diff --git a/packages/driver/cypress/fixtures/auth/delayedNavigate.html b/packages/driver/cypress/fixtures/auth/delayedNavigate.html new file mode 100644 index 000000000000..0367ba084248 --- /dev/null +++ b/packages/driver/cypress/fixtures/auth/delayedNavigate.html @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/driver/cypress/integration/e2e/multi-domain/navigation_spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/navigation_spec.ts index 9471413a699a..892acfdefafd 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/navigation_spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/navigation_spec.ts @@ -198,3 +198,42 @@ describe('navigation events', { experimentalSessionSupport: true }, () => { }) }) }) + +// @ts-ignore / session support is needed for visiting about:blank between tests +describe('delayed navigation', { experimentalSessionSupport: true, defaultCommandTimeout: 2000 }, () => { + it('localhost -> localhost', () => { + cy.visit('/fixtures/auth/delayedNavigate.html') + cy.get('[data-cy="to-localhost"]').click() + cy.get('[data-cy="login-idp"]') + }) + + it('localhost -> foobar, delay in', () => { + cy.visit('/fixtures/auth/delayedNavigate.html') + cy.get('[data-cy="to-foobar"]').click() + cy.switchToDomain('http://foobar.com:3500', () => { + cy.get('[data-cy="login-idp"]') + }) + }) + + it('foobar -> localhost, delay out', () => { + cy.visit('/fixtures/auth/index.html') + cy.switchToDomain('http://foobar.com:3500', () => { + cy.visit('http://www.foobar.com:3500/fixtures/auth/delayedNavigate.html') + cy.get('[data-cy="to-localhost"]').click() + }) + + cy.get('[data-cy="login-idp"]') + }) + + it('foobar -> idp, delay out', () => { + cy.visit('/fixtures/auth/index.html') + cy.switchToDomain('http://foobar.com:3500', () => { + cy.visit('http://www.foobar.com:3500/fixtures/auth/delayedNavigate.html') + cy.get('[data-cy="to-idp"]').click() + }) + + cy.switchToDomain('http://idp.com:3500', () => { + cy.get('[data-cy="login-idp"]') + }) + }) +}) diff --git a/packages/driver/src/multi-domain/events/misc.ts b/packages/driver/src/multi-domain/events/misc.ts index e179025cb2b5..60d4c70522c0 100644 --- a/packages/driver/src/multi-domain/events/misc.ts +++ b/packages/driver/src/multi-domain/events/misc.ts @@ -19,4 +19,9 @@ export const handleMiscEvents = (Cypress: Cypress.Cypress, cy: $Cy) => { Cypress.on('url:changed', (url) => { Cypress.specBridgeCommunicator.toPrimary('url:changed', { url }) }) + + // Listen for any unload events in other domains, if any have unloaded we should also become unstable. + Cypress.specBridgeCommunicator.on('before:unload', () => { + cy.state('isStable', false) + }) } diff --git a/packages/runner-shared/src/event-manager.js b/packages/runner-shared/src/event-manager.js index 975d8a2e178b..4307e0aea789 100644 --- a/packages/runner-shared/src/event-manager.js +++ b/packages/runner-shared/src/event-manager.js @@ -522,6 +522,11 @@ export const eventManager = { Cypress.multiDomainCommunicator.toAllSpecBridges('test:before:run:async', ...args) }) + // Inform all spec bridges that the primary domain has begun to unload. + Cypress.on('window:before:unload', () => { + Cypress.multiDomainCommunicator.toAllSpecBridges('before:unload') + }) + Cypress.multiDomainCommunicator.on('window:load', ({ url }, domain) => { // Sync stable if the expected domain has loaded. // Only listen to window load events from the most recent secondary domain, This prevents nondeterminism in the case where we redirect to an already @@ -535,14 +540,12 @@ export const eventManager = { } }) - Cypress.multiDomainCommunicator.on('before:unload', (_unused, domain) => { + Cypress.multiDomainCommunicator.on('before:unload', () => { // We specifically don't call 'cy.isStable' here because we don't want to inject another load event. - // Only listen to window load events from the most recent secondary domain, This prevents nondeterminism in the case where we redirect to an already - // established spec bridge, but one that is not the current or next switchToDomain command. - if (cy.state('latestActiveDomain') === domain) { - // Unstable is unstable regardless of where it initiated from. - cy.state('isStable', false) - } + // Unstable is unstable regardless of where it initiated from. + cy.state('isStable', false) + // Re-broadcast to any other specBridges. + Cypress.multiDomainCommunicator.toAllSpecBridges('before:unload') }) Cypress.multiDomainCommunicator.on('expect:domain', (domain) => {