From d4421e17347546ec43bc1a6d1dd8a101b4b7860c Mon Sep 17 00:00:00 2001 From: Matthew Schile Date: Tue, 27 May 2025 09:52:18 -0600 Subject: [PATCH 1/6] fix: add cy.then timeouts to cy.session --- .../driver/src/cy/commands/sessions/index.ts | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/packages/driver/src/cy/commands/sessions/index.ts b/packages/driver/src/cy/commands/sessions/index.ts index 3a72d0f98e10..7452a6e443fb 100644 --- a/packages/driver/src/cy/commands/sessions/index.ts +++ b/packages/driver/src/cy/commands/sessions/index.ts @@ -21,6 +21,8 @@ import { * - session data SHOULD be cleared between specs in run mode */ export default function (Commands, Cypress, cy) { + const COMMAND_TIMEOUT = 20000 + const sessionsManager = new SessionsManager(Cypress, cy) const sessions = sessionsManager.sessions @@ -179,7 +181,7 @@ export default function (Commands, Cypress, cy) { } finally { cy.breakSubjectLinksToCurrentChainer() } - }) + }, { timeout: COMMAND_TIMEOUT }) .then(async () => { cy.state('onQueueFailed', null) const data = await sessions.getCurrentSessionData() @@ -200,7 +202,7 @@ export default function (Commands, Cypress, cy) { }) return - }) + }, { timeout: COMMAND_TIMEOUT }) }) } @@ -422,10 +424,10 @@ export default function (Commands, Cypress, cy) { }) return isValidSession - }) + }, { timeout: COMMAND_TIMEOUT }) return _commandToRunAfterValidation - }) + }, { timeout: COMMAND_TIMEOUT }) }) } /** @@ -441,8 +443,8 @@ export default function (Commands, Cypress, cy) { await sessions.clearCurrentSessionData() return cy.whenStable(() => createSession(existingSession, step)) - }) - .then(() => validateSession(existingSession, step)) + }, { timeout: COMMAND_TIMEOUT }) + .then(() => validateSession(existingSession, step), { timeout: COMMAND_TIMEOUT }) .then(async (isValidSession: boolean) => { if (!isValidSession) { return 'failed' @@ -452,7 +454,7 @@ export default function (Commands, Cypress, cy) { await sessionsManager.saveSessionData(existingSession) return statusMap.complete(step) - }) + }, { timeout: COMMAND_TIMEOUT }) } /** @@ -468,15 +470,15 @@ export default function (Commands, Cypress, cy) { await sessions.clearCurrentSessionData() return restoreSession(existingSession) - }) - .then(() => validateSession(existingSession, SESSION_STEPS.restore)) + }, { timeout: COMMAND_TIMEOUT }) + .then(() => validateSession(existingSession, SESSION_STEPS.restore), { timeout: COMMAND_TIMEOUT }) .then((isValidSession: boolean) => { if (!isValidSession) { return createSessionWorkflow(existingSession, SESSION_STEPS.recreate) } return statusMap.complete(SESSION_STEPS.restore) - }) + }, { timeout: COMMAND_TIMEOUT }) } /** @@ -511,12 +513,12 @@ export default function (Commands, Cypress, cy) { } return restoreSessionWorkflow(session) - }).then((status: 'created' | 'restored' | 'recreated' | 'failed') => { + }, { timeout: COMMAND_TIMEOUT }).then((status: 'created' | 'restored' | 'recreated' | 'failed') => { return navigateAboutBlank() .then(() => { setSessionLogStatus(status) }) - }) + }, { timeout: COMMAND_TIMEOUT }) }) }, }) From ba29ed140fc5f100cb0afa078078a5e8e8fccdfc Mon Sep 17 00:00:00 2001 From: Matthew Schile Date: Tue, 27 May 2025 11:26:29 -0600 Subject: [PATCH 2/6] adding timeouts --- packages/app/src/runner/aut-iframe.ts | 2 + .../driver/src/cy/commands/sessions/index.ts | 42 +++++++++---------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/packages/app/src/runner/aut-iframe.ts b/packages/app/src/runner/aut-iframe.ts index 43645f70c6e0..9681dea289c2 100644 --- a/packages/app/src/runner/aut-iframe.ts +++ b/packages/app/src/runner/aut-iframe.ts @@ -126,6 +126,8 @@ export class AutIframe { visitBlankPage = (testIsolation?: boolean) => { return new Promise((resolve) => { if (!this.$iframe) { + resolve() + return } diff --git a/packages/driver/src/cy/commands/sessions/index.ts b/packages/driver/src/cy/commands/sessions/index.ts index 7452a6e443fb..889320168241 100644 --- a/packages/driver/src/cy/commands/sessions/index.ts +++ b/packages/driver/src/cy/commands/sessions/index.ts @@ -151,7 +151,7 @@ export default function (Commands, Cypress, cy) { message: '', type: 'system', }, (setupLogGroup) => { - return cy.then(async () => { + return cy.then({ timeout: COMMAND_TIMEOUT }, async () => { // Catch when a cypress command fails in the setup function to correctly update log status // before failing command and ending command queue. cy.state('onQueueFailed', (err, _queue) => { @@ -181,8 +181,8 @@ export default function (Commands, Cypress, cy) { } finally { cy.breakSubjectLinksToCurrentChainer() } - }, { timeout: COMMAND_TIMEOUT }) - .then(async () => { + }) + .then({ timeout: COMMAND_TIMEOUT }, async () => { cy.state('onQueueFailed', null) const data = await sessions.getCurrentSessionData() @@ -202,7 +202,7 @@ export default function (Commands, Cypress, cy) { }) return - }, { timeout: COMMAND_TIMEOUT }) + }) }) } @@ -243,7 +243,7 @@ export default function (Commands, Cypress, cy) { } }, }, (validateLog) => { - return cy.then(async () => { + return cy.then({ timeout: COMMAND_TIMEOUT }, async () => { const isValidSession = true let caughtCommandErr = false let _commandToRunAfterValidation @@ -352,7 +352,7 @@ export default function (Commands, Cypress, cy) { throw err } - _commandToRunAfterValidation = cy.then(async () => { + _commandToRunAfterValidation = cy.then({ timeout: COMMAND_TIMEOUT }, async () => { Cypress.state('onQueueFailed', null) if (caughtCommandErr) { @@ -424,10 +424,10 @@ export default function (Commands, Cypress, cy) { }) return isValidSession - }, { timeout: COMMAND_TIMEOUT }) + }) return _commandToRunAfterValidation - }, { timeout: COMMAND_TIMEOUT }) + }) }) } /** @@ -436,16 +436,16 @@ export default function (Commands, Cypress, cy) { * 2. validate session */ const createSessionWorkflow = (existingSession, step: 'create' | 'recreate') => { - return cy.then(async () => { + return cy.then({ timeout: COMMAND_TIMEOUT }, async () => { setSessionLogStatus(statusMap.inProgress(step)) await navigateAboutBlank() await sessions.clearCurrentSessionData() return cy.whenStable(() => createSession(existingSession, step)) - }, { timeout: COMMAND_TIMEOUT }) - .then(() => validateSession(existingSession, step), { timeout: COMMAND_TIMEOUT }) - .then(async (isValidSession: boolean) => { + }) + .then({ timeout: COMMAND_TIMEOUT }, () => validateSession(existingSession, step)) + .then({ timeout: COMMAND_TIMEOUT }, async (isValidSession: boolean) => { if (!isValidSession) { return 'failed' } @@ -454,7 +454,7 @@ export default function (Commands, Cypress, cy) { await sessionsManager.saveSessionData(existingSession) return statusMap.complete(step) - }, { timeout: COMMAND_TIMEOUT }) + }) } /** @@ -464,21 +464,21 @@ export default function (Commands, Cypress, cy) { * 3. if validation fails, catch error and recreate session */ const restoreSessionWorkflow = (existingSession: Cypress.SessionData) => { - return cy.then(async () => { + return cy.then({ timeout: COMMAND_TIMEOUT }, async () => { setSessionLogStatus(statusMap.inProgress(SESSION_STEPS.restore)) await navigateAboutBlank() await sessions.clearCurrentSessionData() return restoreSession(existingSession) - }, { timeout: COMMAND_TIMEOUT }) - .then(() => validateSession(existingSession, SESSION_STEPS.restore), { timeout: COMMAND_TIMEOUT }) - .then((isValidSession: boolean) => { + }) + .then({ timeout: COMMAND_TIMEOUT }, () => validateSession(existingSession, SESSION_STEPS.restore)) + .then({ timeout: COMMAND_TIMEOUT }, (isValidSession: boolean) => { if (!isValidSession) { return createSessionWorkflow(existingSession, SESSION_STEPS.recreate) } return statusMap.complete(SESSION_STEPS.restore) - }, { timeout: COMMAND_TIMEOUT }) + }) } /** @@ -497,7 +497,7 @@ export default function (Commands, Cypress, cy) { } return logGroup(Cypress, groupDetails, (log) => { - return cy.then(async () => { + return cy.then({ timeout: COMMAND_TIMEOUT }, async () => { _log = log if (!session.hydrated) { @@ -513,12 +513,12 @@ export default function (Commands, Cypress, cy) { } return restoreSessionWorkflow(session) - }, { timeout: COMMAND_TIMEOUT }).then((status: 'created' | 'restored' | 'recreated' | 'failed') => { + }).then({ timeout: COMMAND_TIMEOUT }, (status: 'created' | 'restored' | 'recreated' | 'failed') => { return navigateAboutBlank() .then(() => { setSessionLogStatus(status) }) - }, { timeout: COMMAND_TIMEOUT }) + }) }) }, }) From 625e95bd5d3c14a79d12845ddb91a50ff546947c Mon Sep 17 00:00:00 2001 From: Matthew Schile Date: Tue, 27 May 2025 11:51:00 -0600 Subject: [PATCH 3/6] updating changelog --- cli/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index dc1499f62142..47fad3313b1a 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -3,6 +3,10 @@ _Released 6/3/2025 (PENDING)_ +**Bugfixes:** + +- Fixed an issue where `cy.session` may fail internally if navigating to `about:blank` takes longer than the `defaultCommandTimeout`. Addresses [#29496](https://github.com/cypress-io/cypress/issues/29496). + **Dependency Updates:** - Updated `@sinonjs/fake-timers` from `10.3.0` to `11.3.1`. Addressed in [#31746](https://github.com/cypress-io/cypress/pull/31746). From 15b1a025f53e9f2392c82b3867688be7430626fd Mon Sep 17 00:00:00 2001 From: Matthew Schile Date: Tue, 27 May 2025 12:13:08 -0600 Subject: [PATCH 4/6] add comment --- packages/driver/src/cy/commands/sessions/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/driver/src/cy/commands/sessions/index.ts b/packages/driver/src/cy/commands/sessions/index.ts index 889320168241..df6a6ab839d3 100644 --- a/packages/driver/src/cy/commands/sessions/index.ts +++ b/packages/driver/src/cy/commands/sessions/index.ts @@ -21,7 +21,8 @@ import { * - session data SHOULD be cleared between specs in run mode */ export default function (Commands, Cypress, cy) { - const COMMAND_TIMEOUT = 20000 + // 20s timeout used for internal cy commands within the session command + const COMMAND_TIMEOUT = 20_000 const sessionsManager = new SessionsManager(Cypress, cy) const sessions = sessionsManager.sessions From e2051127bf6dbbdd6cd8f768d148d2d2df77d249 Mon Sep 17 00:00:00 2001 From: Matthew Schile Date: Wed, 28 May 2025 07:45:58 -0600 Subject: [PATCH 5/6] rename variable --- .../driver/src/cy/commands/sessions/index.ts | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/driver/src/cy/commands/sessions/index.ts b/packages/driver/src/cy/commands/sessions/index.ts index df6a6ab839d3..ffae082cbcde 100644 --- a/packages/driver/src/cy/commands/sessions/index.ts +++ b/packages/driver/src/cy/commands/sessions/index.ts @@ -22,7 +22,7 @@ import { */ export default function (Commands, Cypress, cy) { // 20s timeout used for internal cy commands within the session command - const COMMAND_TIMEOUT = 20_000 + const INTERNAL_COMMAND_TIMEOUT = 20_000 const sessionsManager = new SessionsManager(Cypress, cy) const sessions = sessionsManager.sessions @@ -152,7 +152,7 @@ export default function (Commands, Cypress, cy) { message: '', type: 'system', }, (setupLogGroup) => { - return cy.then({ timeout: COMMAND_TIMEOUT }, async () => { + return cy.then({ timeout: INTERNAL_COMMAND_TIMEOUT }, async () => { // Catch when a cypress command fails in the setup function to correctly update log status // before failing command and ending command queue. cy.state('onQueueFailed', (err, _queue) => { @@ -183,7 +183,7 @@ export default function (Commands, Cypress, cy) { cy.breakSubjectLinksToCurrentChainer() } }) - .then({ timeout: COMMAND_TIMEOUT }, async () => { + .then({ timeout: INTERNAL_COMMAND_TIMEOUT }, async () => { cy.state('onQueueFailed', null) const data = await sessions.getCurrentSessionData() @@ -244,7 +244,7 @@ export default function (Commands, Cypress, cy) { } }, }, (validateLog) => { - return cy.then({ timeout: COMMAND_TIMEOUT }, async () => { + return cy.then({ timeout: INTERNAL_COMMAND_TIMEOUT }, async () => { const isValidSession = true let caughtCommandErr = false let _commandToRunAfterValidation @@ -353,7 +353,7 @@ export default function (Commands, Cypress, cy) { throw err } - _commandToRunAfterValidation = cy.then({ timeout: COMMAND_TIMEOUT }, async () => { + _commandToRunAfterValidation = cy.then({ timeout: INTERNAL_COMMAND_TIMEOUT }, async () => { Cypress.state('onQueueFailed', null) if (caughtCommandErr) { @@ -437,7 +437,7 @@ export default function (Commands, Cypress, cy) { * 2. validate session */ const createSessionWorkflow = (existingSession, step: 'create' | 'recreate') => { - return cy.then({ timeout: COMMAND_TIMEOUT }, async () => { + return cy.then({ timeout: INTERNAL_COMMAND_TIMEOUT }, async () => { setSessionLogStatus(statusMap.inProgress(step)) await navigateAboutBlank() @@ -445,8 +445,8 @@ export default function (Commands, Cypress, cy) { return cy.whenStable(() => createSession(existingSession, step)) }) - .then({ timeout: COMMAND_TIMEOUT }, () => validateSession(existingSession, step)) - .then({ timeout: COMMAND_TIMEOUT }, async (isValidSession: boolean) => { + .then({ timeout: INTERNAL_COMMAND_TIMEOUT }, () => validateSession(existingSession, step)) + .then({ timeout: INTERNAL_COMMAND_TIMEOUT }, async (isValidSession: boolean) => { if (!isValidSession) { return 'failed' } @@ -465,15 +465,15 @@ export default function (Commands, Cypress, cy) { * 3. if validation fails, catch error and recreate session */ const restoreSessionWorkflow = (existingSession: Cypress.SessionData) => { - return cy.then({ timeout: COMMAND_TIMEOUT }, async () => { + return cy.then({ timeout: INTERNAL_COMMAND_TIMEOUT }, async () => { setSessionLogStatus(statusMap.inProgress(SESSION_STEPS.restore)) await navigateAboutBlank() await sessions.clearCurrentSessionData() return restoreSession(existingSession) }) - .then({ timeout: COMMAND_TIMEOUT }, () => validateSession(existingSession, SESSION_STEPS.restore)) - .then({ timeout: COMMAND_TIMEOUT }, (isValidSession: boolean) => { + .then({ timeout: INTERNAL_COMMAND_TIMEOUT }, () => validateSession(existingSession, SESSION_STEPS.restore)) + .then({ timeout: INTERNAL_COMMAND_TIMEOUT }, (isValidSession: boolean) => { if (!isValidSession) { return createSessionWorkflow(existingSession, SESSION_STEPS.recreate) } @@ -498,7 +498,7 @@ export default function (Commands, Cypress, cy) { } return logGroup(Cypress, groupDetails, (log) => { - return cy.then({ timeout: COMMAND_TIMEOUT }, async () => { + return cy.then({ timeout: INTERNAL_COMMAND_TIMEOUT }, async () => { _log = log if (!session.hydrated) { @@ -514,7 +514,7 @@ export default function (Commands, Cypress, cy) { } return restoreSessionWorkflow(session) - }).then({ timeout: COMMAND_TIMEOUT }, (status: 'created' | 'restored' | 'recreated' | 'failed') => { + }).then({ timeout: INTERNAL_COMMAND_TIMEOUT }, (status: 'created' | 'restored' | 'recreated' | 'failed') => { return navigateAboutBlank() .then(() => { setSessionLogStatus(status) From 4489f13cb5c21e983c9b86e818dfa6ed28aaac3b Mon Sep 17 00:00:00 2001 From: Matt Schile Date: Wed, 28 May 2025 12:35:35 -0600 Subject: [PATCH 6/6] Update cli/CHANGELOG.md Co-authored-by: Bill Glesias --- cli/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 47fad3313b1a..684c02b48420 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -5,7 +5,7 @@ _Released 6/3/2025 (PENDING)_ **Bugfixes:** -- Fixed an issue where `cy.session` may fail internally if navigating to `about:blank` takes longer than the `defaultCommandTimeout`. Addresses [#29496](https://github.com/cypress-io/cypress/issues/29496). +- Fixed an issue where `cy.session()` may fail internally if navigating to `about:blank` takes longer than the `defaultCommandTimeout`. Addresses [#29496](https://github.com/cypress-io/cypress/issues/29496). **Dependency Updates:**