70

The question is as simple as that. In Cypress, how can I access a new window that opens up when running the test.

Steps to recreate :

  1. Run the test. After some action, new window pops up (the url is dynamic in nature).
  2. Fill in the fields in the new window, and click a few buttons.
  3. After required actions are completed in the new Window, close the new window and move back to the main window.
  4. Continue execution with the main window.

Point of interest: the focus should be

main window -> new window -> main window

I have read few things that relate to use of iframe and confirmation box, but here its none of those. Relates to accessing a whole new window. Something like Window Handlers in Selenium. Unfortunately could not find anything related to it.

Kaushik NP
  • 6,733
  • 9
  • 31
  • 60

7 Answers7

89

Accessing new windows via Cypress is intentionally not supported.

However, there are many ways this functionality can be tested in Cypress now. You can split up your tests into separate pieces and still have confidence that your application is covered.

  1. Write a test to check that when performing the action in your app, the window.open event is called by using cy.spy() to listen for a window.open event.
cy.visit('http://localhost:3000', {
  onBeforeLoad(win) {
    cy.stub(win, 'open')
  }
})

// Do the action in your app like cy.get('.open-window-btn').click()

cy.window().its('open').should('be.called')
  1. In a new test, use cy.visit() to go to the url that would have opened in the new window, fill in the fields and click the buttons like you would in a Cypress test.
cy.visit('http://localhost:3000/new-window')

// Do the actions you want to test in the new window

Fully working test example can be found here.

Jennifer Shehane
  • 6,645
  • 1
  • 30
  • 26
  • 2
    Hmmm. Roundabout way, but works I guess. One question. How do I get the URL from the button click. Assuming that the url changes each time I click it. – Kaushik NP Dec 19 '17 at 10:53
  • 5
    Instead of `be.called` you can use the assertion `be.calledWith` and assert about the url. I've created a full example of the working tests here: https://github.com/cypress-io/cypress-example-recipes/blob/master/examples/stubbing-spying__window/cypress/integration/window-stubbing.spec.js – Jennifer Shehane Dec 20 '17 at 19:04
  • Um, more like in cases that : I don't know the url of the new window, how can I get it dynamically? I am thinking may be get the `href` attribute if its available? So is there a `.getattribute` function for such scenario? – Kaushik NP Dec 21 '17 at 01:22
  • 3
    Yes, you can always just use JavaScript. cy.get('a').then(($a) => { var url = $a[0].getAttribute('href') }) – Jennifer Shehane Dec 21 '17 at 16:27
  • Ok, thank you Jennifer. I'll check it out when I get time, but it should work perfectly well. – Kaushik NP Dec 21 '17 at 19:20
  • Would it be possible to get the instance of the window that just has been created? Becaus, my app has been made I cannot reach the new window by its URL – Yoann Picquenot Apr 19 '18 at 14:36
  • Is there a way to add the spy to the window inside an iframe? The app I'm testing is an iframe and calls window.open to open a pop up. – William Chou Jan 23 '19 at 23:29
  • Also use Cypress.spy() on the window Object, Okay but how can we access the newly opened window, while the test is running on the default window? – bvmCoder May 07 '19 at 02:36
  • @JenniferShehane : I am facing similar issue but not able to resolve it out https://stackoverflow.com/questions/58328099/not-able-to-switch-windows-using-stub-and-spy-using-cypress – Rahil Kumar Oct 11 '19 at 06:42
  • Current link of the "be.calledWith" implementation can be found at: https://github.com/cypress-io/cypress-example-recipes/tree/master/examples/stubbing-spying__window – Robert DROP TABLE STUDENTS Feb 10 '20 at 08:30
  • "The web has evolved. Finally, testing has too." - says Cypress. Apparently this evolved testing does not include such basic functionality as window handlers. – Alichino Jun 30 '20 at 12:02
  • fwiw I used an alias for the stub, and then later used a matcher to confirm partial match: `cy.get('@facebookPopup').should('have.been.calledWith', Cypress.sinon.match('https://www.facebook.com/v2.1/dialog/oauth'))` – patcon Aug 24 '20 at 20:26
  • Could also get the full url with `cy.get('@facebookPopup').then(stub => {console.log(stub.getCall(0).args[0])})` – patcon Aug 24 '20 at 20:27
  • Hey, @patcon I didn't find any documentation from cypress regarding how to retrieve, handle, and check stubs. 1. How did you figure out about the **getCall** method? 2. What other methods are there to use on the stubs? – Jhonatan Dec 25 '20 at 16:31
  • 3
    Once we have access to the open window, how do we perform operations on it and then switch back to the old window? I could verify till the fact that window opened. But I am not able to find buttons on this opened window. works- cy.window().then((win) => { cy.spy(win, 'open').as('windowOpen'); }); cy.get('button').contains('Sign in to your account').click() cy.get('@windowOpen').should('have.been.calledWith', Cypress.sinon.match('about:blank')) This doesnt work - cy.get('@windowOpen').get('#buttonid1').click() Also not sure how you move back to old window? – namrata Apr 22 '21 at 23:11
  • I want to check window.open is not called how can I do that ? – Ankita Feb 22 '22 at 13:19
22

I am not cypress expert, just started using it few days ago, but I figured out this kind solution for stateful application with dynamic link:

// Get window object
cy.window().then((win) => {
  // Replace window.open(url, target)-function with our own arrow function
  cy.stub(win, 'open', url => 
  {
    // change window location to be same as the popup url
    win.location.href = Cypress.config().baseUrl + url;
  }).as("popup") // alias it with popup, so we can wait refer it with @popup
})

// Click button which triggers javascript's window.open() call
cy.get("#buttonWhichOpensPopupWithDynamicUrl").click()

// Make sure that it triggered window.open function call
cy.get("@popup").should("be.called")

// Now we can continue integration testing for the new "popup tab" inside the same tab

Is there any better way to do this?

Antti
  • 1,029
  • 12
  • 15
  • 4
    Wow, work like charm! This should be documented in the official documentation. – xwlee Jul 29 '20 at 09:53
  • 6
    Once we have access to the open window, how do we perform operations on it and then switch back to the old window? I could verify till the fact that window opened. But I am not able to find buttons on this opened window. works- cy.window().then((win) => { cy.spy(win, 'open').as('windowOpen'); }); cy.get('button').contains('Sign in to your account').click() cy.get('@windowOpen').should('have.been.calledWith', Cypress.sinon.match('about:blank')) This doesnt work - cy.get('@windowOpen').get('#buttonid1').click() Also not sure how you move back to old window? – namrata Apr 22 '21 at 23:28
  • This is great. It works as intended. – AlighaThor Oct 13 '21 at 18:13
10
// We can remove the offending attribute - target='_blank'
      // that would normally open content in a new tab.
      cy.get('#users').invoke('removeAttr', 'target').click()

      // after clicking the <a> we are now navigated to the
      // new page and we can assert that the url is correct
      cy.url().should('include', 'users.html')

Cypress - tab handling anchor links

Gal Margalit
  • 5,525
  • 6
  • 52
  • 56
9

I was able to achieve the same requirement via the following:

let newUrl = '';
cy.window().then((win) => {
  cy.stub(win, 'open').as('windowOpen').callsFake(url => {
    newUrl = url;
  });
})

cy.get('.open-window-btn').click()
cy.get('@windowOpen').should('be.called');
cy.visit(newUrl)
Audwin Oyong
  • 2,247
  • 3
  • 15
  • 32
Madusha
  • 164
  • 3
  • 13
7

Here's a solution i'm using on my project based on "Cypress using child window"

Cypress Window Helpers (aka. Cypress Tab Helpers) They're really popup-windows or child-windows, but i call them tabs for api brevity

cy.openTab(url, opts)
cy.tabVisit(url, window_name)
cy.switchToTab(tab_name)
cy.closeTab(index_or_name) - pass nothing to close active tab
cy.closeAllTabs() - except main root window
jake downs
  • 331
  • 3
  • 9
7

I was recently faced with this issue as well - url for the new tab is dynamic, so I don't know what it is. After much searching, some trial and error, and input from co-workers, resolved by doing the following:

// AFTER cy.visit()
cy.window().then((win) => {
  cy.spy(win, 'open').as('windowOpen'); // 'spy' vs 'stub' lets the new tab still open if you are visually watching it
});
// perform action here [for me it was a button being clicked that eventually ended in a window.open]
// verify the window opened
// verify the first parameter is a string (this is the dynamic url) and the second is _blank (opens a new window)
cy.get('@windowOpen').should('be.calledWith', Cypress.sinon.match.string, '_blank');
lilabnersgal
  • 198
  • 1
  • 4
  • 8
  • 1
    Once we have access to the open window, how do we perform operations on it and then switch back to the old window? I could verify till the fact that window opened. But I am not able to find buttons on this opened window. works- cy.window().then((win) => { cy.spy(win, 'open').as('windowOpen'); }); cy.get('button').contains('Sign in to your account').click() cy.get('@windowOpen').should('have.been.calledWith', Cypress.sinon.match('about:blank')) This doesnt work - cy.get('@windowOpen').get('#buttonid1').click() Also not sure how you move back to old window? – namrata Apr 22 '21 at 23:13
  • 1
    @namrata Cypress does not support multiple tabs. That is why my code is only verifying that window.open was called. In their [examples](https://github.com/cypress-io/cypress-example-recipes/blob/master/examples/testing-dom__tab-handling-links/cypress/integration/tab_handling_anchor_links_spec.js) they provide multiple ways to handle the new tab situation. – lilabnersgal Apr 24 '21 at 02:07
  • @namrata you have to turn off the chromewebsecurity in cypress.json. By default it’s value is true you can check in settings on cypress dashboard. For example please watch this video https://youtu.be/C2DjGl5a_-Y starting 27th minute – pk786 May 02 '21 at 00:14
  • cy.window().its('open').should('be.not.be. called') can I do this – Ankita – Ankita Feb 22 '22 at 13:18
  • @Ankita If you want to verify it did not open, you want should('not.be.called') -- remove the extra 'be' at the beginning. – lilabnersgal Feb 23 '22 at 19:29
2

this is how you can handle tabs in same window..

use this code snippet

cy.xpath("//a[@href='http://www.selenium.dev']").invoke('removeAttr','target').click();
I_love_vegetables
  • 1,575
  • 5
  • 12
  • 26
Siddiqui
  • 21
  • 1