cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
47.02k stars 3.18k forks source link

cy.clearAllCookies() does not clear partitioned cookies in Chrome 123 #29265

Open cacieprins opened 7 months ago

cacieprins commented 7 months ago

Current behavior

In Chrome 123, when a domain has set a partitioned cookie, the cy.clearAllCookies command does not delete the partitioned cookie. As well, partitioned cookies do not seem to be cleared between tests in Chrome 123.

Desired behavior

cy.clearAllCookies should delete all cookies, included partitioned cookies. Partitioned cookies should be cleared between tests when test isolation is enabled.

Test code to reproduce

(to be provided)

Cypress Version

13.7.2

Node version

v18.17.1

Operating System

macOS 14.3

Debug Logs

[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation CyCookieFilter:  [
[cy:open:dev:80964]:   {
[cy:open:dev:80964]:     domain: 'a.b.workers.dev',
[cy:open:dev:80964]:     httpOnly: false,
[cy:open:dev:80964]:     hostOnly: true,
[cy:open:dev:80964]:     name: 'notpartitioned',
[cy:open:dev:80964]:     path: '/',
[cy:open:dev:80964]:     sameSite: 'no_restriction',
[cy:open:dev:80964]:     secure: true,
[cy:open:dev:80964]:     value: 'NotPartitioned'
[cy:open:dev:80964]:   },
[cy:open:dev:80964]:   {
[cy:open:dev:80964]:     domain: 'a.b.domain.dev',
[cy:open:dev:80964]:     httpOnly: false,
[cy:open:dev:80964]:     hostOnly: true,
[cy:open:dev:80964]:     name: 'partitioned',
[cy:open:dev:80964]:     path: '/',
[cy:open:dev:80964]:     sameSite: 'no_restriction',
[cy:open:dev:80964]:     secure: true,
[cy:open:dev:80964]:     value: 'Partitioned'
[cy:open:dev:80964]:   }
[cy:open:dev:80964]: ] +4ms
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation clear:cookie: {
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation   cookie: {
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     domain: 'a.b.domain.dev',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     httpOnly: false,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     hostOnly: true,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     name: 'notpartitioned',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     path: '/',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     sameSite: 'no_restriction',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     secure: true,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     value: 'NotPartitioned'
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation   }
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation } +0ms
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation cookie matches filter? { matches: true, cookie: { name: 'notpartitioned', value: 'NotPartitioned', domain: 'a.b.domain.dev', path: '/', size: 28, httpOnly: false, secure: true, session: true, sameSite: 'no_restriction', priority: 'Medium', sameParty: false, sourceScheme: 'Secure', sourcePort: 443, hostOnly: true, expirationDate: undefined }, filter: { domain: 'a.b.domain.dev', httpOnly: false, hostOnly: true, name: 'notpartitioned', path: '/', sameSite: 'no_restriction', secure: true, value: 'NotPartitioned' } } +4ms
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation cookie matches filter? { matches: false, cookie: { name: 'partitioned', value: 'Partitioned', domain: 'a.b.domain.dev', path: '/', size: 22, httpOnly: false, secure: true, session: true, sameSite: 'no_restriction', priority: 'Medium', sameParty: false, sourceScheme: 'Secure', sourcePort: 443, partitionKey: 'https://b.domain.dev', hostOnly: true, expirationDate: undefined }, filter: { domain: 'a.b.domain.dev', httpOnly: false, hostOnly: true, name: 'notpartitioned', path: '/', sameSite: 'no_restriction', secure: true, value: 'NotPartitioned' } } +0ms
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation {
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation   cookieToBeCleared: {
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     name: 'notpartitioned',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     value: 'NotPartitioned',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     domain: 'a.b.domain.dev',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     path: '/',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     size: 28,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     httpOnly: false,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     secure: true,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     session: true,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     sameSite: 'no_restriction',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     priority: 'Medium',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     sameParty: false,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     sourceScheme: 'Secure',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     sourcePort: 443,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     hostOnly: true,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     expirationDate: undefined
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation   }
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation } +0ms
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation cookie should be cleared! +4ms
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation cookies left over: {
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation   cookies: [
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     {
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       name: 'partitioned',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       value: 'Partitioned',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       domain: 'a.b.domain.dev',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       path: '/',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       expires: -1,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       size: 22,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       httpOnly: false,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       secure: true,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       session: true,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       sameSite: 'None',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       priority: 'Medium',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       sameParty: false,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       sourceScheme: 'Secure',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       sourcePort: 443,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       partitionKey: 'https://b.domain.dev'
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     }
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation   ]
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation } +0ms
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation clear:cookie: {
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation   cookie: {
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     domain: 'a.b.domain.dev',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     httpOnly: false,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     hostOnly: true,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     name: 'partitioned',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     path: '/',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     sameSite: 'no_restriction',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     secure: true,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     value: 'Partitioned'
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation   }
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation } +0ms
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation cookie matches filter? { matches: true, cookie: { name: 'partitioned', value: 'Partitioned', domain: 'a.b.domain.dev', path: '/', size: 22, httpOnly: false, secure: true, session: true, sameSite: 'no_restriction', priority: 'Medium', sameParty: false, sourceScheme: 'Secure', sourcePort: 443, partitionKey: 'https://b.domain.dev', hostOnly: true, expirationDate: undefined }, filter: { domain: 'a.b.domain.dev', httpOnly: false, hostOnly: true, name: 'partitioned', path: '/', sameSite: 'no_restriction', secure: true, value: 'Partitioned' } } +1ms
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation {
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation   cookieToBeCleared: {
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     name: 'partitioned',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     value: 'Partitioned',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     domain: 'a.b.domain.dev',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     path: '/',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     size: 22,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     httpOnly: false,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     secure: true,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     session: true,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     sameSite: 'no_restriction',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     priority: 'Medium',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     sameParty: false,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     sourceScheme: 'Secure',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     sourcePort: 443,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     partitionKey: 'https://b.domain.dev',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     hostOnly: true,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     expirationDate: undefined
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation   }
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation } +0ms
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation cookie should be cleared! +0ms
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation cookies left over: {
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation   cookies: [
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     {
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       name: 'partitioned',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       value: 'Partitioned',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       domain: 'a.b.domain.dev',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       path: '/',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       expires: -1,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       size: 22,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       httpOnly: false,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       secure: true,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       session: true,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       sameSite: 'None',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       priority: 'Medium',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       sameParty: false,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       sourceScheme: 'Secure',
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       sourcePort: 443,
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation       partitionKey: 'https://b.domain.dev'
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation     }
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation   ]
[cy:open:dev:80964]:   cypress-verbose:server:browsers:cdp_automation } +0ms

Other

These debug logs are from a modified clear:cookies case in cdp_automation.ts:

        debugVerbose('CyCookieFilter: ', data)

        return Bluebird.mapSeries(data as CyCookieFilter[], async (cookie) => {
          // resolve with the value of the removed cookie
          // also, getting the cookie via CDP first will ensure that we send a cookie `domain` to CDP
          // that matches the cookie domain that is really stored
          debugVerbose('clear:cookie: %O', { cookie })
          const cookieToBeCleared = await this.getCookie(cookie)

          debugVerbose({ cookieToBeCleared })

          if (!cookieToBeCleared) return

          await this.sendDebuggerCommandFn('Network.deleteCookies', _.pick(cookieToBeCleared, 'name', 'domain'))

          debugVerbose('cookie should be cleared!')

          const existingCookies = await this.sendDebuggerCommandFn('Storage.getCookies')

          debugVerbose('cookies left over: %O', existingCookies)

          return cookieToBeCleared
iepoch commented 6 months ago

We are implementing the CHIPs that is recommended by Chrome and even in the current version on retires it does not clear the cookie with partition. Are you seeing this as well @cacieprins ? We are also seeing duplication of the same cookie with and without partition. But that I think is a different issue other then the clearing.

dkleingit commented 5 months ago

I was not able to clear partitioned cookies using any cypress commands.

This is the workaround I am using to clear partitioned HttpOnly cookies after each test.

afterEach(() => {
  const cookiesToRemove = ['cookie1', 'cookie2'];
  const cookieAliases = [];

  cy.url().then((url) => {
    const currentUrl = new URL(url);

    if (currentUrl.host) {
      cookiesToRemove.forEach((cookieName) => {
        const removeCookieUrl = `${currentUrl.protocol}//${currentUrl.host}/cypress/removeCookie/${cookieName}`;
        cy.intercept('GET', removeCookieUrl, {
          statusCode: 200,
          headers: {
            'Set-Cookie': `${cookieName}=; Max-Age=-1; path=/; Partitioned; secure; HttpOnly; SameSite=None`,
          },
        }).as(cookieName)
          .then(() => {
            fetch(removeCookieUrl, { method: 'GET' });
          });
        cookieAliases.push(cookieName);
      });
    }
  });

  cookieAliases.forEach((cookieName) => {
    cy.wait(`@${cookieName}`).its('response.headers');
  });

  cy.clearAllCookies();
});

This uses an intercepted endpoint to remove the cookie via the Set-Cookie header. This endpoint is called using fetch after each test.

achenieux-eyein commented 4 months ago

Hello, we use cypress for our tests and since Chrome 3rd-party cookies blocking in the future, we switched all our cookies to partitioned cookies (since we need to use our website inside an iframe). But now all tests are failing because cypress does not clear partitioned cookies.

Edit: Here is the workaround found:

beforeEach(() => {
    cy.document().then(document => {
        const cookies = document.cookie.split(`;`);
        for (const cookie of cookies) {
            document.cookie = cookie.split(`=`)[0].trim() + `=; Path=/; Secure; Partitioned; expires=` + new Date(0).toUTCString();
        }
    })
})

We need to add Path, Partitioned and Secure to be able to delete a partitioned cookie (As mentioned here).