diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 10e38351f96e..9690711f9a55 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -3,6 +3,10 @@ _Released 11/5/2024 (PENDING)_ +**Bugfixes:** + +- Fixed an issue where the Cypress runner could hang in `after` or `afterEach` hooks that run Cypress commands after a page load timeout error occurs. Addresses [#30238](https://github.com/cypress-io/cypress/issues/30238). + **Misc:** - Fixed a typo in CLI `global` option help text. Addresses [#30531](https://github.com/cypress-io/cypress/issues/30531). diff --git a/packages/driver/cypress/e2e/issues/30238.cy.js b/packages/driver/cypress/e2e/issues/30238.cy.js new file mode 100644 index 000000000000..f9a66b2adb65 --- /dev/null +++ b/packages/driver/cypress/e2e/issues/30238.cy.js @@ -0,0 +1,34 @@ +after(() => { + // ensure that we're stable in the after hooks + expect(cy.state('isStable')).to.be.true + + // ensure we can enqueue a command without timing out + cy.then(() => { + expect(true).to.be.true + }) +}) + +afterEach(() => { + // ensure that we're stable in the after hooks + expect(cy.state('isStable')).to.be.true + + // ensure that we can enqueue a command without timing out + cy.then(() => { + expect(true).to.be.true + }) +}) + +it('runs an after block without timing out when the page load times out', { pageLoadTimeout: 500 }, () => { + cy.on('fail', (error) => { + expect(error.message).to.include('Timed out after') + + return false + }) + + cy.on('window:before:load', (win) => { + // Stop the page from loading so that the page load times out + win.stop() + }) + + cy.visit('/fixtures/generic.html') +}) diff --git a/packages/driver/src/cypress/command_queue.ts b/packages/driver/src/cypress/command_queue.ts index 3b692c51b413..09ac6e460bf2 100644 --- a/packages/driver/src/cypress/command_queue.ts +++ b/packages/driver/src/cypress/command_queue.ts @@ -223,6 +223,9 @@ export class CommandQueue extends Queue<$Command> { // end in case we have after / afterEach hooks // which need to run this.index = this.length + + // Mark the state as stable, so that any cypress commands can be re-queued during the after / afterEach hooks + this.state('isStable', true) } private runCommand (command: $Command) {