mirror of
https://github.com/cypress-io/cypress.git
synced 2026-02-09 08:40:32 -06:00
chore(sessions): break out session utils and write some unit tests (#21048)
Co-authored-by: Matt Schile <mschile@gmail.com> Co-authored-by: Bill Glesias <bglesias@gmail.com>
This commit is contained in:
@@ -0,0 +1,244 @@
|
||||
const {
|
||||
getSessionDetails,
|
||||
getConsoleProps,
|
||||
navigateAboutBlank,
|
||||
} = require('@packages/driver/src/cy/commands/sessions/utils')
|
||||
|
||||
describe('src/cy/commands/sessions/utils.ts', () => {
|
||||
describe('.getSessionDetails', () => {
|
||||
it('for one domain with neither cookies or local storage set', () => {
|
||||
const sessionState = {
|
||||
id: 'session1',
|
||||
}
|
||||
|
||||
const details = getSessionDetails(sessionState)
|
||||
|
||||
expect(details.id).to.eq('session1')
|
||||
expect(Object.keys(details.data)).to.have.length(0)
|
||||
})
|
||||
|
||||
it('for one domain with only cookies set', () => {
|
||||
const sessionState = {
|
||||
id: 'session1',
|
||||
cookies: [
|
||||
{ name: 'foo', value: 'f', path: '/', domain: 'localhost', secure: true, httpOnly: true, expiry: 123 },
|
||||
],
|
||||
}
|
||||
|
||||
const details = getSessionDetails(sessionState)
|
||||
|
||||
expect(details.id).to.eq('session1')
|
||||
expect(Object.keys(details.data)).to.have.length(1)
|
||||
expect(details.data).to.have.property('localhost')
|
||||
expect(details.data.localhost).to.deep.eq({
|
||||
cookies: 1,
|
||||
})
|
||||
})
|
||||
|
||||
it('for one domain with only local storage set', () => {
|
||||
const sessionState = {
|
||||
id: 'session1',
|
||||
localStorage: [
|
||||
{ origin: 'localhost', value: { 'stor-foo': 's-f' } },
|
||||
],
|
||||
}
|
||||
|
||||
const details = getSessionDetails(sessionState)
|
||||
|
||||
expect(details.id).to.eq('session1')
|
||||
expect(Object.keys(details.data)).to.have.length(1)
|
||||
expect(details.data).to.have.property('localhost')
|
||||
expect(details.data.localhost).to.deep.eq({
|
||||
localStorage: 1,
|
||||
})
|
||||
})
|
||||
|
||||
it('for one domain with both cookies and localStorage', () => {
|
||||
const sessionState = {
|
||||
id: 'session1',
|
||||
cookies: [
|
||||
{ name: 'foo', value: 'f', path: '/', domain: 'localhost', secure: true, httpOnly: true, expiry: 123 },
|
||||
],
|
||||
localStorage: [
|
||||
{ origin: 'localhost', value: { 'stor-foo': 's-f' } },
|
||||
],
|
||||
}
|
||||
|
||||
const details = getSessionDetails(sessionState)
|
||||
|
||||
expect(details.id).to.eq('session1')
|
||||
expect(Object.keys(details.data)).to.have.length(1)
|
||||
expect(details.data).to.have.property('localhost')
|
||||
expect(details.data.localhost).to.deep.eq({
|
||||
cookies: 1,
|
||||
localStorage: 1,
|
||||
})
|
||||
})
|
||||
|
||||
it('for multiple domains', () => {
|
||||
const sessionState = {
|
||||
id: 'session1',
|
||||
cookies: [
|
||||
{ name: 'foo', value: 'f', path: '/', domain: 'localhost', secure: true, httpOnly: true, expiry: 123 },
|
||||
{ name: 'bar', value: 'b', path: '/', domain: 'localhost', secure: false, httpOnly: false, expiry: 456 },
|
||||
],
|
||||
localStorage: [
|
||||
{ origin: 'localhost', value: { 'stor-foo': 's-f' } },
|
||||
{ origin: 'http://example.com', value: { 'random': 'hi' } },
|
||||
],
|
||||
}
|
||||
|
||||
const details = getSessionDetails(sessionState)
|
||||
|
||||
expect(details.id).to.eq('session1')
|
||||
expect(Object.keys(details.data)).to.have.length(2)
|
||||
expect(details.data).to.have.property('localhost')
|
||||
expect(details.data.localhost).to.deep.eq({
|
||||
cookies: 2,
|
||||
localStorage: 1,
|
||||
})
|
||||
|
||||
expect(details.data).to.have.property('example.com')
|
||||
expect(details.data['example.com']).to.deep.eq({
|
||||
localStorage: 1,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.getConsoleProps', () => {
|
||||
it('for one domain with neither cookies or localStorage set', () => {
|
||||
const sessionState = {
|
||||
id: 'session1',
|
||||
}
|
||||
|
||||
const consoleProps = getConsoleProps(sessionState)
|
||||
|
||||
expect(consoleProps.id).to.eq('session1')
|
||||
expect(consoleProps.table).to.have.length(0)
|
||||
})
|
||||
|
||||
it('for one domain with only cookies set', () => {
|
||||
const sessionState = {
|
||||
id: 'session1',
|
||||
cookies: [
|
||||
{ name: 'foo', value: 'f', path: '/', domain: 'localhost', secure: true, httpOnly: true, expiry: 123 },
|
||||
],
|
||||
}
|
||||
|
||||
const consoleProps = getConsoleProps(sessionState)
|
||||
|
||||
expect(consoleProps.id).to.eq('session1')
|
||||
expect(consoleProps.table).to.have.length(1)
|
||||
const cookiesTable = consoleProps.table[0]()
|
||||
|
||||
expect(cookiesTable.name).to.contain('Cookies - localhost (1)')
|
||||
expect(cookiesTable.data).to.deep.eq(sessionState.cookies)
|
||||
})
|
||||
|
||||
it('for one domain with only localStorage set', () => {
|
||||
const sessionState = {
|
||||
id: 'session1',
|
||||
localStorage: [
|
||||
{ origin: 'localhost', value: { 'stor-foo': 's-f' } },
|
||||
],
|
||||
}
|
||||
const consoleProps = getConsoleProps(sessionState)
|
||||
|
||||
expect(consoleProps.id).to.eq('session1')
|
||||
expect(consoleProps.table).to.have.length(1)
|
||||
const localStorageTable = consoleProps.table[0]()
|
||||
|
||||
expect(localStorageTable.name).to.contain('Storage - localhost (1)')
|
||||
expect(localStorageTable.data).to.have.length(1)
|
||||
expect(localStorageTable.data).to.deep.eq([{ key: 'stor-foo', value: 's-f' }])
|
||||
})
|
||||
|
||||
it('for one domain with both cookies and localStorage set', () => {
|
||||
const sessionState = {
|
||||
id: 'session1',
|
||||
cookies: [
|
||||
{ name: 'foo', value: 'f', path: '/', domain: 'localhost', secure: true, httpOnly: true, expiry: 123 },
|
||||
],
|
||||
localStorage: [
|
||||
{ origin: 'localhost', value: { 'stor-foo': 's-f' } },
|
||||
],
|
||||
}
|
||||
|
||||
const consoleProps = getConsoleProps(sessionState)
|
||||
|
||||
expect(consoleProps.id).to.eq('session1')
|
||||
expect(consoleProps.table).to.have.length(2)
|
||||
let table = consoleProps.table[0]()
|
||||
|
||||
expect(table.name).to.contain('Cookies - localhost (1)')
|
||||
expect(table.data).to.have.length(1)
|
||||
expect(table.data).to.deep.eq(sessionState.cookies)
|
||||
|
||||
table = consoleProps.table[1]()
|
||||
expect(table.name).to.contain('Storage - localhost (1)')
|
||||
expect(table.data).to.have.length(1)
|
||||
expect(table.data).to.deep.eq([{ key: 'stor-foo', value: 's-f' }])
|
||||
})
|
||||
|
||||
it('for multiple domains', () => {
|
||||
const sessionState = {
|
||||
id: 'session1',
|
||||
cookies: [
|
||||
{ name: 'foo', value: 'f', path: '/', domain: 'localhost', secure: true, httpOnly: true, expiry: 123 },
|
||||
{ name: 'bar', value: 'b', path: '/', domain: 'localhost', secure: false, httpOnly: false, expiry: 456 },
|
||||
],
|
||||
localStorage: [
|
||||
{ origin: 'localhost', value: { 'stor-foo': 's-f' } },
|
||||
{ origin: 'http://example.com', value: { 'random': 'hi' } },
|
||||
],
|
||||
}
|
||||
|
||||
const consoleProps = getConsoleProps(sessionState)
|
||||
|
||||
expect(consoleProps.id).to.eq('session1')
|
||||
expect(consoleProps.table).to.have.length(3)
|
||||
let table = consoleProps.table[0]()
|
||||
|
||||
expect(table.name).to.contain('Cookies - localhost (2)')
|
||||
expect(table.data).to.have.length(2)
|
||||
expect(table.data).to.deep.eq(sessionState.cookies)
|
||||
|
||||
table = consoleProps.table[1]()
|
||||
expect(table.name).to.contain('Storage - localhost (1)')
|
||||
expect(table.data).to.have.length(1)
|
||||
expect(table.data).to.deep.eq([{ key: 'stor-foo', value: 's-f' }])
|
||||
|
||||
table = consoleProps.table[2]()
|
||||
expect(table.name).to.contain('Storage - example.com (1)')
|
||||
expect(table.data).to.have.length(1)
|
||||
expect(table.data).to.deep.eq([{ key: 'random', value: 'hi' }])
|
||||
})
|
||||
})
|
||||
|
||||
describe('.navigateAboutBlank', () => {
|
||||
it('triggers session blank page visit', () => {
|
||||
const stub = cy.stub(Cypress, 'action').log(false)
|
||||
.callThrough()
|
||||
.withArgs('cy:visit:blank')
|
||||
|
||||
cy.then(() => {
|
||||
navigateAboutBlank()
|
||||
navigateAboutBlank(true)
|
||||
expect(stub).to.have.been.calledTwice
|
||||
expect(stub.args[0]).to.deep.eq(['cy:visit:blank', { type: 'session' }])
|
||||
expect(stub.args[1]).to.deep.eq(['cy:visit:blank', { type: 'session' }])
|
||||
})
|
||||
})
|
||||
|
||||
it('triggers session-lifecycle blank page visit', () => {
|
||||
const stub = cy.stub(Cypress, 'action').log(false)
|
||||
.callThrough()
|
||||
.withArgs('cy:visit:blank')
|
||||
|
||||
cy.then(() => {
|
||||
navigateAboutBlank(false)
|
||||
expect(stub).to.have.been.calledWith('cy:visit:blank', { type: 'session-lifecycle' })
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,10 +1,16 @@
|
||||
import _ from 'lodash'
|
||||
import $ from 'jquery'
|
||||
import { $Location } from '../../cypress/location'
|
||||
import $errUtils from '../../cypress/error_utils'
|
||||
import { $Location } from '../../../cypress/location'
|
||||
import $errUtils from '../../../cypress/error_utils'
|
||||
import stringifyStable from 'json-stable-stringify'
|
||||
import $stackUtils from '../../cypress/stack_utils'
|
||||
import Bluebird from 'bluebird'
|
||||
import $stackUtils from '../../../cypress/stack_utils'
|
||||
import {
|
||||
getSessionDetails,
|
||||
getCurrentOriginStorage,
|
||||
setPostMessageLocalStorage,
|
||||
getConsoleProps,
|
||||
getPostMessageLocalStorage,
|
||||
navigateAboutBlank,
|
||||
} from './utils'
|
||||
const currentTestRegisteredSessions = new Map()
|
||||
|
||||
type ActiveSessions = Cypress.Commands.Session.ActiveSessions
|
||||
@@ -18,193 +24,6 @@ type SessionData = Cypress.Commands.Session.SessionData
|
||||
* therefore session data should be cleared with spec browser launch
|
||||
*/
|
||||
|
||||
const getSessionDetails = (sessState: SessionData) => {
|
||||
return {
|
||||
id: sessState.id,
|
||||
data: _.merge(
|
||||
_.mapValues(_.groupBy(sessState.cookies, 'domain'), (v) => ({ cookies: v.length })),
|
||||
..._.map(sessState.localStorage, (v) => ({ [$Location.create(v.origin).hostname]: { localStorage: Object.keys(v.value).length } })),
|
||||
) }
|
||||
}
|
||||
|
||||
const getSessionDetailsForTable = (sessState: SessionData) => {
|
||||
return _.merge(
|
||||
_.mapValues(_.groupBy(sessState.cookies, 'domain'), (v) => ({ cookies: v })),
|
||||
..._.map(sessState.localStorage, (v) => ({ [$Location.create(v.origin).hostname]: { localStorage: v } })),
|
||||
)
|
||||
}
|
||||
|
||||
const isSecureContext = (url: string) => url.startsWith('https:')
|
||||
|
||||
const getCurrentOriginStorage = () => {
|
||||
// localStorage.length property is not always accurate, we must stringify to check for entries
|
||||
// for ex) try setting localStorage.key = 'val' and reading localStorage.length, may be 0.
|
||||
const _localStorageStr = JSON.stringify(window.localStorage)
|
||||
const _localStorage = _localStorageStr.length > 2 && JSON.parse(_localStorageStr)
|
||||
const _sessionStorageStr = JSON.stringify(window.sessionStorage)
|
||||
const _sessionStorage = _sessionStorageStr.length > 2 && JSON.parse(JSON.stringify(window.sessionStorage))
|
||||
|
||||
const value = {} as any
|
||||
|
||||
if (_localStorage) {
|
||||
value.localStorage = _localStorage
|
||||
}
|
||||
|
||||
if (_sessionStorage) {
|
||||
value.sessionStorage = _sessionStorage
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
const setPostMessageLocalStorage = async (specWindow, originOptions) => {
|
||||
const origins = originOptions.map((v) => v.origin) as string[]
|
||||
|
||||
const iframes: JQuery<HTMLElement>[] = []
|
||||
|
||||
const $iframeContainer = $(`<div style="display:none"></div>`).appendTo($('body', specWindow.document))
|
||||
|
||||
// if we're on an https domain, there is no way for the secure context to access insecure origins from iframes
|
||||
// since there is no way for the app to access localStorage on insecure contexts, we don't have to clear any localStorage on http domains.
|
||||
if (isSecureContext(specWindow.location.href)) {
|
||||
_.remove(origins, (v) => !isSecureContext(v))
|
||||
}
|
||||
|
||||
if (!origins.length) return []
|
||||
|
||||
_.each(origins, (u) => {
|
||||
const $iframe = $(`<iframe src="${`${u}/__cypress/automation/setLocalStorage?${u}`}"></iframe>`)
|
||||
|
||||
$iframe.appendTo($iframeContainer)
|
||||
iframes.push($iframe)
|
||||
})
|
||||
|
||||
let onPostMessage
|
||||
|
||||
const successOrigins = [] as string[]
|
||||
|
||||
return new Bluebird((resolve) => {
|
||||
onPostMessage = (event) => {
|
||||
const data = event.data
|
||||
|
||||
if (data.type === 'set:storage:load') {
|
||||
if (!event.source) {
|
||||
throw new Error('failed to get localStorage')
|
||||
}
|
||||
|
||||
const opts = _.find(originOptions, { origin: event.origin })!
|
||||
|
||||
event.source.postMessage({ type: 'set:storage:data', data: opts }, '*')
|
||||
} else if (data.type === 'set:storage:complete') {
|
||||
successOrigins.push(event.origin)
|
||||
if (successOrigins.length === origins.length) {
|
||||
resolve()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
specWindow.addEventListener('message', onPostMessage)
|
||||
})
|
||||
// timeout just in case something goes wrong and the iframe never loads in
|
||||
.timeout(2000)
|
||||
.finally(() => {
|
||||
specWindow.removeEventListener('message', onPostMessage)
|
||||
$iframeContainer.remove()
|
||||
})
|
||||
.catch(() => {
|
||||
Cypress.log({
|
||||
name: 'warning',
|
||||
message: `failed to access session localStorage data on origin(s): ${_.xor(origins, successOrigins).join(', ')}`,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const getConsoleProps = (sessState: SessionData) => {
|
||||
const sessionDetails = getSessionDetailsForTable(sessState)
|
||||
|
||||
const tables = _.flatMap(sessionDetails, (val, domain) => {
|
||||
const cookiesTable = () => {
|
||||
return {
|
||||
name: `🍪 Cookies - ${domain} (${val.cookies.length})`,
|
||||
data: val.cookies,
|
||||
}
|
||||
}
|
||||
|
||||
const localStorageTable = () => {
|
||||
return {
|
||||
name: `📁 Storage - ${domain} (${_.keys(val.localStorage.value).length})`,
|
||||
data: _.map(val.localStorage.value, (value, key) => {
|
||||
return {
|
||||
key,
|
||||
value,
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
val.cookies && cookiesTable,
|
||||
val.localStorage && localStorageTable,
|
||||
]
|
||||
})
|
||||
|
||||
return {
|
||||
id: sessState.id,
|
||||
table: _.compact(tables),
|
||||
}
|
||||
}
|
||||
|
||||
const getPostMessageLocalStorage = (specWindow, origins): Promise<any[]> => {
|
||||
const results = [] as any[]
|
||||
const iframes: JQuery<HTMLElement>[] = []
|
||||
let onPostMessage
|
||||
const successOrigins = [] as string[]
|
||||
|
||||
const $iframeContainer = $(`<div style="display:none"></div>`).appendTo($('body', specWindow.document))
|
||||
|
||||
_.each(origins, (u) => {
|
||||
const $iframe = $(`<iframe src="${`${u}/__cypress/automation/getLocalStorage`}"></iframe>`)
|
||||
|
||||
$iframe.appendTo($iframeContainer)
|
||||
iframes.push($iframe)
|
||||
})
|
||||
|
||||
return new Bluebird((resolve) => {
|
||||
// when the cross-domain iframe for each domain is loaded
|
||||
// we can only communicate through postmessage
|
||||
onPostMessage = ((event) => {
|
||||
const data = event.data
|
||||
|
||||
if (data.type !== 'localStorage') return
|
||||
|
||||
const value = data.value
|
||||
|
||||
results.push([event.origin, value])
|
||||
|
||||
successOrigins.push(event.origin)
|
||||
if (successOrigins.length === origins.length) {
|
||||
resolve(results)
|
||||
}
|
||||
})
|
||||
|
||||
specWindow.addEventListener('message', onPostMessage)
|
||||
})
|
||||
// timeout just in case something goes wrong and the iframe never loads in
|
||||
.timeout(2000)
|
||||
.finally(() => {
|
||||
specWindow.removeEventListener('message', onPostMessage)
|
||||
$iframeContainer.remove()
|
||||
})
|
||||
.catch((err) => {
|
||||
Cypress.log({
|
||||
name: 'warning',
|
||||
message: `failed to access session localStorage data on origin(s): ${_.xor(origins, successOrigins).join(', ')}`,
|
||||
})
|
||||
|
||||
return []
|
||||
})
|
||||
}
|
||||
|
||||
export default function (Commands, Cypress, cy) {
|
||||
const { Promise } = Cypress
|
||||
|
||||
@@ -867,9 +686,3 @@ export default function (Commands, Cypress, cy) {
|
||||
|
||||
Cypress.session = sessions
|
||||
}
|
||||
|
||||
function navigateAboutBlank (session = true) {
|
||||
Cypress.action('cy:url:changed', '')
|
||||
|
||||
return Cypress.action('cy:visit:blank', { type: session ? 'session' : 'session-lifecycle' }) as unknown as Promise<void>
|
||||
}
|
||||
208
packages/driver/src/cy/commands/sessions/utils.ts
Normal file
208
packages/driver/src/cy/commands/sessions/utils.ts
Normal file
@@ -0,0 +1,208 @@
|
||||
import _ from 'lodash'
|
||||
import $ from 'jquery'
|
||||
import { $Location } from '../../../cypress/location'
|
||||
import Bluebird from 'bluebird'
|
||||
|
||||
type SessionData = Cypress.Commands.Session.SessionData
|
||||
|
||||
const getSessionDetails = (sessState: SessionData) => {
|
||||
return {
|
||||
id: sessState.id,
|
||||
data: _.merge(
|
||||
_.mapValues(_.groupBy(sessState.cookies, 'domain'), (v) => ({ cookies: v.length })),
|
||||
..._.map(sessState.localStorage, (v) => ({ [$Location.create(v.origin).hostname]: { localStorage: Object.keys(v.value).length } })),
|
||||
) }
|
||||
}
|
||||
|
||||
const getSessionDetailsForTable = (sessState: SessionData) => {
|
||||
return _.merge(
|
||||
_.mapValues(_.groupBy(sessState.cookies, 'domain'), (v) => ({ cookies: v })),
|
||||
..._.map(sessState.localStorage, (v) => ({ [$Location.create(v.origin).hostname]: { localStorage: v } })),
|
||||
)
|
||||
}
|
||||
|
||||
const isSecureContext = (url: string) => url.startsWith('https:')
|
||||
|
||||
const getCurrentOriginStorage = () => {
|
||||
// localStorage.length property is not always accurate, we must stringify to check for entries
|
||||
// for ex) try setting localStorage.key = 'val' and reading localStorage.length, may be 0.
|
||||
const _localStorageStr = JSON.stringify(window.localStorage)
|
||||
const _localStorage = _localStorageStr.length > 2 && JSON.parse(_localStorageStr)
|
||||
const _sessionStorageStr = JSON.stringify(window.sessionStorage)
|
||||
const _sessionStorage = _sessionStorageStr.length > 2 && JSON.parse(JSON.stringify(window.sessionStorage))
|
||||
|
||||
const value = {} as any
|
||||
|
||||
if (_localStorage) {
|
||||
value.localStorage = _localStorage
|
||||
}
|
||||
|
||||
if (_sessionStorage) {
|
||||
value.sessionStorage = _sessionStorage
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
const setPostMessageLocalStorage = async (specWindow, originOptions) => {
|
||||
const origins = originOptions.map((v) => v.origin) as string[]
|
||||
|
||||
const iframes: JQuery<HTMLElement>[] = []
|
||||
|
||||
const $iframeContainer = $(`<div style="display:none"></div>`).appendTo($('body', specWindow.document))
|
||||
|
||||
// if we're on an https domain, there is no way for the secure context to access insecure origins from iframes
|
||||
// since there is no way for the app to access localStorage on insecure contexts, we don't have to clear any localStorage on http domains.
|
||||
if (isSecureContext(specWindow.location.href)) {
|
||||
_.remove(origins, (v) => !isSecureContext(v))
|
||||
}
|
||||
|
||||
if (!origins.length) return []
|
||||
|
||||
_.each(origins, (u) => {
|
||||
const $iframe = $(`<iframe src="${`${u}/__cypress/automation/setLocalStorage?${u}`}"></iframe>`)
|
||||
|
||||
$iframe.appendTo($iframeContainer)
|
||||
iframes.push($iframe)
|
||||
})
|
||||
|
||||
let onPostMessage
|
||||
|
||||
const successOrigins = [] as string[]
|
||||
|
||||
return new Bluebird((resolve) => {
|
||||
onPostMessage = (event) => {
|
||||
const data = event.data
|
||||
|
||||
if (data.type === 'set:storage:load') {
|
||||
if (!event.source) {
|
||||
throw new Error('failed to get localStorage')
|
||||
}
|
||||
|
||||
const opts = _.find(originOptions, { origin: event.origin })!
|
||||
|
||||
event.source.postMessage({ type: 'set:storage:data', data: opts }, '*')
|
||||
} else if (data.type === 'set:storage:complete') {
|
||||
successOrigins.push(event.origin)
|
||||
if (successOrigins.length === origins.length) {
|
||||
resolve()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
specWindow.addEventListener('message', onPostMessage)
|
||||
})
|
||||
// timeout just in case something goes wrong and the iframe never loads in
|
||||
.timeout(2000)
|
||||
.finally(() => {
|
||||
specWindow.removeEventListener('message', onPostMessage)
|
||||
$iframeContainer.remove()
|
||||
})
|
||||
.catch(() => {
|
||||
Cypress.log({
|
||||
name: 'warning',
|
||||
message: `failed to access session localStorage data on origin(s): ${_.xor(origins, successOrigins).join(', ')}`,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const getConsoleProps = (sessState: SessionData) => {
|
||||
const sessionDetails = getSessionDetailsForTable(sessState)
|
||||
|
||||
const tables = _.flatMap(sessionDetails, (val, domain) => {
|
||||
const cookiesTable = () => {
|
||||
return {
|
||||
name: `🍪 Cookies - ${domain} (${val.cookies.length})`,
|
||||
data: val.cookies,
|
||||
}
|
||||
}
|
||||
|
||||
const localStorageTable = () => {
|
||||
return {
|
||||
name: `📁 Storage - ${domain} (${_.keys(val.localStorage.value).length})`,
|
||||
data: _.map(val.localStorage.value, (value, key) => {
|
||||
return {
|
||||
key,
|
||||
value,
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
val.cookies && cookiesTable,
|
||||
val.localStorage && localStorageTable,
|
||||
]
|
||||
})
|
||||
|
||||
return {
|
||||
id: sessState.id,
|
||||
table: _.compact(tables),
|
||||
}
|
||||
}
|
||||
|
||||
const getPostMessageLocalStorage = (specWindow, origins): Promise<any[]> => {
|
||||
const results = [] as any[]
|
||||
const iframes: JQuery<HTMLElement>[] = []
|
||||
let onPostMessage
|
||||
const successOrigins = [] as string[]
|
||||
|
||||
const $iframeContainer = $(`<div style="display:none"></div>`).appendTo($('body', specWindow.document))
|
||||
|
||||
_.each(origins, (u) => {
|
||||
const $iframe = $(`<iframe src="${`${u}/__cypress/automation/getLocalStorage`}"></iframe>`)
|
||||
|
||||
$iframe.appendTo($iframeContainer)
|
||||
iframes.push($iframe)
|
||||
})
|
||||
|
||||
return new Bluebird((resolve) => {
|
||||
// when the cross-domain iframe for each domain is loaded
|
||||
// we can only communicate through postmessage
|
||||
onPostMessage = ((event) => {
|
||||
const data = event.data
|
||||
|
||||
if (data.type !== 'localStorage') return
|
||||
|
||||
const value = data.value
|
||||
|
||||
results.push([event.origin, value])
|
||||
|
||||
successOrigins.push(event.origin)
|
||||
if (successOrigins.length === origins.length) {
|
||||
resolve(results)
|
||||
}
|
||||
})
|
||||
|
||||
specWindow.addEventListener('message', onPostMessage)
|
||||
})
|
||||
// timeout just in case something goes wrong and the iframe never loads in
|
||||
.timeout(2000)
|
||||
.finally(() => {
|
||||
specWindow.removeEventListener('message', onPostMessage)
|
||||
$iframeContainer.remove()
|
||||
})
|
||||
.catch((err) => {
|
||||
Cypress.log({
|
||||
name: 'warning',
|
||||
message: `failed to access session localStorage data on origin(s): ${_.xor(origins, successOrigins).join(', ')}`,
|
||||
})
|
||||
|
||||
return []
|
||||
})
|
||||
}
|
||||
|
||||
function navigateAboutBlank (session: boolean = true) {
|
||||
Cypress.action('cy:url:changed', '')
|
||||
|
||||
return Cypress.action('cy:visit:blank', { type: session ? 'session' : 'session-lifecycle' }) as unknown as Promise<void>
|
||||
}
|
||||
|
||||
export {
|
||||
getSessionDetails,
|
||||
getCurrentOriginStorage,
|
||||
setPostMessageLocalStorage,
|
||||
getConsoleProps,
|
||||
getPostMessageLocalStorage,
|
||||
navigateAboutBlank,
|
||||
}
|
||||
Reference in New Issue
Block a user