Msw: add a virtual cookie store

Created on 25 Oct 2020  Â·  10Comments  Â·  Source: mswjs/msw

Is your feature request related to a problem? Please describe.

Let's say there are two mocked routes which look like this:

rest.get('https://example.org/set-cookie', (_, res, ctx) => {
    return res(ctx.cookie('key', 'value'));
}),
rest.get('https://example.org/require-cookie', (req, res, ctx) => {
    if (req.cookies.key === 'value') {
        return res(ctx.status(204));
    }

    return res(ctx.status(400));
}),

When invoking those routes with two chained request ...

fetch('https://example.org/set-cookie').then(() => fetch('https://example.org/require-cookie'))

... the second request will get a 400 response since there is no cookie header send with the request.

Describe the solution you'd like

As far as I understand, this currently doesn't work since the cookie is set by using document.cookie. This means that the cookie will always be associated with the domain of the current document which is not necessarily the domain the response came from. There seems to be no way to change this behavior.

I would therefore like to propose adding a virtual cookie store. It would keep track of the cookies set by calling ctx.cookie() and it would automatically set the appropriate header to each mocked request to the same domain.

Describe alternatives you've considered

As mentioned above I think there is no alternative right now since setting cookies via JavaScript is restricted for good reasons.

Additional context

I'm happy to start a PR for this if we conclude that this is something useful.

feature

Most helpful comment

What about adding an option to the start() function?

We could also warn users in case they turned of the virtual cookie store but attempt to store a cross-origin cookie via ctx.cookie().

All 10 comments

Hey, @chrisguttandin. Thank you for raising this.

How would this scenario behave if you explicitly include cookies in the second request?

fetch('https://example.org/set-cookie').then(() => fetch('https://example.org/require-cookie', {
  credentials: 'include'
}))

Initially I thought if we could specify the request hostname as the cookie's domain, but it appears to be forbidden per spec:

_The domain must match the domain of the JavaScript origin. Setting cookies to foreign domains will be silently ignored._
– MDN

Can you elaborate on the API this cookie storage would take as a part of this thread? We can brainstorm on that, as well as how this implementation would integrate into the existing one, prior to issuing a pull request. Thank you!

Hi Artem,

explicitly including the cookies with the credentials option works. Thanks, I didn't know that. However using it with the mocks would require me to change the actual application code.

I would propose to not change the API at all. The "magic" could be done under the hood. We could add some logic here (https://github.com/mswjs/msw/blob/master/src/context/cookie.ts#L19) which stores the cookies in memory and keeps track of the domains and all the other cookie flags. Likewise we could add some code in here (https://github.com/mswjs/msw/blob/master/src/utils/request/getRequestCookies.ts) to attach the matching cookies to the request object.

For the example above that would mean that the request to https://example.org/set-cookie would add a cookie to the virtual cookie store. It would be registered for the example.org domain. Later on when https://example.org/require-cookie is requested that cookie will be retrieved from the virtual cookie store again since it matches the domain.

Hey, @chrisguttandin. How would you out-out of this cookies inclusion?

What about adding an option to the start() function?

We could also warn users in case they turned of the virtual cookie store but attempt to store a cross-origin cookie via ctx.cookie().

I think both suggestions make sense. Would
you mind shipping a proof of concept? I’m excited to try this out.

If that makes sense to you, we can distribute such functionality in a standalone package. I can prepare the repository under MSW namespace if you're okay with that, or we can transfer your own repo here once it's done.

I just created a PR. Not really to get it merged but more to show what I did to implement a proof of concept. #454

Thank you, @chrisguttandin! I'll take a look at the pull request.

The functionality has been moved into its own virtual-cookie package. Let's iterate on it there and install it as MSW's dependency to provide the request cookies handling support.

Thanks @kettanaito for creating the package. I created a new PR which uses that package. #469

Was this page helpful?
0 / 5 - 0 ratings