mirror of
https://github.com/cypress-io/cypress.git
synced 2026-03-13 12:59:07 -05:00
feat: Add domain option to cookie commands (#24471)
This commit is contained in:
26
cli/types/cypress.d.ts
vendored
26
cli/types/cypress.d.ts
vendored
@@ -775,20 +775,20 @@ declare namespace Cypress {
|
||||
clear(options?: Partial<ClearOptions>): Chainable<Subject>
|
||||
|
||||
/**
|
||||
* Clear a specific browser cookie.
|
||||
* Clear a specific browser cookie for the current superdomain or for the domain specified.
|
||||
* Cypress automatically clears all cookies before each test to prevent state from being shared across tests. You shouldn't need to use this command unless you're using it to clear a specific cookie inside a single test.
|
||||
*
|
||||
* @see https://on.cypress.io/clearcookie
|
||||
*/
|
||||
clearCookie(name: string, options?: Partial<Loggable & Timeoutable>): Chainable<null>
|
||||
clearCookie(name: string, options?: CookieOptions): Chainable<null>
|
||||
|
||||
/**
|
||||
* Clear all browser cookies.
|
||||
* Cypress automatically clears all cookies before each test to prevent state from being shared across tests. You shouldn't need to use this command unless you're using it to clear a specific cookie inside a single test.
|
||||
* Clear all browser cookies for the current superdomain or for the domain specified.
|
||||
* Cypress automatically clears all cookies before each test to prevent state from being shared across tests. You shouldn't need to use this command unless you're using it to clear all cookies or specific cookies inside a single test.
|
||||
*
|
||||
* @see https://on.cypress.io/clearcookies
|
||||
*/
|
||||
clearCookies(options?: Partial<Loggable & Timeoutable>): Chainable<null>
|
||||
clearCookies(options?: CookieOptions): Chainable<null>
|
||||
|
||||
/**
|
||||
* Clear data in local storage.
|
||||
@@ -1248,18 +1248,18 @@ declare namespace Cypress {
|
||||
get<S = any>(alias: string, options?: Partial<Loggable & Timeoutable & Withinable & Shadow>): Chainable<S>
|
||||
|
||||
/**
|
||||
* Get a browser cookie by its name.
|
||||
* Get a browser cookie by its name for the current superdomain or for the domain specified.
|
||||
*
|
||||
* @see https://on.cypress.io/getcookie
|
||||
*/
|
||||
getCookie(name: string, options?: Partial<Loggable & Timeoutable>): Chainable<Cookie | null>
|
||||
getCookie(name: string, options?: CookieOptions): Chainable<Cookie | null>
|
||||
|
||||
/**
|
||||
* Get all of the browser cookies.
|
||||
* Get all of the browser cookies for the current superdomain or for the domain specified.
|
||||
*
|
||||
* @see https://on.cypress.io/getcookies
|
||||
*/
|
||||
getCookies(options?: Partial<Loggable & Timeoutable>): Chainable<Cookie[]>
|
||||
getCookies(options?: CookieOptions): Chainable<Cookie[]>
|
||||
|
||||
/**
|
||||
* Navigate back or forward to the previous or next URL in the browser's history.
|
||||
@@ -2633,6 +2633,14 @@ declare namespace Cypress {
|
||||
cmdKey: boolean
|
||||
}
|
||||
|
||||
interface CookieOptions extends Partial<Loggable & Timeoutable> {
|
||||
/**
|
||||
* Domain to set cookies on or get cookies from
|
||||
* @default superdomain of the current app under test
|
||||
*/
|
||||
domain?: string
|
||||
}
|
||||
|
||||
interface PEMCert {
|
||||
/**
|
||||
* Path to the certificate file, relative to project root.
|
||||
|
||||
@@ -936,6 +936,7 @@ namespace CypressSessionsTests {
|
||||
validate: { foo: true } // $ExpectError
|
||||
})
|
||||
}
|
||||
|
||||
namespace CypressCurrentTest {
|
||||
Cypress.currentTest.title // $ExpectType string
|
||||
Cypress.currentTest.titlePath // $ExpectType string[]
|
||||
@@ -974,3 +975,82 @@ namespace CypressOriginTests {
|
||||
cy.origin('example.com', { args: ['value'] }, (value: boolean[]) => {}) // $ExpectError
|
||||
cy.origin('example.com', {}, (value: undefined) => {}) // $ExpectError
|
||||
}
|
||||
|
||||
namespace CypressGetCookiesTests {
|
||||
cy.getCookies().then((cookies) => {
|
||||
cookies // $ExpectType Cookie[]
|
||||
})
|
||||
cy.getCookies({ log: true })
|
||||
cy.getCookies({ timeout: 10 })
|
||||
cy.getCookies({ domain: 'localhost' })
|
||||
cy.getCookies({ log: true, timeout: 10, domain: 'localhost' })
|
||||
|
||||
cy.getCookies({ log: 'true' }) // $ExpectError
|
||||
cy.getCookies({ timeout: '10' }) // $ExpectError
|
||||
cy.getCookies({ domain: false }) // $ExpectError
|
||||
}
|
||||
|
||||
namespace CypressGetCookieTests {
|
||||
cy.getCookie('name').then((cookie) => {
|
||||
cookie // $ExpectType Cookie | null
|
||||
})
|
||||
cy.getCookie('name', { log: true })
|
||||
cy.getCookie('name', { timeout: 10 })
|
||||
cy.getCookie('name', { domain: 'localhost' })
|
||||
cy.getCookie('name', { log: true, timeout: 10, domain: 'localhost' })
|
||||
|
||||
cy.getCookie('name', { log: 'true' }) // $ExpectError
|
||||
cy.getCookie('name', { timeout: '10' }) // $ExpectError
|
||||
cy.getCookie('name', { domain: false }) // $ExpectError
|
||||
}
|
||||
|
||||
namespace CypressSetCookieTests {
|
||||
cy.setCookie('name', 'value').then((cookie) => {
|
||||
cookie // $ExpectType Cookie
|
||||
})
|
||||
cy.setCookie('name', 'value', { log: true })
|
||||
cy.setCookie('name', 'value', { timeout: 10 })
|
||||
cy.setCookie('name', 'value', {
|
||||
domain: 'localhost',
|
||||
path: '/',
|
||||
secure: true,
|
||||
httpOnly: false,
|
||||
expiry: 12345,
|
||||
sameSite: 'lax',
|
||||
})
|
||||
cy.setCookie('name', 'value', { log: true, timeout: 10, domain: 'localhost' })
|
||||
|
||||
cy.setCookie('name') // $ExpectError
|
||||
cy.setCookie('name', 'value', { log: 'true' }) // $ExpectError
|
||||
cy.setCookie('name', 'value', { timeout: '10' }) // $ExpectError
|
||||
cy.setCookie('name', 'value', { domain: false }) // $ExpectError
|
||||
cy.setCookie('name', 'value', { foo: 'bar' }) // $ExpectError
|
||||
}
|
||||
|
||||
namespace CypressClearCookieTests {
|
||||
cy.clearCookie('name').then((result) => {
|
||||
result // $ExpectType null
|
||||
})
|
||||
cy.clearCookie('name', { log: true })
|
||||
cy.clearCookie('name', { timeout: 10 })
|
||||
cy.clearCookie('name', { domain: 'localhost' })
|
||||
cy.clearCookie('name', { log: true, timeout: 10, domain: 'localhost' })
|
||||
|
||||
cy.clearCookie('name', { log: 'true' }) // $ExpectError
|
||||
cy.clearCookie('name', { timeout: '10' }) // $ExpectError
|
||||
cy.clearCookie('name', { domain: false }) // $ExpectError
|
||||
}
|
||||
|
||||
namespace CypressClearCookiesTests {
|
||||
cy.clearCookies().then((result) => {
|
||||
result // $ExpectType null
|
||||
})
|
||||
cy.clearCookies({ log: true })
|
||||
cy.clearCookies({ timeout: 10 })
|
||||
cy.clearCookies({ domain: 'localhost' })
|
||||
cy.clearCookies({ log: true, timeout: 10, domain: 'localhost' })
|
||||
|
||||
cy.clearCookies({ log: 'true' }) // $ExpectError
|
||||
cy.clearCookies({ timeout: '10' }) // $ExpectError
|
||||
cy.clearCookies({ domain: false }) // $ExpectError
|
||||
}
|
||||
|
||||
@@ -2,21 +2,335 @@ const { assertLogLength } = require('../../support/utils')
|
||||
const { stripIndent } = require('common-tags')
|
||||
const { Promise } = Cypress
|
||||
|
||||
const isWebkit = Cypress.isBrowser('webkit')
|
||||
|
||||
describe('src/cy/commands/cookies - no stub', () => {
|
||||
it('clears all cookies', () => {
|
||||
cy.setCookie('foo', 'bar')
|
||||
cy.getCookies().should('have.length', 1)
|
||||
cy.clearCookies()
|
||||
cy.getCookies().should('have.length', 0)
|
||||
context('#getCookies', () => {
|
||||
// this can be removed along with the experimental flag since once the flag
|
||||
// removed, clearing cookies for all domains will be done by default
|
||||
beforeEach(() => {
|
||||
if (!Cypress.config('experimentalSessionAndOrigin')) {
|
||||
cy.clearCookies({ domain: null })
|
||||
}
|
||||
})
|
||||
|
||||
it('returns cookies from the domain matching the AUT by default', () => {
|
||||
cy.visit('http://www.barbaz.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('foo', 'bar', { domain: 'www.foobar.com' })
|
||||
cy.setCookie('baz', 'qux', { domain: 'foobar.com' })
|
||||
cy.setCookie('foo', 'bar') // defaults to (super)domain: barbaz.com
|
||||
cy.setCookie('qux', 'quuz', { domain: 'www.barbaz.com' })
|
||||
|
||||
cy.getCookies().then((cookies) => {
|
||||
expect(cookies).to.have.length(2)
|
||||
// both the barbaz.com and www.barbaz.com cookies are yielded
|
||||
expect(cookies[0].domain).to.match(/\.?barbaz\.com/)
|
||||
expect(cookies[1].domain).to.match(/\.?www\.barbaz\.com/)
|
||||
})
|
||||
|
||||
if (isWebkit || !Cypress.config('experimentalSessionAndOrigin')) return
|
||||
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.visit('http://www.foobar.com:3500/fixtures/generic.html')
|
||||
|
||||
cy.getCookies().then((cookies) => {
|
||||
expect(cookies[0].domain).to.match(/\.?www\.foobar\.com/)
|
||||
expect(cookies[1].domain).to.match(/\.?foobar\.com/)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('returns cookies for the specified domain', () => {
|
||||
cy.visit('http://www.barbaz.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('foo', 'bar', { domain: 'www.foobar.com' })
|
||||
cy.setCookie('foo', 'bar') // defaults to (super)domain: barbaz.com
|
||||
cy.setCookie('qux', 'quuz', { domain: 'www.barbaz.com' })
|
||||
|
||||
cy.getCookies({ domain: 'www.foobar.com' }).then((cookies) => {
|
||||
expect(cookies[0].domain).to.match(/\.?www\.foobar\.com/)
|
||||
})
|
||||
|
||||
if (isWebkit || !Cypress.config('experimentalSessionAndOrigin')) return
|
||||
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.visit('http://www.foobar.com:3500/fixtures/generic.html')
|
||||
|
||||
cy.getCookies({ domain: 'barbaz.com' }).then((cookies) => {
|
||||
expect(cookies).to.have.length(2)
|
||||
// both the barbaz.com and www.barbaz.com cookies are yielded
|
||||
expect(cookies[0].domain).to.match(/\.?barbaz\.com/)
|
||||
expect(cookies[1].domain).to.match(/\.?www\.barbaz\.com/)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('returns cookies for all domains when domain is null', () => {
|
||||
cy.visit('http://www.barbaz.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('foo', 'bar', { domain: 'www.foobar.com' })
|
||||
cy.setCookie('foo', 'bar')
|
||||
|
||||
cy.getCookies({ domain: null }).should('have.length', 2)
|
||||
|
||||
if (isWebkit || !Cypress.config('experimentalSessionAndOrigin')) return
|
||||
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.visit('http://www.foobar.com:3500/fixtures/generic.html')
|
||||
|
||||
cy.getCookies({ domain: null }).should('have.length', 2)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('clears a single cookie', () => {
|
||||
cy.setCookie('foo', 'bar')
|
||||
cy.setCookie('key', 'val')
|
||||
cy.getCookies().should('have.length', 2)
|
||||
cy.clearCookie('foo')
|
||||
cy.getCookies().should('have.length', 1).then((cookies) => {
|
||||
expect(cookies[0].name).to.eq('key')
|
||||
context('#getCookie', () => {
|
||||
it('returns the cookie from the domain matching the AUT by default', () => {
|
||||
cy.visit('http://www.barbaz.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('foo', 'bar', { domain: 'www.foobar.com' })
|
||||
cy.setCookie('foo', 'bar')
|
||||
|
||||
cy.getCookie('foo').its('domain').should('match', /\.?barbaz\.com/)
|
||||
|
||||
if (isWebkit || !Cypress.config('experimentalSessionAndOrigin')) return
|
||||
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.visit('http://www.foobar.com:3500/fixtures/generic.html')
|
||||
|
||||
cy.getCookie('foo').its('domain').should('match', /\.?www\.foobar\.com/)
|
||||
})
|
||||
})
|
||||
|
||||
it('returns the cookie from the specified domain', () => {
|
||||
cy.visit('http://www.barbaz.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('foo', 'bar', { domain: 'www.foobar.com' })
|
||||
cy.setCookie('foo', 'bar')
|
||||
|
||||
cy.getCookie('foo', { domain: 'www.foobar.com' })
|
||||
.its('domain').should('match', /\.?www\.foobar\.com/)
|
||||
|
||||
if (isWebkit || !Cypress.config('experimentalSessionAndOrigin')) return
|
||||
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.visit('http://www.foobar.com:3500/fixtures/generic.html')
|
||||
|
||||
cy.getCookie('foo', { domain: 'barbaz.com' })
|
||||
.its('domain').should('match', /\.?barbaz\.com/)
|
||||
})
|
||||
})
|
||||
|
||||
it('returns cookie for any domain when domain is null', () => {
|
||||
cy.visit('http://www.barbaz.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('foo', 'bar', { domain: 'www.foobar.com' })
|
||||
|
||||
cy.getCookie('foo', { domain: null })
|
||||
.its('domain').should('match', /\.?www\.foobar\.com/)
|
||||
|
||||
if (isWebkit || !Cypress.config('experimentalSessionAndOrigin')) return
|
||||
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.visit('http://www.foobar.com:3500/fixtures/generic.html')
|
||||
|
||||
cy.clearCookie('foo')
|
||||
cy.setCookie('foo', 'bar', { domain: 'barbaz.com' })
|
||||
|
||||
cy.getCookie('foo', { domain: null })
|
||||
.its('domain').should('match', /\.?barbaz\.com/)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('#setCookie', () => {
|
||||
it('sets the cookie on the domain matching the AUT by default', () => {
|
||||
cy.visit('http://www.barbaz.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('foo', 'bar')
|
||||
|
||||
cy.getCookie('foo').its('domain').should('match', /\.?barbaz\.com/)
|
||||
|
||||
if (isWebkit || !Cypress.config('experimentalSessionAndOrigin')) return
|
||||
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.visit('http://www.foobar.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('foo', 'bar')
|
||||
|
||||
cy.getCookie('foo').its('domain').should('equal', '.foobar.com')
|
||||
})
|
||||
})
|
||||
|
||||
it('set the cookie on the specified domain', () => {
|
||||
cy.visit('http://www.barbaz.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('foo', 'bar', { domain: 'www.foobar.com' })
|
||||
|
||||
cy.getCookie('foo', { domain: 'www.foobar.com' })
|
||||
.its('domain').should('match', /\.?www\.foobar\.com/)
|
||||
|
||||
if (isWebkit || !Cypress.config('experimentalSessionAndOrigin')) return
|
||||
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.visit('http://www.foobar.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('foo', 'bar', { domain: 'barbaz.com' })
|
||||
|
||||
cy.getCookie('foo', { domain: 'barbaz.com' })
|
||||
.its('domain').should('match', /\.?barbaz\.com/)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('#clearCookies', () => {
|
||||
it('clears all cookies', () => {
|
||||
cy.setCookie('foo', 'bar')
|
||||
cy.getCookies().should('have.length', 1)
|
||||
cy.clearCookies()
|
||||
cy.getCookies().should('have.length', 0)
|
||||
})
|
||||
|
||||
it('clears the cookies on the domain matching the AUT by default', () => {
|
||||
cy.visit('http://www.barbaz.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('foo', 'bar')
|
||||
cy.setCookie('baz', 'qux')
|
||||
cy.setCookie('foo', 'bar', { domain: 'www.foobar.com' })
|
||||
|
||||
cy.clearCookies()
|
||||
|
||||
cy.getCookie('foo').should('be.null')
|
||||
cy.getCookie('baz').should('be.null')
|
||||
cy.getCookie('foo', { domain: 'www.foobar.com' }).should('exist')
|
||||
|
||||
if (isWebkit || !Cypress.config('experimentalSessionAndOrigin')) return
|
||||
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.visit('http://www.foobar.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('baz', 'qux')
|
||||
cy.setCookie('foo', 'bar', { domain: 'barbaz.com' })
|
||||
|
||||
cy.clearCookies()
|
||||
|
||||
cy.getCookie('foo').should('be.null')
|
||||
cy.getCookie('baz').should('be.null')
|
||||
cy.getCookie('foo', { domain: 'barbaz.com' }).should('exist')
|
||||
})
|
||||
})
|
||||
|
||||
it('clears the cookies on the specified domain', () => {
|
||||
cy.visit('http://www.barbaz.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('foo', 'bar')
|
||||
cy.setCookie('foo', 'bar', { domain: 'www.foobar.com' })
|
||||
cy.setCookie('baz', 'qux', { domain: 'www.foobar.com' })
|
||||
|
||||
cy.clearCookies({ domain: 'www.foobar.com' })
|
||||
|
||||
cy.getCookie('foo', { domain: 'www.foobar.com' }).should('be.null')
|
||||
cy.getCookie('baz', { domain: 'www.foobar.com' }).should('be.null')
|
||||
cy.getCookie('foo').should('exist')
|
||||
|
||||
if (isWebkit || !Cypress.config('experimentalSessionAndOrigin')) return
|
||||
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.visit('http://www.foobar.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('foo', 'bar')
|
||||
cy.setCookie('baz', 'qux', { domain: 'barbaz.com' })
|
||||
|
||||
cy.clearCookies({ domain: 'barbaz.com' })
|
||||
|
||||
cy.getCookie('foo', { domain: 'barbaz.com' }).should('be.null')
|
||||
cy.getCookie('baz', { domain: 'barbaz.com' }).should('be.null')
|
||||
cy.getCookie('foo').should('exist')
|
||||
})
|
||||
})
|
||||
|
||||
it('clears cookies for all domains when domain is null', () => {
|
||||
cy.visit('http://www.barbaz.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('foo', 'bar')
|
||||
cy.setCookie('foo', 'bar', { domain: 'www.foobar.com' })
|
||||
|
||||
cy.clearCookies({ domain: null })
|
||||
cy.getCookies().should('have.length', 0)
|
||||
|
||||
if (isWebkit || !Cypress.config('experimentalSessionAndOrigin')) return
|
||||
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.visit('http://www.foobar.com:3500/fixtures/generic.html')
|
||||
|
||||
cy.setCookie('foo', 'bar')
|
||||
cy.setCookie('foo', 'bar', { domain: 'barbaz.com' })
|
||||
|
||||
cy.clearCookies({ domain: null })
|
||||
cy.getCookies().should('have.length', 0)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('#clearCookie', () => {
|
||||
it('clears a single cookie', () => {
|
||||
cy.setCookie('foo', 'bar')
|
||||
cy.setCookie('key', 'val')
|
||||
cy.getCookies().should('have.length', 2)
|
||||
cy.clearCookie('foo')
|
||||
cy.getCookies().should('have.length', 1).then((cookies) => {
|
||||
expect(cookies[0].name).to.eq('key')
|
||||
})
|
||||
})
|
||||
|
||||
it('clears the cookie on the domain matching the AUT by default', () => {
|
||||
cy.visit('http://www.barbaz.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('foo', 'bar')
|
||||
cy.setCookie('foo', 'bar', { domain: 'www.foobar.com' })
|
||||
|
||||
cy.clearCookie('foo')
|
||||
|
||||
cy.getCookie('foo').should('be.null')
|
||||
cy.getCookie('foo', { domain: 'www.foobar.com' }).should('exist')
|
||||
|
||||
if (isWebkit || !Cypress.config('experimentalSessionAndOrigin')) return
|
||||
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.visit('http://www.foobar.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('foo', 'bar', { domain: 'barbaz.com' })
|
||||
|
||||
cy.clearCookie('foo')
|
||||
|
||||
cy.getCookie('foo').should('be.null')
|
||||
cy.getCookie('foo', { domain: 'barbaz.com' }).should('exist')
|
||||
})
|
||||
})
|
||||
|
||||
it('clears the cookie on the specified domain', () => {
|
||||
cy.visit('http://www.barbaz.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('foo', 'bar')
|
||||
cy.setCookie('foo', 'bar', { domain: 'www.foobar.com' })
|
||||
|
||||
cy.clearCookie('foo', { domain: 'www.foobar.com' })
|
||||
|
||||
cy.getCookie('foo', { domain: 'www.foobar.com' }).should('be.null')
|
||||
cy.getCookie('foo').should('exist')
|
||||
|
||||
if (isWebkit || !Cypress.config('experimentalSessionAndOrigin')) return
|
||||
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.visit('http://www.foobar.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('foo', 'bar')
|
||||
|
||||
cy.clearCookie('foo', { domain: 'barbaz.com' })
|
||||
|
||||
cy.getCookie('foo', { domain: 'barbaz.com' }).should('be.null')
|
||||
cy.getCookie('foo').should('exist')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('clears cookie for any domain when domain is null', () => {
|
||||
cy.visit('http://www.barbaz.com:3500/fixtures/generic.html')
|
||||
cy.setCookie('foo', 'bar', { domain: 'www.foobar.com' })
|
||||
|
||||
cy.clearCookie('foo', { domain: null })
|
||||
cy.getCookies().should('have.length', 0)
|
||||
|
||||
if (isWebkit || !Cypress.config('experimentalSessionAndOrigin')) return
|
||||
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.visit('http://www.foobar.com:3500/fixtures/generic.html')
|
||||
|
||||
cy.setCookie('foo', 'bar', { domain: 'barbaz.com' })
|
||||
|
||||
cy.clearCookie('foo', { domain: null })
|
||||
cy.getCookies().should('have.length', 0)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -25,6 +339,8 @@ describe('src/cy/commands/cookies', () => {
|
||||
beforeEach(() => {
|
||||
// call through normally on everything
|
||||
cy.stub(Cypress, 'automation').rejects(new Error('Cypress.automation was not stubbed'))
|
||||
|
||||
cy.visit('http://localhost:3500/fixtures/generic.html')
|
||||
})
|
||||
|
||||
context('test:before:run:async', () => {
|
||||
@@ -143,6 +459,20 @@ describe('src/cy/commands/cookies', () => {
|
||||
return null
|
||||
})
|
||||
|
||||
it('when an invalid domain prop is supplied', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('error').message).to.eq('`cy.getCookies()` must be passed a valid domain name. You passed: `true`')
|
||||
expect(lastLog.get('error').docsUrl).to.eq('https://on.cypress.io/getcookies')
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.getCookies({ domain: true })
|
||||
})
|
||||
|
||||
it('logs once on error', function (done) {
|
||||
const error = new Error('some err message')
|
||||
|
||||
@@ -370,6 +700,20 @@ describe('src/cy/commands/cookies', () => {
|
||||
|
||||
cy.getCookie(123)
|
||||
})
|
||||
|
||||
it('when an invalid domain prop is supplied', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('error').message).to.eq('`cy.getCookie()` must be passed a valid domain name. You passed: `true`')
|
||||
expect(lastLog.get('error').docsUrl).to.eq('https://on.cypress.io/getcookie')
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.getCookie('foo', { domain: true })
|
||||
})
|
||||
})
|
||||
|
||||
describe('.log', () => {
|
||||
@@ -454,8 +798,7 @@ describe('src/cy/commands/cookies', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// TODO: fix flaky test https://github.com/cypress-io/cypress/issues/23444
|
||||
context.skip('#setCookie', () => {
|
||||
context('#setCookie', () => {
|
||||
beforeEach(() => {
|
||||
cy.stub(Cypress.utils, 'addTwentyYears').returns(12345)
|
||||
})
|
||||
@@ -529,8 +872,7 @@ describe('src/cy/commands/cookies', () => {
|
||||
})
|
||||
|
||||
describe('timeout', () => {
|
||||
// TODO: fix flaky test https://github.com/cypress-io/cypress/issues/23444
|
||||
it.skip('sets timeout to Cypress.config(responseTimeout)', {
|
||||
it('sets timeout to Cypress.config(responseTimeout)', {
|
||||
responseTimeout: 2500,
|
||||
}, () => {
|
||||
Cypress.automation.resolves(null)
|
||||
@@ -542,8 +884,7 @@ describe('src/cy/commands/cookies', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// TODO: fix flaky test https://github.com/cypress-io/cypress/issues/23444
|
||||
it.skip('can override timeout', () => {
|
||||
it('can override timeout', () => {
|
||||
Cypress.automation.resolves(null)
|
||||
|
||||
const timeout = cy.spy(Promise.prototype, 'timeout')
|
||||
@@ -553,8 +894,7 @@ describe('src/cy/commands/cookies', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// TODO: fix flaky test https://github.com/cypress-io/cypress/issues/23444
|
||||
it.skip('clears the current timeout and restores after success', () => {
|
||||
it('clears the current timeout and restores after success', () => {
|
||||
Cypress.automation.resolves(null)
|
||||
|
||||
cy.timeout(100)
|
||||
@@ -586,8 +926,7 @@ describe('src/cy/commands/cookies', () => {
|
||||
return null
|
||||
})
|
||||
|
||||
// TODO: fix flaky test https://github.com/cypress-io/cypress/issues/23444
|
||||
it.skip('logs once on error', function (done) {
|
||||
it('logs once on error', function (done) {
|
||||
const error = new Error('some err message')
|
||||
|
||||
error.name = 'foo'
|
||||
@@ -607,8 +946,7 @@ describe('src/cy/commands/cookies', () => {
|
||||
cy.setCookie('foo', 'bar')
|
||||
})
|
||||
|
||||
// TODO: fix flaky test https://github.com/cypress-io/cypress/issues/23444
|
||||
it.skip('throws after timing out', function (done) {
|
||||
it('throws after timing out', function (done) {
|
||||
Cypress.automation.resolves(Promise.delay(1000))
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
@@ -697,6 +1035,20 @@ describe('src/cy/commands/cookies', () => {
|
||||
cy.setCookie('foo', 'bar', { sameSite: 'None' })
|
||||
})
|
||||
|
||||
it('when an invalid domain prop is supplied', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('error').message).to.eq('`cy.setCookie()` must be passed a valid domain name. You passed: `true`')
|
||||
expect(lastLog.get('error').docsUrl).to.eq('https://on.cypress.io/setcookie')
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.setCookie('foo', 'bar', { domain: true })
|
||||
})
|
||||
|
||||
context('when setting an invalid cookie', () => {
|
||||
it('throws an error if the backend responds with an error', (done) => {
|
||||
const err = new Error('backend could not set cookie')
|
||||
@@ -891,6 +1243,20 @@ describe('src/cy/commands/cookies', () => {
|
||||
|
||||
cy.clearCookie(123)
|
||||
})
|
||||
|
||||
it('when an invalid domain prop is supplied', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('error').message).to.eq('`cy.clearCookie()` must be passed a valid domain name. You passed: `true`')
|
||||
expect(lastLog.get('error').docsUrl).to.eq('https://on.cypress.io/clearcookie')
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.clearCookie('foo', { domain: true })
|
||||
})
|
||||
})
|
||||
|
||||
describe('.log', () => {
|
||||
@@ -1104,6 +1470,20 @@ describe('src/cy/commands/cookies', () => {
|
||||
return null
|
||||
})
|
||||
|
||||
it('when an invalid domain prop is supplied', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('error').message).to.eq('`cy.clearCookies()` must be passed a valid domain name. You passed: `true`')
|
||||
expect(lastLog.get('error').docsUrl).to.eq('https://on.cypress.io/clearcookies')
|
||||
expect(lastLog.get('error')).to.eq(err)
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
cy.clearCookies({ domain: true })
|
||||
})
|
||||
|
||||
it('logs once on \'get:cookies\' error', function (done) {
|
||||
const error = new Error('some err message')
|
||||
|
||||
|
||||
@@ -691,6 +691,18 @@ describe('cy.origin - cookie login', { browser: '!webkit' }, () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('does not error when setting cookie with different domain', () => {
|
||||
cy.get('[data-cy="cross-origin-secondary-link"]').click()
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.document().then((doc) => {
|
||||
doc.cookie = 'key=value; domain=www.example.com'
|
||||
})
|
||||
|
||||
// the cookie should not be set if the domain does not match
|
||||
cy.document().its('cookie').should('equal', '')
|
||||
})
|
||||
})
|
||||
|
||||
it('works when setting cookie with extra, benign parts', () => {
|
||||
cy.get('[data-cy="cross-origin-secondary-link"]').click()
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
|
||||
@@ -79,28 +79,16 @@ function cookieValidatesSecurePrefix (options) {
|
||||
return options.secure === false
|
||||
}
|
||||
|
||||
interface InternalGetCookieOptions extends Partial<Cypress.Loggable & Cypress.Timeoutable> {
|
||||
_log?: Log
|
||||
cookie?: Cypress.Cookie
|
||||
}
|
||||
|
||||
interface InternalGetCookiesOptions extends Partial<Cypress.Loggable & Cypress.Timeoutable> {
|
||||
_log?: Log
|
||||
cookies?: Cypress.Cookie[]
|
||||
}
|
||||
|
||||
interface InternalSetCookieOptions extends Partial<Cypress.SetCookieOptions> {
|
||||
_log?: Log
|
||||
name: string
|
||||
cookie?: Cypress.Cookie
|
||||
}
|
||||
|
||||
type InternalClearCookieOptions = InternalGetCookieOptions
|
||||
|
||||
interface InternalClearCookiesOptions extends Partial<Cypress.Loggable & Cypress.Timeoutable> {
|
||||
_log?: Log
|
||||
cookies?: Cypress.Cookie[]
|
||||
domain?: any
|
||||
function validateDomainOption (domain: any, commandName: string, log: Log | undefined) {
|
||||
if (domain !== undefined && domain !== null && !_.isString(domain)) {
|
||||
$errUtils.throwErrByPath('cookies.invalid_domain', {
|
||||
onFail: log,
|
||||
args: {
|
||||
cmd: commandName,
|
||||
domain,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default function (Commands, Cypress, cy, state, config) {
|
||||
@@ -192,8 +180,8 @@ export default function (Commands, Cypress, cy, state, config) {
|
||||
}
|
||||
|
||||
return Commands.addAll({
|
||||
getCookie (name, userOptions: Partial<Cypress.Loggable & Cypress.Timeoutable> = {}) {
|
||||
const options: InternalGetCookieOptions = _.defaults({}, userOptions, {
|
||||
getCookie (name, userOptions: Cypress.CookieOptions = {}) {
|
||||
const options: Cypress.CookieOptions = _.defaults({}, userOptions, {
|
||||
log: true,
|
||||
})
|
||||
|
||||
@@ -201,18 +189,18 @@ export default function (Commands, Cypress, cy, state, config) {
|
||||
|
||||
options.timeout = options.timeout || config('defaultCommandTimeout')
|
||||
|
||||
let cookie: Cypress.Cookie
|
||||
let log: Log | undefined
|
||||
|
||||
if (options.log) {
|
||||
options._log = Cypress.log({
|
||||
log = Cypress.log({
|
||||
message: name,
|
||||
timeout: responseTimeout,
|
||||
consoleProps () {
|
||||
let c
|
||||
const obj = {}
|
||||
|
||||
c = options.cookie
|
||||
|
||||
if (c) {
|
||||
obj['Yielded'] = c
|
||||
if (cookie) {
|
||||
obj['Yielded'] = cookie
|
||||
} else {
|
||||
obj['Yielded'] = 'null'
|
||||
obj['Note'] = `No cookie with the name: '${name}' was found.`
|
||||
@@ -223,26 +211,24 @@ export default function (Commands, Cypress, cy, state, config) {
|
||||
})
|
||||
}
|
||||
|
||||
const onFail = options._log
|
||||
|
||||
if (!_.isString(name)) {
|
||||
$errUtils.throwErrByPath('getCookie.invalid_argument', { onFail })
|
||||
$errUtils.throwErrByPath('getCookie.invalid_argument', { onFail: log })
|
||||
}
|
||||
|
||||
return cy.retryIfCommandAUTOriginMismatch(() => {
|
||||
return automateCookies('get:cookie', { name }, options._log, responseTimeout)
|
||||
.then(pickCookieProps)
|
||||
.then((resp) => {
|
||||
options.cookie = resp
|
||||
validateDomainOption(options.domain, 'getCookie', log)
|
||||
|
||||
return resp
|
||||
return cy.retryIfCommandAUTOriginMismatch(() => {
|
||||
return automateCookies('get:cookie', { name, domain: options.domain }, log, responseTimeout)
|
||||
.then(pickCookieProps)
|
||||
.tap((result) => {
|
||||
cookie = result
|
||||
})
|
||||
.catch(handleBackendError('getCookie', 'reading the requested cookie from', onFail))
|
||||
.catch(handleBackendError('getCookie', 'reading the requested cookie from', log))
|
||||
}, options.timeout)
|
||||
},
|
||||
|
||||
getCookies (userOptions: Partial<Cypress.Loggable & Cypress.Timeoutable> = {}) {
|
||||
const options: InternalGetCookiesOptions = _.defaults({}, userOptions, {
|
||||
getCookies (userOptions: Cypress.CookieOptions = {}) {
|
||||
const options: Cypress.CookieOptions = _.defaults({}, userOptions, {
|
||||
log: true,
|
||||
})
|
||||
|
||||
@@ -250,19 +236,19 @@ export default function (Commands, Cypress, cy, state, config) {
|
||||
|
||||
options.timeout = options.timeout || config('defaultCommandTimeout')
|
||||
|
||||
let cookies: Cypress.Cookie[] = []
|
||||
let log: Log | undefined
|
||||
|
||||
if (options.log) {
|
||||
options._log = Cypress.log({
|
||||
log = Cypress.log({
|
||||
message: '',
|
||||
timeout: responseTimeout,
|
||||
consoleProps () {
|
||||
let c
|
||||
const obj = {}
|
||||
|
||||
c = options.cookies
|
||||
|
||||
if (c) {
|
||||
obj['Yielded'] = c
|
||||
obj['Num Cookies'] = c.length
|
||||
if (cookies.length) {
|
||||
obj['Yielded'] = cookies
|
||||
obj['Num Cookies'] = cookies.length
|
||||
}
|
||||
|
||||
return obj
|
||||
@@ -270,22 +256,20 @@ export default function (Commands, Cypress, cy, state, config) {
|
||||
})
|
||||
}
|
||||
|
||||
return cy.retryIfCommandAUTOriginMismatch(() => {
|
||||
return automateCookies('get:cookies', _.pick(options, 'domain'), options._log, responseTimeout)
|
||||
.then(pickCookieProps)
|
||||
.then((resp) => {
|
||||
options.cookies = resp
|
||||
validateDomainOption(options.domain, 'getCookies', log)
|
||||
|
||||
return resp
|
||||
return cy.retryIfCommandAUTOriginMismatch(() => {
|
||||
return automateCookies('get:cookies', _.pick(options, 'domain'), log, responseTimeout)
|
||||
.then(pickCookieProps)
|
||||
.tap((result: Cypress.Cookie[]) => {
|
||||
cookies = result
|
||||
})
|
||||
.catch(handleBackendError('getCookies', 'reading cookies from', options._log))
|
||||
.catch(handleBackendError('getCookies', 'reading cookies from', log))
|
||||
}, options.timeout)
|
||||
},
|
||||
|
||||
setCookie (name, value, userOptions: Partial<Cypress.SetCookieOptions> = {}) {
|
||||
const options: InternalSetCookieOptions = _.defaults({}, userOptions, {
|
||||
name,
|
||||
value,
|
||||
const options: Partial<Cypress.SetCookieOptions> = _.defaults({}, userOptions, {
|
||||
path: '/',
|
||||
secure: false,
|
||||
httpOnly: false,
|
||||
@@ -297,20 +281,19 @@ export default function (Commands, Cypress, cy, state, config) {
|
||||
|
||||
options.timeout = options.timeout || config('defaultCommandTimeout')
|
||||
|
||||
const cookie = pickCookieProps(options)
|
||||
const cookie = _.extend(pickCookieProps(options), { name, value })
|
||||
let resultingCookie: Cypress.Cookie
|
||||
let log: Log | undefined
|
||||
|
||||
if (options.log) {
|
||||
options._log = Cypress.log({
|
||||
log = Cypress.log({
|
||||
message: [name, value],
|
||||
timeout: responseTimeout,
|
||||
consoleProps () {
|
||||
let c
|
||||
const obj = {}
|
||||
|
||||
c = options.cookie
|
||||
|
||||
if (c) {
|
||||
obj['Yielded'] = c
|
||||
if (resultingCookie) {
|
||||
obj['Yielded'] = resultingCookie
|
||||
}
|
||||
|
||||
return obj
|
||||
@@ -318,13 +301,11 @@ export default function (Commands, Cypress, cy, state, config) {
|
||||
})
|
||||
}
|
||||
|
||||
const onFail = options._log
|
||||
|
||||
cookie.sameSite = normalizeSameSite(cookie.sameSite)
|
||||
|
||||
if (!_.isUndefined(cookie.sameSite) && !VALID_SAMESITE_VALUES.includes(cookie.sameSite)) {
|
||||
$errUtils.throwErrByPath('setCookie.invalid_samesite', {
|
||||
onFail,
|
||||
onFail: log,
|
||||
args: {
|
||||
value: options.sameSite, // for clarity, throw the error with the user's unnormalized option
|
||||
validValues: VALID_SAMESITE_VALUES,
|
||||
@@ -336,7 +317,7 @@ export default function (Commands, Cypress, cy, state, config) {
|
||||
// @see https://web.dev/samesite-cookies-explained/#changes-to-the-default-behavior-without-samesite
|
||||
if (cookie.sameSite === 'no_restriction' && cookie.secure !== true) {
|
||||
$errUtils.throwErrByPath('setCookie.secure_not_set_with_samesite_none', {
|
||||
onFail,
|
||||
onFail: log,
|
||||
args: {
|
||||
value: options.sameSite, // for clarity, throw the error with the user's unnormalized option
|
||||
},
|
||||
@@ -344,32 +325,32 @@ export default function (Commands, Cypress, cy, state, config) {
|
||||
}
|
||||
|
||||
if (!_.isString(name) || !_.isString(value)) {
|
||||
$errUtils.throwErrByPath('setCookie.invalid_arguments', { onFail })
|
||||
$errUtils.throwErrByPath('setCookie.invalid_arguments', { onFail: log })
|
||||
}
|
||||
|
||||
if (options.name.startsWith('__Secure-') && cookieValidatesSecurePrefix(options)) {
|
||||
$errUtils.throwErrByPath('setCookie.secure_prefix', { onFail })
|
||||
if (name.startsWith('__Secure-') && cookieValidatesSecurePrefix(options)) {
|
||||
$errUtils.throwErrByPath('setCookie.secure_prefix', { onFail: log })
|
||||
}
|
||||
|
||||
if (options.name.startsWith('__Host-') && cookieValidatesHostPrefix(options)) {
|
||||
$errUtils.throwErrByPath('setCookie.host_prefix', { onFail })
|
||||
if (name.startsWith('__Host-') && cookieValidatesHostPrefix(options)) {
|
||||
$errUtils.throwErrByPath('setCookie.host_prefix', { onFail: log })
|
||||
}
|
||||
|
||||
validateDomainOption(options.domain, 'setCookie', log)
|
||||
|
||||
Cypress.emit('set:cookie', cookie)
|
||||
|
||||
return cy.retryIfCommandAUTOriginMismatch(() => {
|
||||
return automateCookies('set:cookie', cookie, options._log, responseTimeout)
|
||||
return automateCookies('set:cookie', cookie, log, responseTimeout)
|
||||
.then(pickCookieProps)
|
||||
.then((resp) => {
|
||||
options.cookie = resp
|
||||
|
||||
return resp
|
||||
}).catch(handleBackendError('setCookie', 'setting the requested cookie in', onFail))
|
||||
.tap((result) => {
|
||||
resultingCookie = result
|
||||
}).catch(handleBackendError('setCookie', 'setting the requested cookie in', log))
|
||||
}, options.timeout)
|
||||
},
|
||||
|
||||
clearCookie (name, userOptions: Partial<Cypress.Loggable & Cypress.Timeoutable> = {}) {
|
||||
const options: InternalClearCookieOptions = _.defaults({}, userOptions, {
|
||||
clearCookie (name, userOptions: Cypress.CookieOptions = {}) {
|
||||
const options: Cypress.CookieOptions = _.defaults({}, userOptions, {
|
||||
log: true,
|
||||
})
|
||||
|
||||
@@ -377,20 +358,20 @@ export default function (Commands, Cypress, cy, state, config) {
|
||||
|
||||
options.timeout = options.timeout || config('defaultCommandTimeout')
|
||||
|
||||
let cookie: Cypress.Cookie
|
||||
let log: Log | undefined
|
||||
|
||||
if (options.log) {
|
||||
options._log = Cypress.log({
|
||||
log = Cypress.log({
|
||||
message: name,
|
||||
timeout: responseTimeout,
|
||||
consoleProps () {
|
||||
let c
|
||||
const obj = {}
|
||||
|
||||
obj['Yielded'] = 'null'
|
||||
|
||||
c = options.cookie
|
||||
|
||||
if (c) {
|
||||
obj['Cleared Cookie'] = c
|
||||
if (cookie) {
|
||||
obj['Cleared Cookie'] = cookie
|
||||
} else {
|
||||
obj['Note'] = `No cookie with the name: '${name}' was found or removed.`
|
||||
}
|
||||
@@ -400,30 +381,30 @@ export default function (Commands, Cypress, cy, state, config) {
|
||||
})
|
||||
}
|
||||
|
||||
const onFail = options._log
|
||||
|
||||
if (!_.isString(name)) {
|
||||
$errUtils.throwErrByPath('clearCookie.invalid_argument', { onFail })
|
||||
$errUtils.throwErrByPath('clearCookie.invalid_argument', { onFail: log })
|
||||
}
|
||||
|
||||
validateDomainOption(options.domain, 'clearCookie', log)
|
||||
|
||||
Cypress.emit('clear:cookie', name)
|
||||
|
||||
// TODO: prevent clearing a cypress namespace
|
||||
return cy.retryIfCommandAUTOriginMismatch(() => {
|
||||
return automateCookies('clear:cookie', { name }, options._log, responseTimeout)
|
||||
return automateCookies('clear:cookie', { name, domain: options.domain }, log, responseTimeout)
|
||||
.then(pickCookieProps)
|
||||
.then((resp) => {
|
||||
options.cookie = resp
|
||||
.then((result) => {
|
||||
cookie = result
|
||||
|
||||
// null out the current subject
|
||||
return null
|
||||
})
|
||||
.catch(handleBackendError('clearCookie', 'clearing the requested cookie in', onFail))
|
||||
.catch(handleBackendError('clearCookie', 'clearing the requested cookie in', log))
|
||||
}, options.timeout)
|
||||
},
|
||||
|
||||
clearCookies (userOptions: Partial<Cypress.Loggable & Cypress.Timeoutable> = {}) {
|
||||
const options: InternalClearCookiesOptions = _.defaults({}, userOptions, {
|
||||
clearCookies (userOptions: Cypress.CookieOptions = {}) {
|
||||
const options: Cypress.CookieOptions = _.defaults({}, userOptions, {
|
||||
log: true,
|
||||
})
|
||||
|
||||
@@ -431,19 +412,21 @@ export default function (Commands, Cypress, cy, state, config) {
|
||||
|
||||
options.timeout = options.timeout || config('defaultCommandTimeout')
|
||||
|
||||
let cookies: Cypress.Cookie[] = []
|
||||
let log: Log | undefined
|
||||
|
||||
if (options.log) {
|
||||
options._log = Cypress.log({
|
||||
log = Cypress.log({
|
||||
message: '',
|
||||
timeout: responseTimeout,
|
||||
consoleProps () {
|
||||
const c = options.cookies
|
||||
const obj = {}
|
||||
|
||||
obj['Yielded'] = 'null'
|
||||
|
||||
if (c && c.length) {
|
||||
obj['Cleared Cookies'] = c
|
||||
obj['Num Cookies'] = c.length
|
||||
if (cookies.length) {
|
||||
obj['Cleared Cookies'] = cookies
|
||||
obj['Num Cookies'] = cookies.length
|
||||
} else {
|
||||
obj['Note'] = 'No cookies were found or removed.'
|
||||
}
|
||||
@@ -453,12 +436,14 @@ export default function (Commands, Cypress, cy, state, config) {
|
||||
})
|
||||
}
|
||||
|
||||
validateDomainOption(options.domain, 'clearCookies', log)
|
||||
|
||||
Cypress.emit('clear:cookies')
|
||||
|
||||
return cy.retryIfCommandAUTOriginMismatch(() => {
|
||||
return getAndClear(options._log, responseTimeout, { domain: options.domain })
|
||||
.then((resp) => {
|
||||
options.cookies = resp
|
||||
return getAndClear(log, responseTimeout, { domain: options.domain })
|
||||
.then((result) => {
|
||||
cookies = result
|
||||
|
||||
// null out the current subject
|
||||
return null
|
||||
@@ -467,7 +452,7 @@ export default function (Commands, Cypress, cy, state, config) {
|
||||
err.message = err.message.replace('getCookies', 'clearCookies')
|
||||
throw err
|
||||
})
|
||||
.catch(handleBackendError('clearCookies', 'clearing cookies in', options._log))
|
||||
.catch(handleBackendError('clearCookies', 'clearing cookies in', log))
|
||||
}, options.timeout)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -325,6 +325,12 @@ export default {
|
||||
docsUrl: 'https://on.cypress.io/session',
|
||||
}
|
||||
},
|
||||
invalid_domain (obj) {
|
||||
return {
|
||||
message: `${cmd('{{cmd}}')} must be passed a valid domain name. You passed: \`{{domain}}\``,
|
||||
docsUrl: `https://on.cypress.io/${_.toLower(obj.cmd)}`,
|
||||
}
|
||||
},
|
||||
invalid_name (obj) {
|
||||
return {
|
||||
message: `${cmd('{{cmd}}')} must be passed an RFC-6265-compliant cookie name. You passed:\n\n\`{{name}}\``,
|
||||
|
||||
@@ -63,6 +63,17 @@ export const patchDocumentCookie = (requestCookies: AutomationCookie[]) => {
|
||||
})
|
||||
}
|
||||
|
||||
const setCookie = (cookie: ToughCookie | string) => {
|
||||
try {
|
||||
return cookieJar.setCookie(cookie, url, undefined)
|
||||
} catch (err) {
|
||||
// it's possible setting the cookie fails because the domain does not
|
||||
// match. this is expected and okay to do nothing, since it wouldn't be
|
||||
// set in the browser anyway
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// requestCookies are ones included with the page request that's now being
|
||||
// injected into. they're captured by the proxy and included statically in
|
||||
// the injection so they can be added here and available before page load
|
||||
@@ -84,19 +95,21 @@ export const patchDocumentCookie = (requestCookies: AutomationCookie[]) => {
|
||||
// value, but tough-cookie doesn't recognize it using an instanceof
|
||||
// check and throws an error. because we can't, we have to massage
|
||||
// some of the properties below to be correct
|
||||
const cookie = cookieJar.setCookie(stringValue, url, undefined)!
|
||||
const cookie = setCookie(stringValue)
|
||||
|
||||
cookie.sameSite = parsedCookie.sameSite
|
||||
if (cookie) {
|
||||
cookie.sameSite = parsedCookie.sameSite
|
||||
|
||||
if (!parsedCookie.path) {
|
||||
cookie.path = '/'
|
||||
if (!parsedCookie.path) {
|
||||
cookie.path = '/'
|
||||
}
|
||||
|
||||
// send the cookie to the server so it can be set in the browser via
|
||||
// automation and in our server-side cookie jar so it's available
|
||||
// to subsequent injections
|
||||
sendCookieToServer(toughCookieToAutomationCookie(cookie, domain))
|
||||
}
|
||||
|
||||
// send the cookie to the server so it can be set in the browser via
|
||||
// automation and in our server-side cookie jar so it's available
|
||||
// to subsequent injections
|
||||
sendCookieToServer(toughCookieToAutomationCookie(cookie, domain))
|
||||
|
||||
return getDocumentCookieValue()
|
||||
},
|
||||
})
|
||||
@@ -111,7 +124,7 @@ export const patchDocumentCookie = (requestCookies: AutomationCookie[]) => {
|
||||
// the following listeners are called from Cypress cookie commands, so that
|
||||
// the document.cookie value is updated optimistically
|
||||
Cypress.on('set:cookie', (cookie: AutomationCookie) => {
|
||||
cookieJar.setCookie(automationCookieToToughCookie(cookie, domain), url, undefined)
|
||||
setCookie(automationCookieToToughCookie(cookie, domain))
|
||||
})
|
||||
|
||||
Cypress.on('clear:cookie', (name: string) => {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import _ from 'lodash'
|
||||
import Bluebird from 'bluebird'
|
||||
import type playwright from 'playwright-webkit'
|
||||
import type { Protocol } from 'devtools-protocol'
|
||||
import type ProtocolMapping from 'devtools-protocol/types/protocol-mapping'
|
||||
import { cors, uri } from '@packages/network'
|
||||
@@ -25,7 +26,7 @@ export type CyCookie = Pick<chrome.cookies.Cookie, 'name' | 'value' | 'expiratio
|
||||
|
||||
// Cypress uses the webextension-style filtering
|
||||
// https://developer.chrome.com/extensions/cookies#method-getAll
|
||||
type CyCookieFilter = chrome.cookies.GetAllDetails
|
||||
export type CyCookieFilter = chrome.cookies.GetAllDetails
|
||||
|
||||
export function screencastOpts (everyNthFrame = Number(process.env.CYPRESS_EVERY_NTH_FRAME || 5)): Protocol.Page.StartScreencastRequest {
|
||||
return {
|
||||
@@ -61,7 +62,7 @@ export const _domainIsWithinSuperdomain = (domain: string, suffix: string) => {
|
||||
return _.isEqual(suffixParts, domainParts.slice(domainParts.length - suffixParts.length))
|
||||
}
|
||||
|
||||
export const _cookieMatches = (cookie: CyCookie, filter: CyCookieFilter) => {
|
||||
export const cookieMatches = (cookie: CyCookie | playwright.Cookie, filter: CyCookieFilter) => {
|
||||
if (filter.domain && !(cookie.domain && _domainIsWithinSuperdomain(cookie.domain, filter.domain))) {
|
||||
return false
|
||||
}
|
||||
@@ -255,7 +256,7 @@ export class CdpAutomation {
|
||||
.then((result: Protocol.Network.GetAllCookiesResponse) => {
|
||||
return normalizeGetCookies(result.cookies)
|
||||
.filter((cookie: CyCookie) => {
|
||||
const matches = _cookieMatches(cookie, filter)
|
||||
const matches = cookieMatches(cookie, filter)
|
||||
|
||||
debugVerbose('cookie matches filter? %o', { matches, cookie, filter })
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import _ from 'lodash'
|
||||
import Debug from 'debug'
|
||||
import type playwright from 'playwright-webkit'
|
||||
import type { Automation } from '../automation'
|
||||
import { normalizeResourceType } from './cdp_automation'
|
||||
import { cookieMatches, normalizeResourceType, CyCookieFilter } from './cdp_automation'
|
||||
import os from 'os'
|
||||
import type { RunModeVideoApi } from '@packages/types'
|
||||
import path from 'path'
|
||||
@@ -15,11 +14,6 @@ export type CyCookie = Pick<chrome.cookies.Cookie, 'name' | 'value' | 'expiratio
|
||||
sameSite?: 'no_restriction' | 'lax' | 'strict'
|
||||
}
|
||||
|
||||
type CookieFilter = {
|
||||
name: string
|
||||
domain: string
|
||||
}
|
||||
|
||||
const extensionMap = {
|
||||
'no_restriction': 'None',
|
||||
'lax': 'Lax',
|
||||
@@ -65,29 +59,6 @@ const normalizeSetCookieProps = (cookie: CyCookie): playwright.Cookie => {
|
||||
}
|
||||
}
|
||||
|
||||
const _domainIsWithinSuperdomain = (domain: string, suffix: string) => {
|
||||
const suffixParts = suffix.split('.').filter(_.identity)
|
||||
const domainParts = domain.split('.').filter(_.identity)
|
||||
|
||||
return _.isEqual(suffixParts, domainParts.slice(domainParts.length - suffixParts.length))
|
||||
}
|
||||
|
||||
const _cookieMatches = (cookie: any, filter: Record<string, any>) => {
|
||||
if (filter.domain && !(cookie.domain && _domainIsWithinSuperdomain(cookie.domain, filter.domain))) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (filter.path && filter.path !== cookie.path) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (filter.name && filter.name !== cookie.name) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
let requestIdCounter = 1
|
||||
const requestIdMap = new WeakMap<playwright.Request, string>()
|
||||
let downloadIdCounter = 1
|
||||
@@ -279,19 +250,23 @@ export class WebKitAutomation {
|
||||
})
|
||||
}
|
||||
|
||||
private async getCookies (): Promise<CyCookie[]> {
|
||||
private async getCookies (filter: CyCookieFilter): Promise<CyCookie[]> {
|
||||
const cookies = await this.context.cookies()
|
||||
|
||||
return cookies.map(normalizeGetCookieProps)
|
||||
return cookies
|
||||
.filter((cookie) => {
|
||||
return cookieMatches(cookie, filter)
|
||||
})
|
||||
.map(normalizeGetCookieProps)
|
||||
}
|
||||
|
||||
private async getCookie (filter: CookieFilter) {
|
||||
private async getCookie (filter: CyCookieFilter) {
|
||||
const cookies = await this.context.cookies()
|
||||
|
||||
if (!cookies.length) return null
|
||||
|
||||
const cookie = cookies.find((cookie) => {
|
||||
return _cookieMatches(cookie, {
|
||||
return cookieMatches(cookie, {
|
||||
domain: filter.domain,
|
||||
name: filter.name,
|
||||
})
|
||||
@@ -306,13 +281,16 @@ export class WebKitAutomation {
|
||||
* @param filter the cookie to be cleared
|
||||
* @returns the cleared cookie
|
||||
*/
|
||||
private async clearCookie (filter: CookieFilter): Promise<CookieFilter> {
|
||||
private async clearCookie (filter: CyCookieFilter): Promise<CyCookieFilter> {
|
||||
// webkit doesn't have a way to only clear certain cookies, so we have
|
||||
// to clear all cookies and put back the ones we don't want cleared
|
||||
const allCookies = await this.context.cookies()
|
||||
const persistCookies = allCookies.filter((cookie) => {
|
||||
return !_cookieMatches(cookie, filter)
|
||||
return !cookieMatches(cookie, filter)
|
||||
})
|
||||
|
||||
await this.context.clearCookies()
|
||||
|
||||
if (persistCookies.length) await this.context.addCookies(persistCookies)
|
||||
|
||||
return filter
|
||||
@@ -322,12 +300,24 @@ export class WebKitAutomation {
|
||||
* Clear all cookies
|
||||
* @returns cookies cleared
|
||||
*/
|
||||
private async clearCookies (): Promise<CyCookie[]> {
|
||||
const allCookies = await this.getCookies()
|
||||
private async clearCookies (cookiesToClear: CyCookie[]): Promise<CyCookie[]> {
|
||||
// webkit doesn't have a way to only clear certain cookies, so we have
|
||||
// to clear all cookies and put back the ones we don't want cleared
|
||||
const allCookies = await this.context.cookies()
|
||||
const persistCookies = allCookies.filter((cookie) => {
|
||||
return !cookiesToClear.find((cookieToClear) => {
|
||||
return cookieMatches(cookie, cookieToClear)
|
||||
})
|
||||
})
|
||||
|
||||
debug('clear cookies: %o', cookiesToClear)
|
||||
debug('put back cookies: %o', persistCookies)
|
||||
|
||||
await this.context.clearCookies()
|
||||
|
||||
return allCookies
|
||||
if (persistCookies.length) await this.context.addCookies(persistCookies)
|
||||
|
||||
return cookiesToClear
|
||||
}
|
||||
|
||||
private async takeScreenshot (data) {
|
||||
@@ -347,7 +337,7 @@ export class WebKitAutomation {
|
||||
case 'is:automation:client:connected':
|
||||
return true
|
||||
case 'get:cookies':
|
||||
return await this.getCookies()
|
||||
return await this.getCookies(data)
|
||||
case 'get:cookie':
|
||||
return await this.getCookie(data)
|
||||
case 'set:cookie':
|
||||
@@ -356,7 +346,7 @@ export class WebKitAutomation {
|
||||
case 'set:cookies':
|
||||
return await this.context.addCookies(data.map(normalizeSetCookieProps))
|
||||
case 'clear:cookies':
|
||||
return await this.clearCookies()
|
||||
return await this.clearCookies(data)
|
||||
case 'clear:cookie':
|
||||
return await this.clearCookie(data)
|
||||
case 'take:screenshot':
|
||||
|
||||
@@ -2,7 +2,7 @@ const { expect, sinon } = require('../../spec_helper')
|
||||
|
||||
import {
|
||||
CdpAutomation,
|
||||
_cookieMatches,
|
||||
cookieMatches,
|
||||
_domainIsWithinSuperdomain,
|
||||
CyCookie,
|
||||
} from '../../../lib/browsers/cdp_automation'
|
||||
@@ -47,7 +47,7 @@ context('lib/browsers/cdp_automation', () => {
|
||||
})
|
||||
})
|
||||
|
||||
context('._cookieMatches', () => {
|
||||
context('.cookieMatches', () => {
|
||||
it('matches as expected', () => {
|
||||
[
|
||||
{
|
||||
@@ -61,7 +61,7 @@ context('lib/browsers/cdp_automation', () => {
|
||||
expected: true,
|
||||
},
|
||||
].forEach(({ cookie, filter, expected }) => {
|
||||
expect(_cookieMatches(cookie as CyCookie, filter)).to.eq(expected)
|
||||
expect(cookieMatches(cookie as CyCookie, filter)).to.eq(expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user