When running a test using the Electron browser on a webpage that contains a window.onbeforeunload
script and trying to navigate away, Cypress will fail to load the next page. The test will eventually fail after a PageLoadTimeout exception. This occurs when using any kind of navigation such as cy.reload()
, cy.visit()
, or interacting with an element that contains an href
linking to somewhere else.
Test run with Electron 59:
Test run with Chrome 67:
describe('Electron 59 alert prompt bug', function() {
it('Should navigate away from the page', function() {
cy.on('window:confirm', function() {
return true;
});
cy.visit('http://localhost:8080/');
cy.visit('http://localhost:8080/form');
});
it('Should reload the page', function() {
cy.visit('http://localhost:8080/');
cy.reload();
});
});
The page under test needs to contain a window.onbeforeunload
function which alters the returnValue. To reproduce, I use http-server
to serve a barebones HTML file
<!DOCTYPE html>
<script>
window.onbeforeunload = function (e) {
e.returnValue = 'Dialog';
return;
}
</script>
Cypress: 3.0.2
MacOS: High Sierra 10.13.5
Browsers: Chrome 67
, Electron 59
I've just hit this exact same problem. For now I've wrapped my onBeforeUnload
binding in a check for cypress which feels a bit dirty.
if (!window.Cypress) {
$window.onbeforeunload = function (e) { ... }
}
I was able to work around the issue with the following code in the test:
cy.window().then((win) => {
win.onbeforeunload = null;
})
cy.visit(<the next page goes here>)
Reproducible example: https://github.com/cypress-io/cypress-test-tiny/pull/27
Just chiming in here to say we have an issue within our tests because Cypress doesn't properly handle the window.onbeforeunload
event in Electron w/ Chromium 59, but works perfectly fine using Chrome 70 running the test runner. In our Jenkins env using docker, it also experiences the same issue with the cypress/base:10
image.
My guess is that the version of Chromium used by Electron (59) that ships with Cypress currently (3.1.0) has some major bugs and issues. I see #2559 is acknowledged, any ETA when that might get rolled out? I imagine this would fix a swath of issues being worked around due to an old version of Chromium.
Ya'll doin' great work though, I really appreciate Cypress :)
Cypress: 3.1.0
macOS: 10.14.1
Browsers: Electron 59
, Chrome 70
Started encountering this problem in our CI build. For now going to workaround by monkey patching window.addEventListener
:
Cypress.on('window:load', function(window) {
const original = window.addEventListener;
window.addEventListener = function() {
if (arguments && arguments[0] === 'beforeunload') {
return;
}
return original.apply(this, arguments);
};
});
If you're using window.onbeforeunload=function() {...}
instead of window.addEventListener('beforeunload', function() {...}
, you can use this workaround:
Cypress.on('window:load', function(window) {
Object.defineProperty(window, 'onbeforeunload', {
get: function() {},
set: function() {}
});
});
Regarding dannsam's approach, you may want to change 'window:load'
to 'window:before:load'
if you are adding the beforeunload
listener in some code executed on load.
Thank you @dannsam and @fritz-c , your workaround did it for me. I have encountered this issue using the autosave plugin for CKEditor 5, since it tries to make sure the last call was completed or something.
I have pushed another example https://github.com/cypress-io/cypress-test-tiny/tree/test-unload that shows the problem in Electron 61 (Chrome passes, despite showing an error). The website in question is http://webdriverjsdemo.github.io/leave/
and has the following script
window.onbeforeunload = function(){
return 'Are you sure you want to leave?';
};
The error displayed in the browser console:
This error has docs in https://www.chromestatus.com/feature/5082396709879808 and probably is not disabled in Electron
Funnily, you cannot close the Electron browser in GUI mode - it just keeps showing the error
Running cypress run --headed
shows the error that happens on CI - the test keeps running
There is also a situation where, where after visiting the site above, this will exhibit as a Page Load timeout.
Failing test code below:
describe('page', () => {
it('works', () => {
cy.visit('http://webdriverjsdemo.github.io/leave/')
cy.contains('Go Home')
.click()
})
it('works 2', () => {
cy.visit('http://webdriverjsdemo.github.io/leave/')
.contains('Go Home')
.click()
})
})
Electron will not display this error in the Console when this is happening also (if you have not manually interacted with the page)
[Intervention] Blocked attempt to show a 'beforeunload' confirmation panel for a frame that never had a user gesture since its load. https://www.chromestatus.com/feature/5082396709879808
There are 2 possible workarounds.
--chrome
flag during cypress run
or choosing Chrome during cypress open
.OR
support/index.js
file. This will prevent the prompts from occurring - and not hang Electron.Cypress.on('window:before:load', function (win) {
const original = win.EventTarget.prototype.addEventListener
win.EventTarget.prototype.addEventListener = function () {
if (arguments && arguments[0] === 'beforeunload') {
return
}
return original.apply(this, arguments)
}
Object.defineProperty(win, 'onbeforeunload', {
get: function () { },
set: function () { }
})
})
The code for this is done in cypress-io/cypress#5603, but has yet to be released.
We'll update this issue and reference the changelog when it's released.
Released in 3.6.1
.
Is this confirmed fix? Still experiencing this after upgrading to 3.6.1.
@hvuong-sigma Yes, please open a new issue with a reproducible example.
I am reopening this issue. While this was partially addressed in https://github.com/cypress-io/cypress/pull/5603 in 3.6.1 release by fixing the hanging while running in Electron (aka - the process would never exit), this did not actually fix the error portion of the issue.
Any application that has a defined onbeforeunload
handler that triggers an alert causes Cypress page load to time out within the Electron browser (not Chrome). Typically this is only noticed in CI since Electron is the chosen browser by default. Resulting in the error below:
index.html
<html>
<body>
hello world
</body>
<script>
window.onbeforeunload = () => confirm("test");
</script>
</html>
spec.js
it('should accept the confirm and successfully reload', function () {
cy.on('window:confirm', () => true) // this is unnecessary as it is the default behavior
cy.visit(`index.html`)
cy.reload()
})
it('works', () => {
cy.visit('http://webdriverjsdemo.github.io/leave/')
cy.contains('Go Home')
.click()
})
There are 2 possible workarounds.
--browser
flag during cypress run
or choosing Chrome during cypress open
.OR
support/index.js
file. This will prevent the prompts from occurring - and not hang Electron.Cypress.on('window:before:load', function (win) {
const original = win.EventTarget.prototype.addEventListener
win.EventTarget.prototype.addEventListener = function () {
if (arguments && arguments[0] === 'beforeunload') {
return
}
return original.apply(this, arguments)
}
Object.defineProperty(win, 'onbeforeunload', {
get: function () { },
set: function () { }
})
})
The window:before:load
solution worked for me.
I had an aha moment when I realized that the project that I work on shows a popup to confirm that the user will release her lock on that piece of content.
This is not fixed as part of upcoming Electron 9 upgrade.
Hey I is anyone else still seeing this issue when using a custom protocol?
Like this zoommtg://us04web.zoom.us/join?action=join&confno=...
I am getting this error
Looks like a different issue to me, @Russ93 — consider opening a new issue ☺️
Still the same issue occurs. Accessing an URL and throws one pop-up since one file couldn't be loaded. After that, even after closing the pop-up the tool shows 'Loading' progress and keeps waiting for the page to load and throws the below error.
Yes, this hasn't been fixed yet. See https://github.com/cypress-io/cypress/issues/2118#issuecomment-580095512 where there exists a workaround.
Thanks for the quick response. Tried the below workaround, however still not working.
Cypress.on('window:before:load', function (win) {
const original = win.EventTarget.prototype.addEventListener
win.EventTarget.prototype.addEventListener = function () {
if (arguments && arguments[0] === 'beforeunload') {
return
}
return original.apply(this, arguments)
}
Object.defineProperty(win, 'onbeforeunload', {
get: function () { },
set: function () { }
})
})
Please suggest for any other workarounds and I shall try it!! Thanks in advance!!!
Most helpful comment
I am reopening this issue. While this was partially addressed in https://github.com/cypress-io/cypress/pull/5603 in 3.6.1 release by fixing the hanging while running in Electron (aka - the process would never exit), this did not actually fix the error portion of the issue.
Problem
Any application that has a defined
onbeforeunload
handler that triggers an alert causes Cypress page load to time out within the Electron browser (not Chrome). Typically this is only noticed in CI since Electron is the chosen browser by default. Resulting in the error below:To reproduce
Example 1
index.html
spec.js
Example 2
Workaround
There are 2 possible workarounds.
--browser
flag duringcypress run
or choosing Chrome duringcypress open
.OR
support/index.js
file. This will prevent the prompts from occurring - and not hang Electron.