Skip to content

Instantly share code, notes, and snippets.

@jakedowns
Last active November 22, 2022 04:27
Show Gist options
  • Save jakedowns/32b75add88736fcd99c7202a98354384 to your computer and use it in GitHub Desktop.
Save jakedowns/32b75add88736fcd99c7202a98354384 to your computer and use it in GitHub Desktop.
Cypress Popup Window Context Switching
/* cypress/integration/myTest.spec.js */
describe('myComplexWebsocketApp',()=>{
cy.visit('myApp/adminSection')
// ... assert some things about Admin Section
cy.openWindow('myApp/clientSection')
// ... assert some things about Client Section
cy.toggleWindows() // switch back to Admin Section
// ... perform some action Client should see
cy.toggleWindows() // switch to Client
// ... assert Admin action updated Client
// ... perform some action Admin should see
cy.toggleWindows() // switch to Admin Section
// ... assert Admin sees Client's response
cy.closeWindow() // close popup window and return to root window context
})
/* cypress/support/command.js */
let originalWindow = null;
Cypress.Commands.add('openWindow', (url, features) => {
if(!originalWindow){
originalWindow = cy.state('window');
originalWindow.APP_ID = 1; // depth 1
}
const w = Cypress.config('viewportWidth')
const h = Cypress.config('viewportHeight')
if (!features) {
features = `width=${w}, height=${h}`
}
console.log('openWindow %s "%s"', url, features)
return new Promise(resolve => {
if (window.top.MyAltWindow && window.top.MyAltWindow.close) {
console.log('window exists already')
window.top.MyAltWindow.close()
}
// https://developer.mozilla.org/en-US/docs/Web/API/Window/open
window.top.MyAltWindow = window.top.open(url, 'MyAltWindow', features)
window.top.MyAltWindow.APP_ID = 2; // TODO: make this support n-many
// letting page enough time to load and set "document.domain = localhost"
// so we can access it
setTimeout(() => {
cy.state('document', window.top.MyAltWindow.document)
cy.state('window', window.top.MyAltWindow)
resolve()
}, 500)
})
})
/* toggle between 2 for now, could set this up to handle N-many windows */
Cypress.Commands.add('toggleWindows', ()=>{
return new Promise(resolve=>{
if(cy.state('window').APP_ID === 1){
// switch to our ALT window
console.log('switching to alt popup window...')
cy.state('document', originalWindow.top.MyAltWindow.document)
cy.state('window', originalWindow.top.MyAltWindow)
originalWindow.blur()
}else{
console.log('switching back to original window')
// switch back to originalWindow
cy.state('document', originalWindow.document)
cy.state('window', originalWindow)
originalWindow.top.MyAltWindow.blur()
}
window.blur();
cy.state('window').focus()
resolve();
})
})
Cypress.Commands.add('closeWindow', ()=>{
return new Promise(resolve=>{
if(window.top.MyAltWindow && window.top.MyAltWindow.close){
window.top.MyAltWindow.close() // close popup
window.top.MyAltWindow = null
}
if(originalWindow){
cy.state('document', originalWindow.document)
cy.state('window', originalWindow)
}
cy.state('window').focus()
resolve()
})
})
@jakedowns
Copy link
Author

jakedowns commented Aug 31, 2022

it's been 2 years since i've used cypress, and, they may have worked on new APIs for solving this (they've been promising it for years, maybe they still haven't) but, I would think if in your code somewhere you capture a reference to the new window in a variable that you can access from your cypress test, you could then use a modified version of these commands to switch between your main window and your "captured" window.

specifically, this part (add this to your code where you open the window)

// capture the alt window
window.top.MyAltWindow = window.top.open(url, 'MyAltWindow', features)
// set a var to identify it (so you know if you're in the alt window or the OG window)
window.top.MyAltWindow.APP_ID = 2;

then, in your test:

let features = ''; // or features = `width=${w}, height=${h}`
let originalWindow = cy.state('window') // reference to return to
// set cypress context to the ALT window
cy.state('document', originalWindow.top.MyAltWindow.document) // set context doc
cy.state('window', originalWindow.top.MyAltWindow) // set context window
originalWindow.blur() // blur original window
cy.state('window').focus() // focus new window

// to get back to the main window
originalWindow.top.MyAltWindow.close() // close it
originalWindow.top.MyAltWindow = null // de-reference it
cy.state('document', originalWindow.document) // set context doc
cy.state('window', originalWindow) // set context window
cy.state('window').focus() // focus it

i think you could add a special listener to the button to keep all this code in your cypress script only, without modifying the original code / href. but this is just off the top of my head

granted this isn't ideal since your link would need a click handler, rather than just a href+target="_blank" or target="my_new_window_name"
but, hopefully this is semi-helpful

@jakedowns
Copy link
Author

ultimately, i scrapped this approach and used a page full of iframes instead: https://github.com/jakedowns/CypressHelpers/blob/master/frame_helpers.js

but, that was more for testing simultaneous events happening across multiple pages, not really pop-up's specifically

@a2ospennikov
Copy link

Hello. I have some issue.
I have legasy app, which was made with using many iframes. But the main problem - many events links to the script in top frame by using window.top. We can't refactor this because app is very big and spagetting. ThereforeI I need to open app in separate window.

I try to use your commands for windows manipulation, but they works strange with my app:

  1. When i open use just cy.openWindow() without cy.visit(), Cypress dont see any elements on page.
  2. When use firstly cy.visit() and after that cy.openWindow(), Cypress see all elements, but interact only with new page (until I switch by cy.toggleWindows)
  3. When i change page in new window (after login) Cypress dont see new elements.

Looks like Cypress find and interact just with elements in main window and in new window just shows results of interactions.

What can i do to get arount problem with using window.top in my app?

@jakedowns
Copy link
Author

jakedowns commented Nov 21, 2022

Hello. I have some issue. I have legasy app, which was made with using many iframes. But the main problem - many events links to the script in top frame by using window.top. We can't refactor this because app is very big and spagetting. ThereforeI I need to open app in separate window.

I try to use your commands for windows manipulation, but they works strange with my app:

  1. When i open use just cy.openWindow() without cy.visit(), Cypress dont see any elements on page.
  2. When use firstly cy.visit() and after that cy.openWindow(), Cypress see all elements, but interact only with new page (until I switch by cy.toggleWindows)
  3. When i change page in new window (after login) Cypress dont see new elements.

Looks like Cypress find and interact just with elements in main window and in new window just shows results of interactions.

What can i do to get arount problem with using window.top in my app?

Hey, sorry, I just saw i missed your message. In case it's still helpful for you or someone who stumbles on this page in the future, please check out my example here https://github.com/jakedowns/CypressHelpers/blob/master/tab_window_switching_test.cy.js

It works by assigning a "tab_name" to the root page and the page opened by window.open, therefore allowing you to switch contexts back and forth between the opened window and to original "root" page

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment