diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 125f7eddd6..d99bc1739a 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -1,4 +1,11 @@ +## 15.13.0 + +_Released 03/11/2026 (PENDING)_ + +**Misc:** + +- Rerun tests on `pagehide` or `unload` instead of on `beforeunload`. Addressed in [#33456](https://github.com/cypress-io/cypress/pull/33456). ## 15.12.0 @@ -9,6 +16,7 @@ _Released 03/10/2026_ - Adds an option to enable word wrap for Studio panel code. Addressed in [#33411](https://github.com/cypress-io/cypress/pull/33411). **Bugfixes:** + - Fixed an issue where sending SIGINT (e.g. Ctrl+C) to exit Cypress left the terminal displaying raw characters. Fixes [#33367](https://github.com/cypress-io/cypress/issues/33367). Addressed in [#33431](https://github.com/cypress-io/cypress/pull/33431). - Fixed an issue in develop mode (when running Cypress via gulp with file watching) where closing the Electron window did not exit the gulp process, leaving it running. Addressed in [#33431](https://github.com/cypress-io/cypress/pull/33431). - Fixed an issue where internal tags on stderr streams were surfacing to the end user CLI during component testing. Addresses [#32769](https://github.com/cypress-io/cypress/issues/32769). Addressed in [#33400](https://github.com/cypress-io/cypress/pull/33400). diff --git a/packages/app/src/runner/event-manager.ts b/packages/app/src/runner/event-manager.ts index bccb9451f7..1c96f21898 100644 --- a/packages/app/src/runner/event-manager.ts +++ b/packages/app/src/runner/event-manager.ts @@ -65,6 +65,7 @@ export class EventManager { studioStore: ReturnType promptStore: ReturnType specDirtyDataStore: ReturnType + _deferCleanupToUnload = false constructor ( // import '@packages/driver' @@ -361,8 +362,13 @@ export class EventManager { // event as a proxy for AUT unloads. const unloadEvent = this.isBrowserFamily('chromium') ? 'pagehide' : 'unload' - $window.on(unloadEvent, (e) => { - this._clearAllCookies() + $window.on(unloadEvent, () => { + if (this._deferCleanupToUnload) { + this._runFullUnloadCleanup() + this._deferCleanupToUnload = false + } else { + this._clearAllCookies() + } }) // when our window triggers beforeunload @@ -372,11 +378,18 @@ export class EventManager { // that Cypress knows not to set any more // cookies $window.on('beforeunload', () => { - telemetry.getSpan('cypress:app')?.end() - this.reporterBus.emit('reporter:restart:test:run') + if (this.specDirtyDataStore.isDirty()) { + // Used to handle Studio unsaved changes. It defers the cleanup to the unload event + // so that the test is not rerun if the user cancels the beforeunload dialog. + this._deferCleanupToUnload = true - this._clearAllCookies() - this._setUnload() + return + } + + // Clear any stale flag from a previously cancelled beforeunload so the unload + // handler does not run full cleanup again + this._deferCleanupToUnload = false + this._runFullUnloadCleanup() }) this.addPromptListeners() @@ -998,6 +1011,13 @@ export class EventManager { this.ws.emit('reload:browser', window.location.toString(), browser && browser.name) } + _runFullUnloadCleanup () { + telemetry.getSpan('cypress:app')?.end() + this.reporterBus.emit('reporter:restart:test:run') + this._clearAllCookies() + this._setUnload() + } + // clear all the cypress specific cookies // whenever our app starts // and additional when we stop running our tests