diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index d990cb00f785..73b792f56383 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). + **Misc:** - The design of commands that display as grouped (such as `.within()` and `cy.session()`) has been updated to provide better clarity when collapsing groups. Addressed in [#31739](https://github.com/cypress-io/cypress/pull/31739). 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 3a72d0f98e10..ffae082cbcde 100644 --- a/packages/driver/src/cy/commands/sessions/index.ts +++ b/packages/driver/src/cy/commands/sessions/index.ts @@ -21,6 +21,9 @@ import { * - session data SHOULD be cleared between specs in run mode */ export default function (Commands, Cypress, cy) { + // 20s timeout used for internal cy commands within the session command + const INTERNAL_COMMAND_TIMEOUT = 20_000 + const sessionsManager = new SessionsManager(Cypress, cy) const sessions = sessionsManager.sessions @@ -149,7 +152,7 @@ export default function (Commands, Cypress, cy) { message: '', type: 'system', }, (setupLogGroup) => { - return cy.then(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) => { @@ -180,7 +183,7 @@ export default function (Commands, Cypress, cy) { cy.breakSubjectLinksToCurrentChainer() } }) - .then(async () => { + .then({ timeout: INTERNAL_COMMAND_TIMEOUT }, async () => { cy.state('onQueueFailed', null) const data = await sessions.getCurrentSessionData() @@ -241,7 +244,7 @@ export default function (Commands, Cypress, cy) { } }, }, (validateLog) => { - return cy.then(async () => { + return cy.then({ timeout: INTERNAL_COMMAND_TIMEOUT }, async () => { const isValidSession = true let caughtCommandErr = false let _commandToRunAfterValidation @@ -350,7 +353,7 @@ export default function (Commands, Cypress, cy) { throw err } - _commandToRunAfterValidation = cy.then(async () => { + _commandToRunAfterValidation = cy.then({ timeout: INTERNAL_COMMAND_TIMEOUT }, async () => { Cypress.state('onQueueFailed', null) if (caughtCommandErr) { @@ -434,7 +437,7 @@ export default function (Commands, Cypress, cy) { * 2. validate session */ const createSessionWorkflow = (existingSession, step: 'create' | 'recreate') => { - return cy.then(async () => { + return cy.then({ timeout: INTERNAL_COMMAND_TIMEOUT }, async () => { setSessionLogStatus(statusMap.inProgress(step)) await navigateAboutBlank() @@ -442,8 +445,8 @@ export default function (Commands, Cypress, cy) { return cy.whenStable(() => createSession(existingSession, step)) }) - .then(() => validateSession(existingSession, step)) - .then(async (isValidSession: boolean) => { + .then({ timeout: INTERNAL_COMMAND_TIMEOUT }, () => validateSession(existingSession, step)) + .then({ timeout: INTERNAL_COMMAND_TIMEOUT }, async (isValidSession: boolean) => { if (!isValidSession) { return 'failed' } @@ -462,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(async () => { + return cy.then({ timeout: INTERNAL_COMMAND_TIMEOUT }, async () => { setSessionLogStatus(statusMap.inProgress(SESSION_STEPS.restore)) await navigateAboutBlank() await sessions.clearCurrentSessionData() return restoreSession(existingSession) }) - .then(() => validateSession(existingSession, SESSION_STEPS.restore)) - .then((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) } @@ -495,7 +498,7 @@ export default function (Commands, Cypress, cy) { } return logGroup(Cypress, groupDetails, (log) => { - return cy.then(async () => { + return cy.then({ timeout: INTERNAL_COMMAND_TIMEOUT }, async () => { _log = log if (!session.hydrated) { @@ -511,7 +514,7 @@ export default function (Commands, Cypress, cy) { } return restoreSessionWorkflow(session) - }).then((status: 'created' | 'restored' | 'recreated' | 'failed') => { + }).then({ timeout: INTERNAL_COMMAND_TIMEOUT }, (status: 'created' | 'restored' | 'recreated' | 'failed') => { return navigateAboutBlank() .then(() => { setSessionLogStatus(status)