Stub window.open
Motivation
If an application calls window.open
during Cypress test it might lead to two problems:
- the new URL might point at a different domain, rendering Cypress "blind" and unable to continue the test
- the new URL might open in the second tab, invisible to Cypress
Stubbing an object's method
In order to stub (replace) an object's method we need three things:
- a reference to the object
- method's name
- we also have to register the stub before the application calls the method we are replacing
🖥 I explain how the commands cy.spy and cy.stub work at the start of the presentation How
cy.intercept
works.
Luckily for us stubbing the window.open
satisfies all the criteria easily
- the command cy.window gets the reference to the application's
window
object - the method's name is
open
- we can use
onBeforeLoad
callback in the cy.visit to stub thewindow.open
method. This callback runs when thewindow
object is ready, but before any application code runs
1 | it('opens a new window', () => { |
When window changes
If the application navigates to a new page or even reloads, the old window
object is destroyed and the new window
object is created. Thus our window.open
stub can "disappear": the application calls window.open
, but the stub does not intercept the new calls.
1 | // 🚨 SHOWING THE PROBLEM |
We need to register window.open
stub for every window object created during the test. We can use cy.on('window:before:load')
event:
1 | // ✅ CORRECT SOLUTION |
The above test correctly prevents window.open
from causing problems when the application reloads or navigates to another page.
cy.on vs Cypress.on
We have used cy.on('window:before:load')
to register our stub. We could have used Cypress.on('window:before:load')
, but then we could not use the cy.stub
command inside the callback - Cypress.on
runs outside a test context and thus cannot use any cy.
commands. It is often used to perform general application actions. For example we could remove window.fetch
method from every window object
1 | Cypress.on('window:before:load', (win) => { |
In our window.open
case we can bypass the problem. We can return the same stub for every window, we just have to return the variable prepared by the test via closure scope:
1 | // variable that will hold cy.stub created in the test |
Tip: you can reset a spy or a stub by invoking its reset()
method
1 | // triggers the application to call window.open |
See also
I have described in detail how to deal with anchor links and window.open
in two sections in the blog post Cypress Tips and Tricks:
- Deal with Second Tab in Cypress
- Deal with
target=_blank
- I strongly recommend reading Deal with
window.open
There is also more documentation and examples available at:
- Sinon.js
- Cypress guide to Stubs, Spies, and Clocks
cy.stub
andcy.spy
examples
You can also read about and practice with cy.stub
in the section of the Cypress Testing Workshop
See the blog post Stub window.track