3

I have a test case which opens a secondary window. From what I read online, you should prevent this second window opening and visit the url that should have been opened. However, in all the test example I saw, the second url is static. In my case, I need it to be dynamic. This is why I'm using a cy.stub() to a window opening and trying to get the url from it.

cy.visit('https://myUrl.com');

cy.window().then(win => {
  cy.stub(win, 'open', newUrl => {
    cy.wrap(newUrl).as('newUrl');
  });
});

cy.get('#myButton').click(); // opens new window at new url with generated keys

cy.get('@newUrl').then(newUrl => {
  cy.visit(newUrl);
});

However, the cy.wrap() inside the cy.stub() triggers this error:

Error:        CypressError: Cypress detected that you returned a promise from a command while also invoking one or more cy commands in that promise.

The command that returned the promise was:

  > `cy.click()`

The cy command you invoked inside the promise was:

  > `cy.wrap()`

Because Cypress commands are already promise-like, you don't need to wrap them or return your own promise.

Basically my question is how to capture the url in a stub for later use. Thanks in advance.

Fody
  • 23,754
  • 3
  • 20
  • 37
Xavier DF
  • 33
  • 2

1 Answers1

1

The problem is using cy.wrap() or any cy commands inside an event listener. The code you have is valid, and the error should actually be a warning IMO.

One way to handle it is with a plain JS variable.

You may also need a cy.origin() wrapper for this test.

In a recent similar question How to access new tab by clicking on "href" it was found that the cy.visit(newUrl) was causing a reload of the test window, which looses all the data (variables and aliases) previously obtained.

cy.visit('https://myUrl.com');

let nextUrl;

cy.window().then(win => {
  cy.stub(win, 'open', newUrl => {
    nextUrl = newUrl
  });
});

cy.get('#myButton').click(); // opens new window at new url with generated keys

cy.then(() => {

  const newOrigin = nextUrl.split('?')[0]  // remove query params 
      .replace('http://', 'https://')      // correct for secure protocol

  cy.origin(newOrigin, { args: { nextUrl } }, ({ nextUrl }) => {
    cy.visit(nextUrl) 
  })
})

Alternative way to alias

Looking again at your code, you may be able to apply the alias this way

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

cy.get('#myButton').click(); 

cy.get('@newUrl').then(newUrl => {
  cy.visit(newUrl);
})
Fody
  • 23,754
  • 3
  • 20
  • 37
  • I didn't realize you could simply use a cy.then() to resolve Cypress's promise-like statements. I'm sure this will solve a lot of my problems. The first solution works great. Thanks a lot! I tried the second solution and what gets stored in newUrl is 'open'. First solution works great though! Thanks again! – Xavier DF Jul 20 '22 at 17:18