Skip to content

Commit

Permalink
chore: update session api types & exposed global helpers (#24980)
Browse files Browse the repository at this point in the history
Co-authored-by: Matt Schile <[email protected]>
Co-authored-by: Chris Breiding <[email protected]>
  • Loading branch information
3 people authored Dec 6, 2022
1 parent 166bf8e commit 797c8f8
Show file tree
Hide file tree
Showing 13 changed files with 157 additions and 180 deletions.
72 changes: 52 additions & 20 deletions cli/types/cypress.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -794,25 +794,6 @@ declare namespace Cypress {
onSpecWindow: (window: Window, specList: string[] | Array<() => Promise<void>>) => void
}

interface SessionOptions {
/**
* Whether or not to persist the session across all specs in the run.
* @default {false}
*/
cacheAcrossSpecs?: boolean
/**
* Function to run immediately after the session is created and `setup` function runs or
* after a session is restored and the page is cleared. If this returns `false`, throws an
* exception, returns a Promise which resolves to `false` or rejects or contains any failing
* Cypress command, the session is considered invalid.
*
* If validation fails immediately after `setup`, the test will fail.
* If validation fails after restoring a session, `setup` will re-run.
* @default {false}
*/
validate?: () => Promise<false | void> | void
}

type CanReturnChainable = void | Chainable | Promise<unknown>
type ThenReturn<S, R> =
R extends void ? Chainable<S> :
Expand Down Expand Up @@ -3423,8 +3404,59 @@ declare namespace Cypress {
}

interface Session {
// Clear all saved sessions and re-run the current spec file.
/**
* Clear all sessions saved on the backend, including cached global sessions.
*/
clearAllSavedSessions: () => Promise<void>
/**
* Clear all storage and cookie data across all origins associated with the current session.
*/
clearCurrentSessionData: () => Promise<void>
/**
* Get all storage and cookie data across all origins associated with the current session.
*/
getCurrentSessionData: () => Promise<SessionData>
/**
* Get all storage and cookie data saved on the backend associated with the provided session id.
*/
getSession: (id: string) => Promise<ServerSessionData>
}

type ActiveSessions = Record<string, SessionData>

interface SessionData {
id: string
hydrated: boolean
cacheAcrossSpecs: SessionOptions['cacheAcrossSpecs']
cookies?: Cookie[] | null
localStorage?: OriginStorage[] | null
sessionStorage?: OriginStorage[] | null
setup: () => void
validate?: SessionOptions['validate']
}

interface ServerSessionData extends Omit<SessionData, 'setup' |'validate'> {
setup: string
validate?: string
}

interface SessionOptions {
/**
* Whether or not to persist the session across all specs in the run.
* @default {false}
*/
cacheAcrossSpecs?: boolean
/**
* Function to run immediately after the session is created and `setup` function runs or
* after a session is restored and the page is cleared. If this returns `false`, throws an
* exception, returns a Promise which resolves to `false` or rejects or contains any failing
* Cypress command, the session is considered invalid.
*
* If validation fails immediately after `setup`, the test will fail.
* If validation fails after restoring a session, `setup` will re-run.
* @default {false}
*/
validate?: () => Promise<false | void> | void
}

type SameSiteStatus = 'no_restriction' | 'strict' | 'lax'
Expand Down
6 changes: 3 additions & 3 deletions packages/app/cypress/e2e/runner/sessions.ui.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ describe('runner/cypress sessions.ui.spec', {
before(() => {
cy.then(async () => {
await Cypress.action('cy:url:changed', '')
await Cypress.action('cy:visit:blank', { type: 'on' })
await Cypress.action('cy:visit:blank', { testIsolation: false })
})
.then(() => {
loadSpec({
Expand Down Expand Up @@ -550,7 +550,7 @@ describe('runner/cypress sessions.ui.spec', {
before(() => {
cy.then(async () => {
await Cypress.action('cy:url:changed', '')
await Cypress.action('cy:visit:blank', { type: 'on' })
await Cypress.action('cy:visit:blank', { testIsolation: false })
})
.then(() => {
loadSpec({
Expand Down Expand Up @@ -630,7 +630,7 @@ describe('runner/cypress sessions.ui.spec', {
before(() => {
cy.then(async () => {
await Cypress.action('cy:url:changed', '')
await Cypress.action('cy:visit:blank', { type: 'on' })
await Cypress.action('cy:visit:blank', { testIsolation: false })
})
.then(() => {
loadSpec({
Expand Down
79 changes: 38 additions & 41 deletions packages/driver/cypress/e2e/commands/sessions/manager.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('src/cy/commands/sessions/manager.ts', () => {
it('adds session when none were previously added', () => {
const cySpy = cy.spy(cy, 'state').withArgs('activeSessions')

const activeSession: Cypress.Commands.Session.ActiveSessions = {
const activeSession: Cypress.ActiveSessions = {
'session_1': {
id: 'session_1',
setup: () => {},
Expand All @@ -42,7 +42,7 @@ describe('src/cy/commands/sessions/manager.ts', () => {
})

it('adds session when other sessions were previously added', () => {
const existingSessions: Cypress.Commands.Session.ActiveSessions = {
const existingSessions: Cypress.ActiveSessions = {
'session_1': {
id: 'session_1',
setup: () => {},
Expand All @@ -59,7 +59,7 @@ describe('src/cy/commands/sessions/manager.ts', () => {

const cySpy = cy.stub(cy, 'state').callThrough().withArgs('activeSessions').returns(existingSessions)

const activeSession: Cypress.Commands.Session.ActiveSessions = {
const activeSession: Cypress.ActiveSessions = {
'session_3': {
id: 'session_3',
setup: () => {},
Expand Down Expand Up @@ -94,7 +94,7 @@ describe('src/cy/commands/sessions/manager.ts', () => {
})

it('returns session when found', () => {
const activeSessions: Cypress.Commands.Session.ActiveSessions = {
const activeSessions: Cypress.ActiveSessions = {
'session_1': {
id: 'session_1',
setup: () => {},
Expand Down Expand Up @@ -135,7 +135,7 @@ describe('src/cy/commands/sessions/manager.ts', () => {
})

it('updates the existing active sessions to "hydrated: false"', () => {
const existingSessions: Cypress.Commands.Session.ActiveSessions = {
const existingSessions: Cypress.ActiveSessions = {
'session_1': {
id: 'session_1',
setup: () => {},
Expand Down Expand Up @@ -166,24 +166,41 @@ describe('src/cy/commands/sessions/manager.ts', () => {
})
})

describe('.sessions', () => {
it('sessions.defineSession()', () => {
const sessionsManager = new SessionsManager(CypressInstance, cy)
const setup = cy.stub()
const sess = sessionsManager.sessions.defineSession({ id: '1', setup })

expect(sess).to.deep.eq({
id: '1',
setup,
validate: undefined,
cookies: null,
cacheAcrossSpecs: false,
localStorage: null,
sessionStorage: null,
hydrated: false,
})
it('.defineSession()', () => {
const sessionsManager = new SessionsManager(CypressInstance, cy)
const setup = cy.stub()
const sess = sessionsManager.defineSession({ id: '1', setup })

expect(sess).to.deep.eq({
id: '1',
setup,
validate: undefined,
cookies: null,
cacheAcrossSpecs: false,
localStorage: null,
sessionStorage: null,
hydrated: false,
})
})

it('.saveSessionData()', async () => {
const cypressSpy = cy.stub(CypressInstance, 'backend').callThrough().withArgs('save:session').resolves(null)

const sessionsManager = new SessionsManager(CypressInstance, cy)
const sessionsSpy = cy.stub(sessionsManager, 'setActiveSession')

const setup = cy.stub()
const sess = { id: '1', setup }

await sessionsManager.saveSessionData(sess)

expect(sessionsSpy).to.be.calledOnce
expect(sessionsSpy.getCall(0).args[0]).to.deep.eq({ 1: sess })

expect(cypressSpy).to.be.calledOnceWith('save:session')
})

describe('.sessions', () => {
it('sessions.clearAllSavedSessions()', async () => {
const cypressSpy = cy.stub(CypressInstance, 'backend').callThrough().withArgs('clear:sessions', true).resolves(null)

Expand Down Expand Up @@ -260,26 +277,6 @@ describe('src/cy/commands/sessions/manager.ts', () => {
})
})

it('sessions.saveSessionData', async () => {
const cypressSpy = cy.stub(CypressInstance, 'backend').callThrough().withArgs('save:session').resolves(null)

const sessionsManager = new SessionsManager(CypressInstance, cy)
const sessionsSpy = cy.stub(sessionsManager, 'setActiveSession')

const setup = cy.stub()
const sess = { id: '1', setup }

await sessionsManager.sessions.saveSessionData(sess)

expect(sessionsSpy).to.be.calledOnce
expect(sessionsSpy.getCall(0).args[0]).to.deep.eq({ 1: sess })

expect(cypressSpy).to.be.calledOnceWith('save:session')
})

// TODO:
describe('sessions.setSessionData', () => {})

it('sessions.getCookies()', async () => {
const cookies = [{ id: 'cookie' }]
const cypressSpy = cy.stub(CypressInstance, 'automation').withArgs('get:cookies').resolves(cookies)
Expand Down
1 change: 1 addition & 0 deletions packages/driver/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@babel/code-frame": "7.8.3",
"@cypress/sinon-chai": "2.9.1",
"@cypress/unique-selector": "0.4.4",
"@cypress/webpack-dev-server": "0.0.0-development",
"@cypress/webpack-preprocessor": "0.0.0-development",
"@cypress/what-is-circular": "1.0.1",
"@packages/config": "0.0.0-development",
Expand Down
16 changes: 6 additions & 10 deletions packages/driver/src/cy/commands/sessions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ import {
statusMap,
} from './utils'

import type { ServerSessionData } from '@packages/types'

type SessionData = Cypress.Commands.Session.SessionData

/**
* Session data should be cleared with spec browser launch.
*
Expand All @@ -30,7 +26,7 @@ export default function (Commands, Cypress, cy) {

Cypress.on('run:start', () => {
// @ts-ignore
Object.values(Cypress.state('activeSessions') || {}).forEach((sessionData: ServerSessionData) => {
Object.values(Cypress.state('activeSessions') || {}).forEach((sessionData: Cypress.ServerSessionData) => {
if (sessionData.cacheAcrossSpecs) {
sessionsManager.registeredSessions.set(sessionData.id, true)
}
Expand Down Expand Up @@ -89,7 +85,7 @@ export default function (Commands, Cypress, cy) {
})
}

let session: SessionData = sessionsManager.getActiveSession(id)
let session: Cypress.SessionData = sessionsManager.getActiveSession(id)
const isRegisteredSessionForSpec = sessionsManager.registeredSessions.has(id)

if (session) {
Expand Down Expand Up @@ -120,7 +116,7 @@ export default function (Commands, Cypress, cy) {
$errUtils.throwErrByPath('sessions.session.duplicateId', { args: { id } })
}

session = sessions.defineSession({
session = sessionsManager.defineSession({
id,
setup,
validate: options.validate,
Expand Down Expand Up @@ -215,7 +211,7 @@ export default function (Commands, Cypress, cy) {

_log.set({ consoleProps: () => getConsoleProps(testSession) })

return sessions.setSessionData(testSession)
return sessionsManager.setSessionData(testSession)
}

function validateSession (existingSession, step: keyof typeof SESSION_STEPS) {
Expand Down Expand Up @@ -428,7 +424,7 @@ export default function (Commands, Cypress, cy) {
}

sessionsManager.registeredSessions.set(existingSession.id, true)
await sessions.saveSessionData(existingSession)
await sessionsManager.saveSessionData(existingSession)

return statusMap.complete(step)
})
Expand All @@ -440,7 +436,7 @@ export default function (Commands, Cypress, cy) {
* 2. validate session
* 3. if validation fails, catch error and recreate session
*/
const restoreSessionWorkflow = (existingSession: SessionData) => {
const restoreSessionWorkflow = (existingSession: Cypress.SessionData) => {
return cy.then(async () => {
setSessionLogStatus(statusMap.inProgress(SESSION_STEPS.restore))
await navigateAboutBlank()
Expand Down
Loading

5 comments on commit 797c8f8

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 797c8f8 Dec 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.0.0/linux-x64/develop-797c8f8d7737ff8c5d76107faf505dc980ff953f/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 797c8f8 Dec 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux arm64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.0.0/linux-arm64/develop-797c8f8d7737ff8c5d76107faf505dc980ff953f/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 797c8f8 Dec 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.0.0/darwin-x64/develop-797c8f8d7737ff8c5d76107faf505dc980ff953f/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 797c8f8 Dec 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the win32 x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.0.0/win32-x64/develop-797c8f8d7737ff8c5d76107faf505dc980ff953f/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 797c8f8 Dec 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin arm64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.0.0/darwin-arm64/develop-797c8f8d7737ff8c5d76107faf505dc980ff953f/cypress.tgz

Please sign in to comment.