diff --git a/src/core/utils/cookieStore.ts b/src/core/utils/cookieStore.ts index 9bd68a3e1..d328e79eb 100644 --- a/src/core/utils/cookieStore.ts +++ b/src/core/utils/cookieStore.ts @@ -75,6 +75,11 @@ class WebStorageCookieStore extends Store { callback: (error: Error | null) => void, ): void { try { + // Never set cookies with `maxAge` of `0`. + if (cookie.maxAge === 0) { + return + } + const store = this.getStore() store.push(cookie) this.updateStore(store) @@ -90,6 +95,21 @@ class WebStorageCookieStore extends Store { newCookie: CookieInstance, callback: (error: Error | null) => void, ): void { + /** + * If updating a cookie with `maxAge` of `0`, remove it from the store. + * Otherwise, two cookie entries will be created. + * @see https://github.com/mswjs/msw/issues/2272 + */ + if (newCookie.maxAge === 0) { + this.removeCookie( + newCookie.domain || '', + newCookie.path || '', + newCookie.key, + callback, + ) + return + } + this.putCookie(newCookie, callback) } diff --git a/test/browser/rest-api/request/request-cookies.test.ts b/test/browser/rest-api/request/request-cookies.test.ts index 639dd7028..f136b39b0 100644 --- a/test/browser/rest-api/request/request-cookies.test.ts +++ b/test/browser/rest-api/request/request-cookies.test.ts @@ -177,7 +177,6 @@ test('inherits mocked "HttpOnly" cookies', async ({ test('respects cookie "Path" when exposing cookies', async ({ loadExample, fetch, - page, }) => { await loadExample(require.resolve('./request-cookies.mocks.ts')) @@ -203,3 +202,30 @@ test('respects cookie "Path" when exposing cookies', async ({ mockedCookie: 'mockedValue', }) }) + +test('deletes a cookie when sending "max-age=0" in a mocked response', async ({ + loadExample, + fetch, +}) => { + await loadExample(require.resolve('./request-cookies.mocks.ts')) + + // First, set the cookie. + await fetch('/set-cookies', { + method: 'POST', + body: `mockedCookie=mockedValue`, + }) + + // Must forward the mocked cookied to the matching request. + await expect(fetch('/cookies').then((res) => res.json())).resolves.toEqual({ + mockedCookie: 'mockedValue', + }) + + // Next, delete the cookie by setting "max-age=0". + await fetch('/set-cookies', { + method: 'POST', + body: `mockedCookie=mockedValue; max-age=0`, + }) + + // Must NOT have any cookies on the matching request. + await expect(fetch('/cookies').then((res) => res.json())).resolves.toEqual({}) +})