mirror of
https://github.com/cypress-io/cypress.git
synced 2026-05-06 23:10:22 -05:00
feat: Add new local and session storage commands (#24859)
This commit is contained in:
@@ -34,6 +34,12 @@ module.exports = {
|
||||
'plugin:@cypress/dev/tests',
|
||||
],
|
||||
parser: '@typescript-eslint/parser',
|
||||
ignorePatterns: [
|
||||
// cli types are checked by dtslint
|
||||
'cli/types/**',
|
||||
// these fixtures are supposed to fail linting
|
||||
'npm/eslint-plugin-dev/test/fixtures/**',
|
||||
],
|
||||
overrides: [
|
||||
{
|
||||
files: [
|
||||
|
||||
Vendored
+62
-1
@@ -142,6 +142,39 @@ declare namespace Cypress {
|
||||
clear: (keys?: string[]) => void
|
||||
}
|
||||
|
||||
// TODO: raise minimum required TypeScript version to 3.7
|
||||
// and make this recursive
|
||||
// https://github.com/cypress-io/cypress/issues/24875
|
||||
type Storable =
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null
|
||||
| StorableObject
|
||||
| StorableArray
|
||||
|
||||
interface StorableObject {
|
||||
[key: string]: Storable
|
||||
}
|
||||
|
||||
interface StorableArray extends Array<Storable> { }
|
||||
|
||||
type StorableRecord = Record<string, Storable>
|
||||
|
||||
interface OriginStorage {
|
||||
origin: string
|
||||
value: StorableRecord
|
||||
}
|
||||
|
||||
interface Storages {
|
||||
localStorage: OriginStorage[]
|
||||
sessionStorage: OriginStorage[]
|
||||
}
|
||||
|
||||
interface StorageByOrigin {
|
||||
[key: string]: StorableRecord
|
||||
}
|
||||
|
||||
type IsBrowserMatcher = BrowserName | Partial<Browser> | Array<BrowserName | Partial<Browser>>
|
||||
|
||||
interface ViewportPosition extends WindowPosition {
|
||||
@@ -792,7 +825,35 @@ declare namespace Cypress {
|
||||
clearCookies(options?: CookieOptions): Chainable<null>
|
||||
|
||||
/**
|
||||
* Clear data in local storage.
|
||||
* Get local storage for all origins.
|
||||
*
|
||||
* @see https://on.cypress.io/getalllocalstorage
|
||||
*/
|
||||
getAllLocalStorage(options?: Partial<Loggable>): Chainable<StorageByOrigin>
|
||||
|
||||
/**
|
||||
* Clear local storage for all origins.
|
||||
*
|
||||
* @see https://on.cypress.io/clearalllocalstorage
|
||||
*/
|
||||
clearAllLocalStorage(options?: Partial<Loggable>): Chainable<null>
|
||||
|
||||
/**
|
||||
* Get session storage for all origins.
|
||||
*
|
||||
* @see https://on.cypress.io/getallsessionstorage
|
||||
*/
|
||||
getAllSessionStorage(options?: Partial<Loggable>): Chainable<StorageByOrigin>
|
||||
|
||||
/**
|
||||
* Clear session storage for all origins.
|
||||
*
|
||||
* @see https://on.cypress.io/clearallsessionstorage
|
||||
*/
|
||||
clearAllSessionStorage(options?: Partial<Loggable>): Chainable<null>
|
||||
|
||||
/**
|
||||
* Clear data in local storage for the current origin.
|
||||
* Cypress automatically runs this command 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 localStorage inside a single test. Yields `localStorage` object.
|
||||
|
||||
@@ -1062,3 +1062,29 @@ namespace CypressClearCookiesTests {
|
||||
cy.clearCookies({ timeout: '10' }) // $ExpectError
|
||||
cy.clearCookies({ domain: false }) // $ExpectError
|
||||
}
|
||||
|
||||
namespace CypressLocalStorageTests {
|
||||
cy.getAllLocalStorage().then((result) => {
|
||||
result // $ExpectType StorageByOrigin
|
||||
})
|
||||
cy.getAllLocalStorage({ log: false })
|
||||
cy.getAllLocalStorage({ log: 'true' }) // $ExpectError
|
||||
|
||||
cy.clearAllLocalStorage().then((result) => {
|
||||
result // $ExpectType null
|
||||
})
|
||||
cy.clearAllLocalStorage({ log: false })
|
||||
cy.clearAllLocalStorage({ log: 'true' }) // $ExpectError
|
||||
|
||||
cy.getAllSessionStorage().then((result) => {
|
||||
result // $ExpectType StorageByOrigin
|
||||
})
|
||||
cy.getAllSessionStorage({ log: false })
|
||||
cy.getAllSessionStorage({ log: 'true' }) // $ExpectError
|
||||
|
||||
cy.clearAllSessionStorage().then((result) => {
|
||||
result // $ExpectType null
|
||||
})
|
||||
cy.clearAllSessionStorage({ log: false })
|
||||
cy.clearAllSessionStorage({ log: 'true' }) // $ExpectError
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@ export default defineConfig({
|
||||
experimentalStudio: true,
|
||||
experimentalWebKitSupport: true,
|
||||
hosts: {
|
||||
'foobar.com': '127.0.0.1',
|
||||
'*.foobar.com': '127.0.0.1',
|
||||
'barbaz.com': '127.0.0.1',
|
||||
'*.barbaz.com': '127.0.0.1',
|
||||
'*.idp.com': '127.0.0.1',
|
||||
'localalias': '127.0.0.1',
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
describe('src/cy/commands/local_storage', () => {
|
||||
context('#clearLocalStorage', () => {
|
||||
it('passes keys onto Cypress.LocalStorage.clear', () => {
|
||||
const clear = cy.spy(Cypress.LocalStorage, 'clear')
|
||||
|
||||
cy.clearLocalStorage('foo').then(() => {
|
||||
expect(clear).to.be.calledWith('foo')
|
||||
})
|
||||
})
|
||||
|
||||
it('sets the storages', () => {
|
||||
const {
|
||||
localStorage,
|
||||
} = window
|
||||
const remoteStorage = cy.state('window').localStorage
|
||||
|
||||
const setStorages = cy.spy(Cypress.LocalStorage, 'setStorages')
|
||||
|
||||
cy.clearLocalStorage().then(() => {
|
||||
expect(setStorages).to.be.calledWith(localStorage, remoteStorage)
|
||||
})
|
||||
})
|
||||
|
||||
it('unsets the storages', () => {
|
||||
const unsetStorages = cy.spy(Cypress.LocalStorage, 'unsetStorages')
|
||||
|
||||
cy.clearLocalStorage().then(() => {
|
||||
expect(unsetStorages).to.be.called
|
||||
})
|
||||
})
|
||||
|
||||
it('sets subject to remote localStorage', () => {
|
||||
const ls = cy.state('window').localStorage
|
||||
|
||||
cy.clearLocalStorage().then((remote) => {
|
||||
expect(remote).to.eq(ls)
|
||||
})
|
||||
})
|
||||
|
||||
describe('test:before:run', () => {
|
||||
it('clears localStorage before each test run', () => {
|
||||
const clear = cy.spy(Cypress.LocalStorage, 'clear')
|
||||
|
||||
Cypress.emit('test:before:run', {})
|
||||
if (Cypress.config('experimentalSessionAndOrigin')) {
|
||||
expect(clear).not.to.be.called
|
||||
} else {
|
||||
expect(clear).to.be.calledWith([])
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('errors', () => {
|
||||
it('throws when being passed a non string or regexp', (done) => {
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.include('`cy.clearLocalStorage()` must be called with either a string or regular expression.')
|
||||
expect(err.docsUrl).to.include('https://on.cypress.io/clearlocalstorage')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
// A number is used as an object will be considered as `options`
|
||||
cy.clearLocalStorage(1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('.log', () => {
|
||||
beforeEach(function () {
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
this.lastLog = log
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('ends immediately', () => {
|
||||
cy.clearLocalStorage().then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('ended')).to.be.true
|
||||
expect(lastLog.get('state')).to.eq('passed')
|
||||
})
|
||||
})
|
||||
|
||||
it('snapshots immediately', () => {
|
||||
cy.clearLocalStorage().then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('snapshots').length).to.eq(1)
|
||||
expect(lastLog.get('snapshots')[0]).to.be.an('object')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('without log', () => {
|
||||
beforeEach(function () {
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
this.lastLog = log
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('log is disabled', () => {
|
||||
cy.clearLocalStorage('foo', { log: false }).then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog).to.be.undefined
|
||||
})
|
||||
})
|
||||
|
||||
it('log is disabled without key', () => {
|
||||
cy.clearLocalStorage({ log: false }).then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog).to.be.undefined
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -3,12 +3,10 @@ const $Cypress = require('../../../../src/cypress').default
|
||||
|
||||
describe('src/cy/commands/sessions/manager.ts', () => {
|
||||
let CypressInstance
|
||||
let baseUrl
|
||||
|
||||
beforeEach(function () {
|
||||
// @ts-ignore
|
||||
CypressInstance = new $Cypress()
|
||||
baseUrl = Cypress.config('baseUrl')
|
||||
})
|
||||
|
||||
it('creates SessionsManager instance', () => {
|
||||
@@ -168,70 +166,6 @@ describe('src/cy/commands/sessions/manager.ts', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('.mapOrigins()', () => {
|
||||
it('maps when requesting all origins', async () => {
|
||||
const sessionsManager = new SessionsManager(CypressInstance, cy)
|
||||
|
||||
const allOrigins = ['https://example.com', baseUrl, 'http://foobar.com', 'http://foobar.com']
|
||||
const sessionsSpy = cy.stub(sessionsManager, 'getAllHtmlOrigins').resolves(allOrigins)
|
||||
|
||||
const origins = await sessionsManager.mapOrigins('*')
|
||||
|
||||
expect(origins).to.deep.eq(['https://example.com', baseUrl, 'http://foobar.com'])
|
||||
expect(sessionsSpy).to.be.calledOnce
|
||||
})
|
||||
|
||||
it('maps when requesting the current origin', async () => {
|
||||
const sessionsManager = new SessionsManager(CypressInstance, cy)
|
||||
const sessionsSpy = cy.stub(sessionsManager, 'getAllHtmlOrigins')
|
||||
const origins = await sessionsManager.mapOrigins('currentOrigin')
|
||||
|
||||
expect(origins).to.deep.eq([baseUrl])
|
||||
expect(sessionsSpy).not.to.be.called
|
||||
})
|
||||
|
||||
it('maps when requesting a specific origin', async () => {
|
||||
const sessionsManager = new SessionsManager(CypressInstance, cy)
|
||||
const sessionsSpy = cy.stub(sessionsManager, 'getAllHtmlOrigins')
|
||||
const origins = await sessionsManager.mapOrigins('https://example.com/random_page?1')
|
||||
|
||||
expect(origins).to.deep.eq(['https://example.com'])
|
||||
expect(sessionsSpy).not.to.be.called
|
||||
})
|
||||
|
||||
it('maps when requesting a list of origins', async () => {
|
||||
const sessionsManager = new SessionsManager(CypressInstance, cy)
|
||||
|
||||
const allOrigins = ['https://example.com', baseUrl, 'http://foobar.com', 'http://foobar.com']
|
||||
const sessionsSpy = cy.stub(sessionsManager, 'getAllHtmlOrigins').resolves(allOrigins)
|
||||
|
||||
const origins = await sessionsManager.mapOrigins(['*', 'https://other.com'])
|
||||
|
||||
expect(origins).to.deep.eq(['https://example.com', baseUrl, 'http://foobar.com', 'https://other.com'])
|
||||
expect(sessionsSpy).to.be.calledOnce
|
||||
})
|
||||
})
|
||||
|
||||
// TODO:
|
||||
describe('._setStorageOnOrigins()', () => {})
|
||||
|
||||
it('.getAllHtmlOrigins()', async () => {
|
||||
const storedOrigins = {
|
||||
'https://example.com': {},
|
||||
'https://foobar.com': {},
|
||||
}
|
||||
|
||||
storedOrigins[`${baseUrl}`] = {}
|
||||
const cypressSpy = cy.stub(CypressInstance, 'backend').callThrough().withArgs('get:rendered:html:origins').resolves(storedOrigins)
|
||||
const sessionsManager = new SessionsManager(CypressInstance, cy)
|
||||
|
||||
const origins = await sessionsManager.getAllHtmlOrigins()
|
||||
|
||||
expect(cypressSpy).have.been.calledOnce
|
||||
expect(origins).to.have.lengthOf(3)
|
||||
expect(origins).to.deep.eq(['https://example.com', 'https://foobar.com', baseUrl])
|
||||
})
|
||||
|
||||
describe('.sessions', () => {
|
||||
it('sessions.defineSession()', () => {
|
||||
const sessionsManager = new SessionsManager(CypressInstance, cy)
|
||||
@@ -273,17 +207,27 @@ describe('src/cy/commands/sessions/manager.ts', () => {
|
||||
expect(window.localStorage).of.have.lengthOf(1)
|
||||
expect(window.sessionStorage).of.have.lengthOf(1)
|
||||
|
||||
const specWindow = {}
|
||||
|
||||
CypressInstance.log = cy.stub()
|
||||
CypressInstance.state = cy.stub()
|
||||
CypressInstance.state.withArgs('specWindow').returns(specWindow)
|
||||
|
||||
const storedOrigins = {}
|
||||
|
||||
cy.stub(CypressInstance, 'backend')
|
||||
.callThrough()
|
||||
.withArgs('get:rendered:html:origins')
|
||||
.resolves(storedOrigins)
|
||||
|
||||
const sessionsManager = new SessionsManager(CypressInstance, {
|
||||
state: () => true,
|
||||
})
|
||||
|
||||
const clearStorageSpy = cy.stub(sessionsManager.sessions, 'clearStorage')
|
||||
const clearCookiesSpy = cy.stub(sessionsManager.sessions, 'clearCookies')
|
||||
|
||||
await sessionsManager.sessions.clearCurrentSessionData()
|
||||
|
||||
expect(clearStorageSpy).to.be.calledOnce
|
||||
expect(clearCookiesSpy).to.be.calledOnce
|
||||
expect(window.localStorage).of.have.lengthOf(0)
|
||||
expect(window.sessionStorage).of.have.lengthOf(0)
|
||||
@@ -292,8 +236,8 @@ describe('src/cy/commands/sessions/manager.ts', () => {
|
||||
|
||||
it('does not log message when setting up tests', async () => {
|
||||
// Unable to cleanly mock localStorage or sessionStorage on Firefox,
|
||||
// so add dummy values and ensure they are cleared as expected.
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1141698
|
||||
// so add dummy values and ensure they are cleared as expected.
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1141698
|
||||
window.localStorage.foo = 'bar'
|
||||
window.sessionStorage.jazzy = 'music'
|
||||
|
||||
@@ -301,16 +245,14 @@ describe('src/cy/commands/sessions/manager.ts', () => {
|
||||
expect(window.sessionStorage).of.have.lengthOf(1)
|
||||
|
||||
CypressInstance.log = cy.stub()
|
||||
const sessionsManager = new SessionsManager(CypressInstance, {
|
||||
const sessionsManager = new SessionsManager(Cypress, {
|
||||
state: () => false,
|
||||
})
|
||||
|
||||
const clearStorageSpy = cy.stub(sessionsManager.sessions, 'clearStorage')
|
||||
const clearCookiesSpy = cy.stub(sessionsManager.sessions, 'clearCookies')
|
||||
|
||||
await sessionsManager.sessions.clearCurrentSessionData()
|
||||
|
||||
expect(clearStorageSpy).to.be.calledOnce
|
||||
expect(clearCookiesSpy).to.be.calledOnce
|
||||
expect(window.localStorage).of.have.lengthOf(0)
|
||||
expect(window.sessionStorage).of.have.lengthOf(0)
|
||||
@@ -373,19 +315,18 @@ describe('src/cy/commands/sessions/manager.ts', () => {
|
||||
expect(cypressSpy).to.be.calledOnceWith('clear:cookies', cookies)
|
||||
})
|
||||
|
||||
it('sessions.getCurrentSessionData', async () => {
|
||||
const sessionsManager = new SessionsManager(CypressInstance, () => {})
|
||||
const getStorageSpy = cy.stub(sessionsManager.sessions, 'getStorage').resolves({ localStorage: [] })
|
||||
it('sessions.getCurrentSessionData()', async () => {
|
||||
const sessionsManager = new SessionsManager(Cypress, () => {})
|
||||
const cookiesSpy = cy.stub(sessionsManager.sessions, 'getCookies').resolves([{ id: 'cookie' }])
|
||||
|
||||
const sessData = await sessionsManager.sessions.getCurrentSessionData()
|
||||
|
||||
expect(sessData).to.deep.eq({
|
||||
expect(sessData).to.deep.equal({
|
||||
localStorage: [],
|
||||
sessionStorage: [],
|
||||
cookies: [{ id: 'cookie' }],
|
||||
})
|
||||
|
||||
expect(getStorageSpy).to.be.calledOnce
|
||||
expect(cookiesSpy).to.be.calledOnce
|
||||
})
|
||||
|
||||
@@ -398,14 +339,5 @@ describe('src/cy/commands/sessions/manager.ts', () => {
|
||||
|
||||
expect(cypressSpy).to.be.calledOnceWith('get:session', 'session_1')
|
||||
})
|
||||
|
||||
// TODO:
|
||||
describe('sessions.getStorage', () => {})
|
||||
|
||||
// TODO:
|
||||
describe('sessions.clearStorage', () => {})
|
||||
|
||||
// TODO:
|
||||
describe('sessions.setStorage', () => {})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
import { getAllHtmlOrigins, mapOrigins } from '../../../../src/cy/commands/sessions/origins'
|
||||
const $Cypress = require('../../../../src/cypress').default
|
||||
|
||||
describe('src/cy/commands/sessions/origins', () => {
|
||||
let CypressInstance
|
||||
let baseUrl
|
||||
|
||||
beforeEach(function () {
|
||||
// @ts-ignore
|
||||
CypressInstance = new $Cypress()
|
||||
baseUrl = Cypress.config('baseUrl')
|
||||
})
|
||||
|
||||
describe('mapOrigins()', () => {
|
||||
it('returns unique origins when requesting all origins', async () => {
|
||||
const storedOrigins = {
|
||||
[baseUrl]: {},
|
||||
'https://example.com': {},
|
||||
'http://foobar.com': {},
|
||||
}
|
||||
|
||||
cy.stub(CypressInstance, 'backend')
|
||||
.callThrough()
|
||||
.withArgs('get:rendered:html:origins')
|
||||
.resolves(storedOrigins)
|
||||
|
||||
const origins = await mapOrigins(CypressInstance, '*')
|
||||
|
||||
expect(origins).to.deep.equal([baseUrl, 'https://example.com', 'http://foobar.com'])
|
||||
})
|
||||
|
||||
it('returns current origin when requesting the current origin', async () => {
|
||||
cy.stub(CypressInstance, 'backend').callThrough().withArgs('get:rendered:html:origins')
|
||||
|
||||
const origins = await mapOrigins(CypressInstance, 'currentOrigin')
|
||||
|
||||
expect(origins).to.deep.equal([baseUrl])
|
||||
expect(CypressInstance.backend).not.to.be.calledWith('get:rendered:html:origins')
|
||||
})
|
||||
|
||||
it('returns specific origin when requesitng a specific origin', async () => {
|
||||
cy.stub(CypressInstance, 'backend').callThrough().withArgs('get:rendered:html:origins')
|
||||
|
||||
const origins = await mapOrigins(CypressInstance, 'https://example.com/random_page?1')
|
||||
|
||||
expect(origins).to.deep.equal(['https://example.com'])
|
||||
expect(CypressInstance.backend).not.to.be.calledWith('get:rendered:html:origins')
|
||||
})
|
||||
|
||||
it('return origins when requesting a list of origins', async () => {
|
||||
const storedOrigins = {
|
||||
[baseUrl]: {},
|
||||
'https://example.com': {},
|
||||
'http://foobar.com': {},
|
||||
'https://other.com': {},
|
||||
}
|
||||
|
||||
cy.stub(CypressInstance, 'backend')
|
||||
.callThrough()
|
||||
.withArgs('get:rendered:html:origins')
|
||||
.resolves(storedOrigins)
|
||||
|
||||
const origins = await mapOrigins(CypressInstance, ['*', 'https://other.com'])
|
||||
|
||||
expect(origins).to.deep.equal([baseUrl, 'https://example.com', 'http://foobar.com', 'https://other.com'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('getAllHtmlOrigins()', () => {
|
||||
it('returns rendered html origins from backend', async () => {
|
||||
const storedOrigins = {
|
||||
[baseUrl]: {},
|
||||
'https://example.com': {},
|
||||
'http://foobar.com': {},
|
||||
}
|
||||
|
||||
cy.stub(CypressInstance, 'backend')
|
||||
.callThrough()
|
||||
.withArgs('get:rendered:html:origins')
|
||||
.resolves(storedOrigins)
|
||||
|
||||
const origins = await getAllHtmlOrigins(CypressInstance)
|
||||
|
||||
expect(origins).to.deep.equal([baseUrl, 'https://example.com', 'http://foobar.com'])
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,37 @@
|
||||
import { getStorage, setStorage } from '../../../../src/cy/commands/sessions/storage'
|
||||
|
||||
describe('src/cy/commands/sessions/storage', () => {
|
||||
describe('setStorage()', () => {
|
||||
it('returns unique origins when requesting all origins', () => {
|
||||
cy.visit('http://localhost:3500/fixtures/generic.html')
|
||||
.then(() => {
|
||||
localStorage.key1 = 'val1'
|
||||
|
||||
return setStorage(Cypress, { localStorage: [{ value: { key2: 'val2' } }] })
|
||||
})
|
||||
.then(() => {
|
||||
expect(window.localStorage.key2).equal('val2')
|
||||
})
|
||||
.then(() => {
|
||||
return setStorage(Cypress, {
|
||||
localStorage: [
|
||||
// set localStorage on different origin
|
||||
{ origin: 'http://www.foobar.com:3500', value: { key2: 'val' }, clear: true },
|
||||
// set localStorage on current origin
|
||||
{ value: { key3: 'val' }, clear: true },
|
||||
],
|
||||
})
|
||||
})
|
||||
.then(() => getStorage(Cypress, { origin: ['current_url', 'http://www.foobar.com:3500'] }))
|
||||
.then((result) => {
|
||||
expect(result).deep.equal({
|
||||
localStorage: [
|
||||
{ origin: 'http://localhost:3500', value: { key3: 'val' } },
|
||||
{ origin: 'http://www.foobar.com:3500', value: { key2: 'val' } },
|
||||
],
|
||||
sessionStorage: [],
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,325 @@
|
||||
import { assertLogLength } from '../../support/utils'
|
||||
|
||||
describe('src/cy/commands/storage', () => {
|
||||
let logs: Cypress.Log[]
|
||||
|
||||
beforeEach(() => {
|
||||
logs = []
|
||||
|
||||
cy.on('log:added', (attrs, log: Cypress.Log) => {
|
||||
logs.push(log)
|
||||
})
|
||||
})
|
||||
|
||||
context('#getAllLocalStorage', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/fixtures/set-storage-on-multiple-origins.html')
|
||||
})
|
||||
|
||||
it('gets local storage from all origins', () => {
|
||||
cy.getAllLocalStorage().should('deep.equal', {
|
||||
'http://localhost:3500': {
|
||||
key1: 'value1',
|
||||
key2: 'value2',
|
||||
},
|
||||
'http://www.foobar.com:3500': {
|
||||
key3: 'value3',
|
||||
key4: 'value4',
|
||||
},
|
||||
'http://other.foobar.com:3500': {
|
||||
key5: 'value5',
|
||||
key6: 'value6',
|
||||
},
|
||||
'http://barbaz.com:3500': {
|
||||
key7: 'value7',
|
||||
key8: 'value8',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('logs once', () => {
|
||||
cy.getAllLocalStorage().then(() => {
|
||||
assertLogLength(logs, 2)
|
||||
expect(logs[0].get('name')).to.eq('visit')
|
||||
expect(logs[1].get('name')).to.eq('getAllLocalStorage')
|
||||
})
|
||||
})
|
||||
|
||||
it('does not log when log: false', () => {
|
||||
cy.getAllLocalStorage({ log: false }).then(() => {
|
||||
assertLogLength(logs, 1)
|
||||
expect(logs[0].get('name')).to.eq('visit')
|
||||
})
|
||||
})
|
||||
|
||||
it('consoleProps includes the storage yielded', () => {
|
||||
cy.getAllLocalStorage().then(() => {
|
||||
const consoleProps = logs[1].get('consoleProps')()
|
||||
|
||||
expect(consoleProps).to.deep.equal({
|
||||
Command: 'getAllLocalStorage',
|
||||
Yielded: {
|
||||
'http://localhost:3500': {
|
||||
key1: 'value1',
|
||||
key2: 'value2',
|
||||
},
|
||||
'http://www.foobar.com:3500': {
|
||||
key3: 'value3',
|
||||
key4: 'value4',
|
||||
},
|
||||
'http://other.foobar.com:3500': {
|
||||
key5: 'value5',
|
||||
key6: 'value6',
|
||||
},
|
||||
'http://barbaz.com:3500': {
|
||||
key7: 'value7',
|
||||
key8: 'value8',
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('#clearAllLocalStorage', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/fixtures/set-storage-on-multiple-origins.html')
|
||||
})
|
||||
|
||||
it('clears local storage for all origins', () => {
|
||||
cy.clearAllLocalStorage()
|
||||
cy.getAllLocalStorage().should('deep.equal', {})
|
||||
})
|
||||
|
||||
it('logs once', () => {
|
||||
cy.clearAllLocalStorage().then(() => {
|
||||
assertLogLength(logs, 2)
|
||||
expect(logs[0].get('name')).to.eq('visit')
|
||||
expect(logs[1].get('name')).to.eq('clearAllLocalStorage')
|
||||
})
|
||||
})
|
||||
|
||||
it('does not log when log: false', () => {
|
||||
cy.clearAllLocalStorage({ log: false }).then(() => {
|
||||
assertLogLength(logs, 1)
|
||||
expect(logs[0].get('name')).to.eq('visit')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('#getAllSessionStorage', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/fixtures/set-storage-on-multiple-origins.html')
|
||||
})
|
||||
|
||||
it('gets local storage from all origins', () => {
|
||||
cy.getAllSessionStorage().should('deep.equal', {
|
||||
'http://localhost:3500': {
|
||||
key11: 'value11',
|
||||
key12: 'value12',
|
||||
},
|
||||
'http://www.foobar.com:3500': {
|
||||
key13: 'value13',
|
||||
key14: 'value14',
|
||||
},
|
||||
'http://other.foobar.com:3500': {
|
||||
key15: 'value15',
|
||||
key16: 'value16',
|
||||
},
|
||||
'http://barbaz.com:3500': {
|
||||
key17: 'value17',
|
||||
key18: 'value18',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('logs once', () => {
|
||||
cy.getAllSessionStorage().then(() => {
|
||||
assertLogLength(logs, 2)
|
||||
expect(logs[0].get('name')).to.eq('visit')
|
||||
expect(logs[1].get('name')).to.eq('getAllSessionStorage')
|
||||
})
|
||||
})
|
||||
|
||||
it('does not log when log: false', () => {
|
||||
cy.getAllSessionStorage({ log: false }).then(() => {
|
||||
assertLogLength(logs, 1)
|
||||
expect(logs[0].get('name')).to.eq('visit')
|
||||
})
|
||||
})
|
||||
|
||||
it('consoleProps includes the storage yielded', () => {
|
||||
cy.getAllSessionStorage().then(() => {
|
||||
const consoleProps = logs[1].get('consoleProps')()
|
||||
|
||||
expect(consoleProps).to.deep.equal({
|
||||
Command: 'getAllSessionStorage',
|
||||
Yielded: {
|
||||
'http://localhost:3500': {
|
||||
key11: 'value11',
|
||||
key12: 'value12',
|
||||
},
|
||||
'http://www.foobar.com:3500': {
|
||||
key13: 'value13',
|
||||
key14: 'value14',
|
||||
},
|
||||
'http://other.foobar.com:3500': {
|
||||
key15: 'value15',
|
||||
key16: 'value16',
|
||||
},
|
||||
'http://barbaz.com:3500': {
|
||||
key17: 'value17',
|
||||
key18: 'value18',
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('#clearAllSessionStorage', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/fixtures/set-storage-on-multiple-origins.html')
|
||||
})
|
||||
|
||||
it('clears session storage for all origins', () => {
|
||||
cy.clearAllSessionStorage()
|
||||
cy.getAllSessionStorage().should('deep.equal', {})
|
||||
})
|
||||
|
||||
it('logs once', () => {
|
||||
cy.clearAllSessionStorage().then(() => {
|
||||
assertLogLength(logs, 2)
|
||||
expect(logs[0].get('name')).to.eq('visit')
|
||||
expect(logs[1].get('name')).to.eq('clearAllSessionStorage')
|
||||
})
|
||||
})
|
||||
|
||||
it('does not log when log: false', () => {
|
||||
cy.clearAllSessionStorage({ log: false }).then(() => {
|
||||
assertLogLength(logs, 1)
|
||||
expect(logs[0].get('name')).to.eq('visit')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('#clearLocalStorage', () => {
|
||||
it('passes keys onto Cypress.LocalStorage.clear', () => {
|
||||
const clear = cy.spy(Cypress.LocalStorage, 'clear')
|
||||
|
||||
cy.clearLocalStorage('foo').then(() => {
|
||||
expect(clear).to.be.calledWith('foo')
|
||||
})
|
||||
})
|
||||
|
||||
it('sets the storages', () => {
|
||||
const {
|
||||
localStorage,
|
||||
} = window
|
||||
const remoteStorage = cy.state('window').localStorage
|
||||
|
||||
const setStorages = cy.spy<InternalCypress.LocalStorage>(Cypress.LocalStorage as InternalCypress.LocalStorage, 'setStorages')
|
||||
|
||||
cy.clearLocalStorage().then(() => {
|
||||
expect(setStorages).to.be.calledWith(localStorage, remoteStorage)
|
||||
})
|
||||
})
|
||||
|
||||
it('unsets the storages', () => {
|
||||
const unsetStorages = cy.spy<InternalCypress.LocalStorage>(Cypress.LocalStorage as InternalCypress.LocalStorage, 'unsetStorages')
|
||||
|
||||
cy.clearLocalStorage().then(() => {
|
||||
expect(unsetStorages).to.be.called
|
||||
})
|
||||
})
|
||||
|
||||
it('sets subject to remote localStorage', () => {
|
||||
const ls = cy.state('window').localStorage
|
||||
|
||||
cy.clearLocalStorage().then((remote) => {
|
||||
expect(remote).to.eq(ls)
|
||||
})
|
||||
})
|
||||
|
||||
describe('test:before:run', () => {
|
||||
it('clears localStorage before each test run', () => {
|
||||
const clear = cy.spy(Cypress.LocalStorage, 'clear')
|
||||
|
||||
Cypress.emit('test:before:run', {})
|
||||
if (Cypress.config('experimentalSessionAndOrigin')) {
|
||||
expect(clear).not.to.be.called
|
||||
} else {
|
||||
expect(clear).to.be.calledWith([])
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('errors', () => {
|
||||
it('throws when being passed a non string or regexp', (done) => {
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.include('`cy.clearLocalStorage()` must be called with either a string or regular expression.')
|
||||
expect(err.docsUrl).to.include('https://on.cypress.io/clearlocalstorage')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
// @ts-expect-error
|
||||
cy.clearLocalStorage(1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('.log', () => {
|
||||
beforeEach(function () {
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
this.lastLog = log
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('ends immediately', () => {
|
||||
cy.clearLocalStorage().then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('ended')).to.be.true
|
||||
expect(lastLog.get('state')).to.eq('passed')
|
||||
})
|
||||
})
|
||||
|
||||
it('snapshots immediately', () => {
|
||||
cy.clearLocalStorage().then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog.get('snapshots').length).to.eq(1)
|
||||
expect(lastLog.get('snapshots')[0]).to.be.an('object')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('without log', () => {
|
||||
beforeEach(function () {
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
this.lastLog = log
|
||||
})
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
it('log is disabled', () => {
|
||||
cy.clearLocalStorage('foo', { log: false }).then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog).to.be.undefined
|
||||
})
|
||||
})
|
||||
|
||||
it('log is disabled without key', () => {
|
||||
cy.clearLocalStorage({ log: false }).then(function () {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(lastLog).to.be.undefined
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,52 +0,0 @@
|
||||
import { findCrossOriginLogs } from '../../../../support/utils'
|
||||
|
||||
context('cy.origin local storage', { browser: '!webkit' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/fixtures/primary-origin.html')
|
||||
cy.get('a[data-cy="cross-origin-secondary-link"]').click()
|
||||
})
|
||||
|
||||
it('.clearLocalStorage()', () => {
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.window().then((win) => {
|
||||
win.localStorage.setItem('foo', 'bar')
|
||||
expect(win.localStorage.getItem('foo')).to.equal('bar')
|
||||
})
|
||||
|
||||
cy.clearLocalStorage().should((localStorage) => {
|
||||
expect(localStorage.length).to.equal(0)
|
||||
expect(localStorage.getItem('foo')).to.be.null
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('#consoleProps', () => {
|
||||
let logs: Map<string, any>
|
||||
|
||||
beforeEach(() => {
|
||||
logs = new Map()
|
||||
|
||||
cy.on('log:changed', (attrs, log) => {
|
||||
logs.set(attrs.id, log)
|
||||
})
|
||||
})
|
||||
|
||||
it('.clearLocalStorage()', () => {
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.window().then((win) => {
|
||||
win.localStorage.setItem('foo', 'bar')
|
||||
expect(win.localStorage.getItem('foo')).to.equal('bar')
|
||||
})
|
||||
|
||||
cy.clearLocalStorage()
|
||||
})
|
||||
|
||||
cy.shouldWithTimeout(() => {
|
||||
const { consoleProps } = findCrossOriginLogs('clearLocalStorage', logs, 'foobar.com')
|
||||
|
||||
expect(consoleProps.Command).to.equal('clearLocalStorage')
|
||||
expect(consoleProps.Yielded).to.be.null
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -219,7 +219,7 @@ it('verifies number of cy commands', () => {
|
||||
'focused', 'get', 'contains', 'root', 'shadow', 'within', 'request', 'session', 'screenshot', 'task', 'find', 'filter', 'not',
|
||||
'children', 'eq', 'closest', 'first', 'last', 'next', 'nextAll', 'nextUntil', 'parent', 'parents', 'parentsUntil', 'prev',
|
||||
'prevAll', 'prevUntil', 'siblings', 'wait', 'title', 'window', 'document', 'viewport', 'server', 'route', 'intercept', 'origin',
|
||||
'mount',
|
||||
'mount', 'getAllLocalStorage', 'clearAllLocalStorage', 'getAllSessionStorage', 'clearAllSessionStorage',
|
||||
]
|
||||
const addedCommands = Cypress._.difference(actualCommands, expectedCommands)
|
||||
const removedCommands = Cypress._.difference(expectedCommands, actualCommands)
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
import { findCrossOriginLogs } from '../../../../support/utils'
|
||||
|
||||
context('cy.origin storage', { browser: '!webkit' }, () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/fixtures/primary-origin.html')
|
||||
cy.get('a[data-cy="cross-origin-secondary-link"]').click()
|
||||
})
|
||||
|
||||
it('.getAllLocalStorage', () => {
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.visit('/fixtures/set-storage-on-multiple-origins.html')
|
||||
|
||||
cy.getAllLocalStorage().should('deep.equal', {
|
||||
'http://localhost:3500': {
|
||||
key1: 'value1',
|
||||
key2: 'value2',
|
||||
},
|
||||
'http://www.foobar.com:3500': {
|
||||
key3: 'value3',
|
||||
key4: 'value4',
|
||||
},
|
||||
'http://other.foobar.com:3500': {
|
||||
key5: 'value5',
|
||||
key6: 'value6',
|
||||
},
|
||||
'http://barbaz.com:3500': {
|
||||
key7: 'value7',
|
||||
key8: 'value8',
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('.clearAllLocalStorage', () => {
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.visit('/fixtures/set-storage-on-multiple-origins.html')
|
||||
|
||||
cy.clearAllLocalStorage()
|
||||
cy.getAllLocalStorage().should('deep.equal', {})
|
||||
})
|
||||
})
|
||||
|
||||
it('.getAllSessionStorage', () => {
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.visit('/fixtures/set-storage-on-multiple-origins.html')
|
||||
|
||||
cy.getAllSessionStorage().should('deep.equal', {
|
||||
'http://localhost:3500': {
|
||||
key11: 'value11',
|
||||
key12: 'value12',
|
||||
},
|
||||
'http://www.foobar.com:3500': {
|
||||
key13: 'value13',
|
||||
key14: 'value14',
|
||||
},
|
||||
'http://other.foobar.com:3500': {
|
||||
key15: 'value15',
|
||||
key16: 'value16',
|
||||
},
|
||||
'http://barbaz.com:3500': {
|
||||
key17: 'value17',
|
||||
key18: 'value18',
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('.clearAllSessionStorage', () => {
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.visit('/fixtures/set-storage-on-multiple-origins.html')
|
||||
|
||||
cy.clearAllSessionStorage()
|
||||
cy.getAllSessionStorage().should('deep.equal', {})
|
||||
})
|
||||
})
|
||||
|
||||
it('.clearLocalStorage()', () => {
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.window().then((win) => {
|
||||
win.localStorage.setItem('foo', 'bar')
|
||||
expect(win.localStorage.getItem('foo')).to.equal('bar')
|
||||
})
|
||||
|
||||
cy.clearLocalStorage().should((localStorage) => {
|
||||
expect(localStorage.length).to.equal(0)
|
||||
expect(localStorage.getItem('foo')).to.be.null
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('#consoleProps', () => {
|
||||
let logs: Map<string, any>
|
||||
|
||||
beforeEach(() => {
|
||||
logs = new Map()
|
||||
|
||||
cy.on('log:changed', (attrs, log) => {
|
||||
logs.set(attrs.id, log)
|
||||
})
|
||||
})
|
||||
|
||||
it('.clearLocalStorage()', () => {
|
||||
cy.origin('http://www.foobar.com:3500', () => {
|
||||
cy.window().then((win) => {
|
||||
win.localStorage.setItem('foo', 'bar')
|
||||
expect(win.localStorage.getItem('foo')).to.equal('bar')
|
||||
})
|
||||
|
||||
cy.clearLocalStorage()
|
||||
})
|
||||
|
||||
cy.shouldWithTimeout(() => {
|
||||
const { consoleProps } = findCrossOriginLogs('clearLocalStorage', logs, 'foobar.com')
|
||||
|
||||
expect(consoleProps.Command).to.equal('clearLocalStorage')
|
||||
expect(consoleProps.Yielded).to.be.null
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -230,7 +230,7 @@ describe('cy.origin Cypress API', { browser: '!webkit' }, () => {
|
||||
|
||||
it('throws an error when a user attempts to call Cypress.session.clearAllSavedSessions() inside of cy.origin', (done) => {
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.equal('`Cypress.session.*` methods are not supported in the `cy.switchToDomain()` callback. Consider using them outside of the callback instead.')
|
||||
expect(err.message).to.equal('`Cypress.session.*` methods are not supported in the `cy.origin()` callback. Consider using them outside of the callback instead.')
|
||||
expect(err.docsUrl).to.equal('https://on.cypress.io/session-api')
|
||||
done()
|
||||
})
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<h1>Set storage on multiple origins</h1>
|
||||
<script>
|
||||
const $ = Cypress.$
|
||||
|
||||
$(`<iframe src="http://localhost:3500/fixtures/set-storage.html?nums=1,2"></iframe>`).appendTo($('body'))
|
||||
$(`<iframe src="http://www.foobar.com:3500/fixtures/set-storage.html?nums=3,4"></iframe>`).appendTo($('body'))
|
||||
$(`<iframe src="http://other.foobar.com:3500/fixtures/set-storage.html?nums=5,6"></iframe>`).appendTo($('body'))
|
||||
$(`<iframe src="http://barbaz.com:3500/fixtures/set-storage.html?nums=7,8"></iframe>`).appendTo($('body'))
|
||||
</script>
|
||||
@@ -0,0 +1,10 @@
|
||||
<h1>Set storage</h1>
|
||||
<script>
|
||||
const urlParams = new URLSearchParams(window.location.search)
|
||||
const nums = urlParams.get('nums').split(',').map(Number)
|
||||
|
||||
nums.forEach((num) => {
|
||||
window.localStorage.setItem(`key${num}`, `value${num}`)
|
||||
window.sessionStorage.setItem(`key${num + 10}`, `value${num + 10}`)
|
||||
})
|
||||
</script>
|
||||
@@ -24,7 +24,7 @@ import * as Files from './files'
|
||||
|
||||
import * as Fixtures from './fixtures'
|
||||
|
||||
import LocalStorage from './local_storage'
|
||||
import Storage from './storage'
|
||||
|
||||
import * as Location from './location'
|
||||
|
||||
@@ -68,7 +68,7 @@ export const allCommands = {
|
||||
Exec,
|
||||
Files,
|
||||
Fixtures,
|
||||
LocalStorage,
|
||||
Storage,
|
||||
Location,
|
||||
Misc,
|
||||
Origin,
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import _ from 'lodash'
|
||||
import { $Location } from '../../../cypress/location'
|
||||
import type { ServerSessionData } from '@packages/types'
|
||||
import {
|
||||
getCurrentOriginStorage,
|
||||
setPostMessageLocalStorage,
|
||||
getPostMessageLocalStorage,
|
||||
} from './utils'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { getAllHtmlOrigins } from './origins'
|
||||
import { clearStorage, getStorage, setStorage } from './storage'
|
||||
|
||||
type ActiveSessions = Cypress.Commands.Session.ActiveSessions
|
||||
type SessionData = Cypress.Commands.Session.SessionData
|
||||
@@ -63,66 +60,6 @@ export default class SessionsManager {
|
||||
this.cy.state('activeSessions', clearedSessions)
|
||||
}
|
||||
|
||||
mapOrigins = async (origins: string | Array<string>): Promise<Array<string>> => {
|
||||
const getOrigins = this.Cypress.Promise.map(
|
||||
([] as string[]).concat(origins), async (v) => {
|
||||
if (v === '*') {
|
||||
return await this.getAllHtmlOrigins()
|
||||
}
|
||||
|
||||
if (v === 'currentOrigin') {
|
||||
return $Location.create(window.location.href).origin
|
||||
}
|
||||
|
||||
return $Location.create(v).origin
|
||||
},
|
||||
)
|
||||
|
||||
return _.uniq(_.flatten(await getOrigins))
|
||||
}
|
||||
|
||||
_setStorageOnOrigins = async (originOptions) => {
|
||||
const specWindow = this.cy.state('specWindow')
|
||||
|
||||
const currentOrigin = $Location.create(window.location.href).origin
|
||||
|
||||
const currentOriginIndex = _.findIndex(originOptions, { origin: currentOrigin })
|
||||
|
||||
if (currentOriginIndex !== -1) {
|
||||
const opts = originOptions.splice(currentOriginIndex, 1)[0]
|
||||
|
||||
if (!_.isEmpty(opts.localStorage)) {
|
||||
if (opts.localStorage.clear) {
|
||||
window.localStorage.clear()
|
||||
}
|
||||
|
||||
_.each(opts.localStorage.value, (val, key) => localStorage.setItem(key, val))
|
||||
}
|
||||
|
||||
if (opts.sessionStorage) {
|
||||
if (opts.sessionStorage.clear) {
|
||||
window.sessionStorage.clear()
|
||||
}
|
||||
|
||||
_.each(opts.sessionStorage.value, (val, key) => sessionStorage.setItem(key, val))
|
||||
}
|
||||
}
|
||||
|
||||
if (_.isEmpty(originOptions)) {
|
||||
return
|
||||
}
|
||||
|
||||
await setPostMessageLocalStorage(specWindow, originOptions)
|
||||
}
|
||||
|
||||
getAllHtmlOrigins = async () => {
|
||||
const currentOrigin = $Location.create(window.location.href).origin
|
||||
const storedOrigins = await this.Cypress.backend('get:rendered:html:origins')
|
||||
const origins = [..._.keys(storedOrigins), currentOrigin]
|
||||
|
||||
return _.uniq(origins)
|
||||
}
|
||||
|
||||
// this the public api exposed to consumers as Cypress.session
|
||||
sessions = {
|
||||
defineSession: (options = {} as any): SessionData => {
|
||||
@@ -156,7 +93,7 @@ export default class SessionsManager {
|
||||
window.sessionStorage.clear()
|
||||
|
||||
await Promise.all([
|
||||
this.sessions.clearStorage(),
|
||||
clearStorage(this.Cypress),
|
||||
this.sessions.clearCookies(),
|
||||
])
|
||||
},
|
||||
@@ -170,7 +107,7 @@ export default class SessionsManager {
|
||||
},
|
||||
|
||||
setSessionData: async (data) => {
|
||||
const allHtmlOrigins = await this.getAllHtmlOrigins()
|
||||
const allHtmlOrigins = await getAllHtmlOrigins(this.Cypress)
|
||||
|
||||
let _localStorage = data.localStorage || []
|
||||
let _sessionStorage = data.sessionStorage || []
|
||||
@@ -186,7 +123,7 @@ export default class SessionsManager {
|
||||
})
|
||||
|
||||
await Promise.all([
|
||||
this.sessions.setStorage({ localStorage: _localStorage, sessionStorage: _sessionStorage }),
|
||||
setStorage(this.Cypress, { localStorage: _localStorage, sessionStorage: _sessionStorage }),
|
||||
this.sessions.setCookies(data.cookies),
|
||||
])
|
||||
},
|
||||
@@ -205,7 +142,7 @@ export default class SessionsManager {
|
||||
|
||||
getCurrentSessionData: async () => {
|
||||
const [storage, cookies] = await Promise.all([
|
||||
this.sessions.getStorage({ origin: '*' }),
|
||||
getStorage(this.Cypress, { origin: '*' }),
|
||||
this.sessions.getCookies(),
|
||||
])
|
||||
|
||||
@@ -218,110 +155,5 @@ export default class SessionsManager {
|
||||
getSession: (id: string): Promise<ServerSessionData> => {
|
||||
return this.Cypress.backend('get:session', id)
|
||||
},
|
||||
|
||||
/**
|
||||
* 1) if we only need currentOrigin localStorage, access sync
|
||||
* 2) if cross-origin http, we need to load in iframe from our proxy that will intercept all http reqs at /__cypress/automation/*
|
||||
* and postMessage() the localStorage value to us
|
||||
* 3) if cross-origin https, since we pass-thru https connections in the proxy, we need to
|
||||
* send a message telling our proxy server to intercept the next req to the https domain,
|
||||
* then follow 2)
|
||||
*/
|
||||
getStorage: async (options = {}) => {
|
||||
const specWindow = this.cy.state('specWindow')
|
||||
|
||||
if (!_.isObject(options)) {
|
||||
throw new Error('getStorage() takes an object')
|
||||
}
|
||||
|
||||
const opts = _.defaults({}, options, {
|
||||
origin: 'currentOrigin',
|
||||
})
|
||||
|
||||
const currentOrigin = $Location.create(window.location.href).origin
|
||||
|
||||
const origins: Array<string> = await this.mapOrigins(opts.origin)
|
||||
|
||||
const results = {
|
||||
localStorage: [] as any[],
|
||||
sessionStorage: [] as any[],
|
||||
}
|
||||
|
||||
function pushValue (origin, value) {
|
||||
if (!_.isEmpty(value.localStorage)) {
|
||||
results.localStorage.push({ origin, value: value.localStorage })
|
||||
}
|
||||
|
||||
if (!_.isEmpty(value.sessionStorage)) {
|
||||
results.sessionStorage.push({ origin, value: value.sessionStorage })
|
||||
}
|
||||
}
|
||||
|
||||
const currentOriginIndex = origins.indexOf(currentOrigin)
|
||||
|
||||
if (currentOriginIndex !== -1) {
|
||||
origins.splice(currentOriginIndex, 1)
|
||||
const currentOriginStorage = getCurrentOriginStorage()
|
||||
|
||||
pushValue(currentOrigin, currentOriginStorage)
|
||||
}
|
||||
|
||||
if (_.isEmpty(origins)) {
|
||||
return results
|
||||
}
|
||||
|
||||
if (currentOrigin.startsWith('https:')) {
|
||||
_.remove(origins, (v) => v.startsWith('http:'))
|
||||
}
|
||||
|
||||
const postMessageResults = await getPostMessageLocalStorage(specWindow, origins)
|
||||
|
||||
postMessageResults.forEach((val) => {
|
||||
pushValue(val[0], val[1])
|
||||
})
|
||||
|
||||
return results
|
||||
},
|
||||
|
||||
clearStorage: async () => {
|
||||
const origins = await this.getAllHtmlOrigins()
|
||||
|
||||
const originOptions = origins.map((v) => ({ origin: v, clear: true }))
|
||||
|
||||
await this.sessions.setStorage({
|
||||
localStorage: originOptions,
|
||||
sessionStorage: originOptions,
|
||||
})
|
||||
},
|
||||
|
||||
setStorage: async (options: any, clearAll = false) => {
|
||||
const currentOrigin = $Location.create(window.location.href).origin as string
|
||||
|
||||
const mapToCurrentOrigin = (v) => ({ ...v, origin: (v.origin && v.origin !== 'currentOrigin') ? $Location.create(v.origin).origin : currentOrigin })
|
||||
|
||||
const mappedLocalStorage = _.map(options.localStorage, (v) => {
|
||||
const mapped = { origin: v.origin, localStorage: _.pick(v, 'value', 'clear') }
|
||||
|
||||
if (clearAll) {
|
||||
mapped.localStorage.clear = true
|
||||
}
|
||||
|
||||
return mapped
|
||||
}).map(mapToCurrentOrigin)
|
||||
|
||||
const mappedSessionStorage = _.map(options.sessionStorage, (v) => {
|
||||
const mapped = { origin: v.origin, sessionStorage: _.pick(v, 'value', 'clear') }
|
||||
|
||||
if (clearAll) {
|
||||
mapped.sessionStorage.clear = true
|
||||
}
|
||||
|
||||
return mapped
|
||||
}).map(mapToCurrentOrigin)
|
||||
|
||||
const storageOptions = _.map(_.groupBy(mappedLocalStorage.concat(mappedSessionStorage), 'origin'), (v) => _.merge({}, ...v))
|
||||
|
||||
await this._setStorageOnOrigins(storageOptions)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import Bluebird from 'bluebird'
|
||||
import { $Location } from '../../../cypress/location'
|
||||
|
||||
export async function mapOrigins (Cypress: Cypress.Cypress, origins: string | string[]): Promise<string[]> {
|
||||
const getOrigins = Bluebird.map(
|
||||
([] as string[]).concat(origins), async (origin) => {
|
||||
if (origin === '*') {
|
||||
return await getAllHtmlOrigins(Cypress)
|
||||
}
|
||||
|
||||
if (origin === 'currentOrigin') {
|
||||
return window.location.origin
|
||||
}
|
||||
|
||||
return $Location.create(origin).origin
|
||||
},
|
||||
)
|
||||
|
||||
return _.uniq(_.flatten(await getOrigins))
|
||||
}
|
||||
|
||||
export async function getAllHtmlOrigins (Cypress: Cypress.Cypress) {
|
||||
const currentOrigin = window.location.origin
|
||||
const storedOrigins = await Cypress.backend('get:rendered:html:origins')
|
||||
const origins = [..._.keys(storedOrigins), currentOrigin]
|
||||
|
||||
return _.uniq(origins)
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
import _ from 'lodash'
|
||||
|
||||
import { $Location } from '../../../cypress/location'
|
||||
import { getAllHtmlOrigins, mapOrigins } from './origins'
|
||||
import { getCurrentOriginStorage, getPostMessageLocalStorage, setPostMessageLocalStorage } from './utils'
|
||||
|
||||
export type StorageType = 'localStorage' | 'sessionStorage'
|
||||
|
||||
interface GetStorageOptions {
|
||||
origin?: '*' | 'currentOrigin' | string | string[]
|
||||
}
|
||||
|
||||
interface OriginStorageOptions {
|
||||
clear?: boolean
|
||||
origin?: string | string[]
|
||||
value?: any
|
||||
}
|
||||
|
||||
interface SetStoragesOptions {
|
||||
localStorage?: OriginStorageOptions[]
|
||||
sessionStorage?: OriginStorageOptions[]
|
||||
}
|
||||
/**
|
||||
* 1) if we only need currentOrigin localStorage, access sync
|
||||
* 2) if cross-origin http, we need to load in iframe from our proxy that will intercept all http reqs at /__cypress/automation/*
|
||||
* and postMessage() the localStorage value to us
|
||||
* 3) if cross-origin https, since we pass-thru https connections in the proxy, we need to
|
||||
* send a message telling our proxy server to intercept the next req to the https domain,
|
||||
* then follow 2)
|
||||
*/
|
||||
export async function getStorage (Cypress: Cypress.Cypress, options: GetStorageOptions = {}): Promise<Cypress.Storages> {
|
||||
const specWindow = Cypress.state('specWindow')
|
||||
|
||||
if (!_.isObject(options)) {
|
||||
throw new Error('getStorage() takes an object')
|
||||
}
|
||||
|
||||
const opts = _.defaults({}, options, {
|
||||
origin: 'currentOrigin',
|
||||
})
|
||||
|
||||
const currentOrigin = window.location.origin
|
||||
const origins: Array<string> = await mapOrigins(Cypress, opts.origin)
|
||||
const results = {
|
||||
localStorage: [] as Cypress.OriginStorage[],
|
||||
sessionStorage: [] as Cypress.OriginStorage[],
|
||||
}
|
||||
|
||||
function pushValue (origin, value) {
|
||||
if (!_.isEmpty(value.localStorage)) {
|
||||
results.localStorage.push({ origin, value: value.localStorage })
|
||||
}
|
||||
|
||||
if (!_.isEmpty(value.sessionStorage)) {
|
||||
results.sessionStorage.push({ origin, value: value.sessionStorage })
|
||||
}
|
||||
}
|
||||
|
||||
const currentOriginIndex = origins.indexOf(currentOrigin)
|
||||
|
||||
if (currentOriginIndex !== -1) {
|
||||
origins.splice(currentOriginIndex, 1)
|
||||
const currentOriginStorage = getCurrentOriginStorage()
|
||||
|
||||
pushValue(currentOrigin, currentOriginStorage)
|
||||
}
|
||||
|
||||
if (_.isEmpty(origins)) {
|
||||
return results
|
||||
}
|
||||
|
||||
if (currentOrigin.startsWith('https:')) {
|
||||
_.remove(origins, (v) => v.startsWith('http:'))
|
||||
}
|
||||
|
||||
const postMessageResults = await getPostMessageLocalStorage(specWindow, origins)
|
||||
|
||||
postMessageResults.forEach((val) => {
|
||||
pushValue(val[0], val[1])
|
||||
})
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
export async function clearStorage (Cypress: Cypress.Cypress, type?: StorageType) {
|
||||
const origins = await getAllHtmlOrigins(Cypress)
|
||||
const originOptions = origins.map((origin) => ({ origin, clear: true }))
|
||||
const options: SetStoragesOptions = {}
|
||||
|
||||
if (!type || type === 'localStorage') {
|
||||
options.localStorage = originOptions
|
||||
}
|
||||
|
||||
if (!type || type === 'sessionStorage') {
|
||||
options.sessionStorage = originOptions
|
||||
}
|
||||
|
||||
await setStorage(Cypress, options)
|
||||
}
|
||||
|
||||
async function setStorageOnOrigins (Cypress: Cypress.Cypress, originOptions) {
|
||||
const specWindow = Cypress.state('specWindow')
|
||||
|
||||
const currentOrigin = window.location.origin
|
||||
|
||||
const currentOriginIndex = _.findIndex(originOptions, { origin: currentOrigin })
|
||||
|
||||
if (currentOriginIndex !== -1) {
|
||||
const opts = originOptions.splice(currentOriginIndex, 1)[0]
|
||||
|
||||
if (!_.isEmpty(opts.localStorage)) {
|
||||
if (opts.localStorage.clear) {
|
||||
window.localStorage.clear()
|
||||
}
|
||||
|
||||
_.each(opts.localStorage.value, (val, key) => localStorage.setItem(key, val))
|
||||
}
|
||||
|
||||
if (opts.sessionStorage) {
|
||||
if (opts.sessionStorage.clear) {
|
||||
window.sessionStorage.clear()
|
||||
}
|
||||
|
||||
_.each(opts.sessionStorage.value, (val, key) => sessionStorage.setItem(key, val))
|
||||
}
|
||||
}
|
||||
|
||||
if (_.isEmpty(originOptions)) {
|
||||
return
|
||||
}
|
||||
|
||||
await setPostMessageLocalStorage(specWindow, originOptions)
|
||||
}
|
||||
|
||||
export async function setStorage (Cypress: Cypress.Cypress, options: SetStoragesOptions) {
|
||||
const currentOrigin = window.location.origin
|
||||
|
||||
function mapToCurrentOrigin (v) {
|
||||
return {
|
||||
...v,
|
||||
origin: (v.origin && v.origin !== 'currentOrigin')
|
||||
? $Location.create(v.origin).origin
|
||||
: currentOrigin,
|
||||
}
|
||||
}
|
||||
|
||||
const mappedLocalStorage = _.map(options.localStorage, (v) => {
|
||||
return mapToCurrentOrigin({ origin: v.origin, localStorage: _.pick(v, 'value', 'clear') })
|
||||
})
|
||||
|
||||
const mappedSessionStorage = _.map(options.sessionStorage, (v) => {
|
||||
return mapToCurrentOrigin({ origin: v.origin, sessionStorage: _.pick(v, 'value', 'clear') })
|
||||
})
|
||||
|
||||
const storageOptions = _.map(_.groupBy(mappedLocalStorage.concat(mappedSessionStorage), 'origin'), (v) => _.merge({}, ...v))
|
||||
|
||||
await setStorageOnOrigins(Cypress, storageOptions)
|
||||
}
|
||||
+59
-2
@@ -2,6 +2,9 @@ import _ from 'lodash'
|
||||
|
||||
import $errUtils from '../../cypress/error_utils'
|
||||
import $LocalStorage from '../../cypress/local_storage'
|
||||
import { clearStorage, getStorage, StorageType } from './sessions/storage'
|
||||
|
||||
type Options = Partial<Cypress.Loggable>
|
||||
|
||||
const clearLocalStorage = (state, keys) => {
|
||||
const local = window.localStorage
|
||||
@@ -20,7 +23,55 @@ const clearLocalStorage = (state, keys) => {
|
||||
return remote
|
||||
}
|
||||
|
||||
export default (Commands, Cypress, cy, state) => {
|
||||
const getAllStorage = async (type: StorageType, Cypress: InternalCypress.Cypress, userOptions: Options = {}) => {
|
||||
const options: Options = {
|
||||
log: true,
|
||||
...userOptions,
|
||||
}
|
||||
|
||||
let storageByOrigin: Cypress.StorageByOrigin = {}
|
||||
|
||||
if (options.log) {
|
||||
Cypress.log({
|
||||
consoleProps () {
|
||||
const obj = {}
|
||||
|
||||
if (Object.keys(storageByOrigin).length) {
|
||||
obj['Yielded'] = storageByOrigin
|
||||
}
|
||||
|
||||
return obj
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const storages = await getStorage(Cypress, { origin: '*' })
|
||||
|
||||
storageByOrigin = storages[type].reduce((memo, storage) => {
|
||||
memo[storage.origin] = storage.value
|
||||
|
||||
return memo
|
||||
}, {} as Cypress.StorageByOrigin)
|
||||
|
||||
return storageByOrigin
|
||||
}
|
||||
|
||||
const clearAllStorage = async (type: StorageType, Cypress: InternalCypress.Cypress, userOptions: Options = {}) => {
|
||||
const options: Options = {
|
||||
log: true,
|
||||
...userOptions,
|
||||
}
|
||||
|
||||
if (options.log) {
|
||||
Cypress.log({})
|
||||
}
|
||||
|
||||
await clearStorage(Cypress, type)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export default (Commands, Cypress: InternalCypress.Cypress, cy, state, config) => {
|
||||
// TODO: Cypress sessions will clear local storage on its own before each test.
|
||||
// Once experimentalSessionAndOrigin is made GA, remove this logic. Leave clearing
|
||||
// session data (cookies / local storage / session storage) to reset functionality
|
||||
@@ -38,7 +89,13 @@ export default (Commands, Cypress, cy, state) => {
|
||||
}
|
||||
|
||||
Commands.addAll({
|
||||
clearLocalStorage (keys, options: Partial<Cypress.Loggable> = {}) {
|
||||
getAllLocalStorage: getAllStorage.bind(null, 'localStorage', Cypress),
|
||||
getAllSessionStorage: getAllStorage.bind(null, 'sessionStorage', Cypress),
|
||||
|
||||
clearAllLocalStorage: clearAllStorage.bind(null, 'localStorage', Cypress),
|
||||
clearAllSessionStorage: clearAllStorage.bind(null, 'sessionStorage', Cypress),
|
||||
|
||||
clearLocalStorage (keys, options: Options = {}) {
|
||||
if (_.isPlainObject(keys)) {
|
||||
options = keys
|
||||
keys = null
|
||||
@@ -1304,7 +1304,7 @@ export default {
|
||||
docsUrl: 'https://on.cypress.io/github-issue/20721',
|
||||
},
|
||||
Cypress_session: {
|
||||
message: `\`Cypress.session.*\` methods are not supported in the ${cmd('switchToDomain')} callback. Consider using them outside of the callback instead.`,
|
||||
message: `\`Cypress.session.*\` methods are not supported in the ${cmd('origin')} callback. Consider using them outside of the callback instead.`,
|
||||
docsUrl: 'https://on.cypress.io/session-api',
|
||||
},
|
||||
},
|
||||
|
||||
+10
@@ -63,6 +63,16 @@ declare namespace Cypress {
|
||||
|
||||
interface Backend {
|
||||
(task: 'cross:origin:cookies:received'): Promise<void>
|
||||
(task: 'get:rendered:html:origins'): Promise<string[]>
|
||||
}
|
||||
}
|
||||
|
||||
declare namespace InternalCypress {
|
||||
interface Cypress extends Cypress.Cypress, NodeEventEmitter {}
|
||||
|
||||
interface LocalStorage extends Cypress.LocalStorage {
|
||||
setStorages: (local, remote) => LocalStorage
|
||||
unsetStorages: () => LocalStorage
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,13 +18,6 @@ exports['e2e sessions / session tests'] = `
|
||||
Running: session.cy.js (1 of 1)
|
||||
|
||||
|
||||
cross origin automations
|
||||
✓ get storage
|
||||
✓ get storage w/ sessionStorage
|
||||
✓ set storage
|
||||
✓ get localStorage from all origins
|
||||
✓ only gets localStorage from origins visited in test
|
||||
|
||||
with a blank session
|
||||
✓ t1
|
||||
✓ t2
|
||||
@@ -100,15 +93,15 @@ exports['e2e sessions / session tests'] = `
|
||||
✓ clears only secure context data - 2/2
|
||||
|
||||
|
||||
40 passing
|
||||
35 passing
|
||||
1 pending
|
||||
|
||||
|
||||
(Results)
|
||||
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Tests: 41 │
|
||||
│ Passing: 40 │
|
||||
│ Tests: 36 │
|
||||
│ Passing: 35 │
|
||||
│ Failing: 0 │
|
||||
│ Pending: 1 │
|
||||
│ Skipped: 0 │
|
||||
@@ -126,9 +119,9 @@ exports['e2e sessions / session tests'] = `
|
||||
|
||||
Spec Tests Passing Failing Pending Skipped
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ ✔ session.cy.js XX:XX 41 40 - 1 - │
|
||||
│ ✔ session.cy.js XX:XX 36 35 - 1 - │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
✔ All specs passed! XX:XX 41 40 - 1 -
|
||||
✔ All specs passed! XX:XX 36 35 - 1 -
|
||||
|
||||
|
||||
`
|
||||
|
||||
@@ -38,102 +38,6 @@ const sessionUser = (name = 'user0', cacheAcrossSpecs = false) => {
|
||||
})
|
||||
}
|
||||
|
||||
describe('cross origin automations', function () {
|
||||
it('get storage', () => {
|
||||
cy.visit('https://localhost:4466/cross_origin_iframe/foo')
|
||||
.then(() => {
|
||||
localStorage.key1 = 'val1'
|
||||
})
|
||||
|
||||
.then(() => Cypress.session.getStorage({ origin: ['https://127.0.0.1:44665', 'current_origin'] }))
|
||||
.then((result) => {
|
||||
expect(result).deep.eq({
|
||||
localStorage: [
|
||||
{ origin: 'https://localhost:4466', value: { key1: 'val1' } },
|
||||
{ origin: 'https://127.0.0.1:44665', value: { name: 'foo' } },
|
||||
],
|
||||
sessionStorage: [],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('get storage w/ sessionStorage', () => {
|
||||
cy.visit('https://localhost:4466/cross_origin_iframe/foo')
|
||||
.then(() => {
|
||||
localStorage.key1 = 'val'
|
||||
sessionStorage.key1 = 'val'
|
||||
})
|
||||
|
||||
.then(() => Cypress.session.getStorage({ origin: ['https://127.0.0.1:44665', 'current_origin'] }))
|
||||
.then((result) => {
|
||||
expect(result).deep.eq({
|
||||
localStorage: [
|
||||
{ origin: 'https://localhost:4466', value: { key1: 'val' } },
|
||||
{ origin: 'https://127.0.0.1:44665', value: { name: 'foo' } },
|
||||
],
|
||||
sessionStorage: [
|
||||
{ origin: 'https://localhost:4466', value: { key1: 'val' } },
|
||||
],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('set storage', () => {
|
||||
cy.visit('https://localhost:4466/cross_origin_iframe/foo')
|
||||
.then(() => {
|
||||
localStorage.key1 = 'val1'
|
||||
})
|
||||
.then(() => Cypress.session.setStorage({ localStorage: [{ value: { key2: 'val2' } }] }))
|
||||
.then(() => {
|
||||
expect(window.localStorage.key2).eq('val2')
|
||||
})
|
||||
.then(() => {
|
||||
return Cypress.session.setStorage({
|
||||
localStorage: [
|
||||
// set localStorage on different origin
|
||||
{ origin: 'https://127.0.0.1:44665', value: { key2: 'val' }, clear: true },
|
||||
// set localStorage on current origin
|
||||
{ value: { key3: 'val' }, clear: true },
|
||||
],
|
||||
})
|
||||
})
|
||||
.then(() => Cypress.session.getStorage({ origin: ['current_url', 'https://127.0.0.1:44665'] }))
|
||||
.then((result) => {
|
||||
expect(result).deep.eq({
|
||||
localStorage: [
|
||||
{ origin: 'https://localhost:4466', value: { key3: 'val' } },
|
||||
{ origin: 'https://127.0.0.1:44665', value: { key2: 'val' } },
|
||||
],
|
||||
sessionStorage: [],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('get localStorage from all origins', () => {
|
||||
cy.visit('https://localhost:4466/cross_origin_iframe/foo')
|
||||
.then(() => {
|
||||
localStorage.key1 = 'val1'
|
||||
})
|
||||
|
||||
.then(() => Cypress.session.getStorage({ origin: '*' }))
|
||||
.then((result) => {
|
||||
expect(result.localStorage).deep.eq([{ origin: 'https://localhost:4466', value: { key1: 'val1' } }, { origin: 'https://127.0.0.1:44665', value: { name: 'foo' } }])
|
||||
})
|
||||
})
|
||||
|
||||
it('only gets localStorage from origins visited in test', () => {
|
||||
cy.visit('https://localhost:4466/form')
|
||||
.then(() => {
|
||||
localStorage.key1 = 'val1'
|
||||
})
|
||||
|
||||
.then(() => Cypress.session.getStorage({ origin: '*' }))
|
||||
.then((result) => {
|
||||
expect(result.localStorage).deep.eq([{ origin: 'https://localhost:4466', value: { key1: 'val1' } }])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('with a blank session', () => {
|
||||
beforeEach(() => {
|
||||
cy.session('sess1',
|
||||
|
||||
Reference in New Issue
Block a user