diff --git a/packages/driver/cypress/fixtures/multidomain-secondary.html b/packages/driver/cypress/fixtures/multidomain-secondary.html new file mode 100644 index 000000000000..96c47fdce12d --- /dev/null +++ b/packages/driver/cypress/fixtures/multidomain-secondary.html @@ -0,0 +1,14 @@ + + + + + +

+ + + + diff --git a/packages/driver/cypress/fixtures/multidomain.html b/packages/driver/cypress/fixtures/multidomain.html index 4b6cb59ca2f3..cd7428f2713e 100644 --- a/packages/driver/cypress/fixtures/multidomain.html +++ b/packages/driver/cypress/fixtures/multidomain.html @@ -3,6 +3,6 @@ - Go to 127.0.0.1:3501 + Go to 127.0.0.1:3501 diff --git a/packages/driver/cypress/integration/e2e/multidomain_spec.ts b/packages/driver/cypress/integration/e2e/multidomain_spec.ts index db320cb9a9ee..5581dbb69255 100644 --- a/packages/driver/cypress/integration/e2e/multidomain_spec.ts +++ b/packages/driver/cypress/integration/e2e/multidomain_spec.ts @@ -1,22 +1,23 @@ // FIXME: Skip this for now since it's flaky it.skip('verifies initial implementation of sibling iframe and switchToDomain', (done) => { top.addEventListener('message', (event) => { - if (event.data && event.data.text) { - expect(event.data.text).to.equal('Foo') + if (event.data && event.data.textFromParagraph !== undefined) { expect(event.data.host).to.equal('127.0.0.1:3501') + expect(event.data.textFromParagraph).to.equal('From a secondary domain with window.Cypress') done() } }, false) - cy.state('anticipateMultidomain', true) cy.viewport(900, 300) cy.visit('/fixtures/multidomain.html') + // @ts-ignore + cy.anticipateMultidomain() cy.get('a').click() // @ts-ignore cy.switchToDomain('127.0.0.1:3501', () => { // @ts-ignore - cy.now('get', '.foo').then(($el) => { - top.postMessage({ host: location.host, text: $el.text() }, '*') + cy.now('get', 'p').then(($el) => { + top.postMessage({ host: location.host, textFromParagraph: $el.text() }, '*') }) }) }) diff --git a/packages/driver/src/cy/multidomain/index.ts b/packages/driver/src/cy/multidomain/index.ts index 32cc6d85ca74..ee91a7539e04 100644 --- a/packages/driver/src/cy/multidomain/index.ts +++ b/packages/driver/src/cy/multidomain/index.ts @@ -1,5 +1,20 @@ +import Bluebird from 'bluebird' + export function addCommands (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy, state: Cypress.State) { Commands.addAll({ + anticipateMultidomain () { + state('anticipateMultidomain', true) + + return new Bluebird((resolve) => { + // @ts-ignore + Cypress.once('cross:domain:bridge:ready', () => { + resolve() + }) + + Cypress.action('cy:expect:domain', '127.0.0.1:3501') + }) + }, + switchToDomain (domain, fn) { Cypress.log({ name: 'switchToDomain', diff --git a/packages/driver/src/cypress.js b/packages/driver/src/cypress.js index 5c202ea6cdd8..c0845fe22be0 100644 --- a/packages/driver/src/cypress.js +++ b/packages/driver/src/cypress.js @@ -476,18 +476,6 @@ class $Cypress { case 'cy:scrolled': return this.emit('scrolled', ...args) - case 'app:cross:domain:window:load': - return this.emit('cross:domain:window:load', args[0]) - - case 'cy:switch:domain': - return this.emit('switch:domain', args[0]) - - case 'runner:cross:domain:driver:ready': - return this.emit('cross:domain:driver:ready') - - case 'cy:cross:domain:message': - return this.emit('cross:domain:message', ...args) - case 'app:uncaught:exception': return this.emitMap('uncaught:exception', ...args) @@ -535,6 +523,18 @@ class $Cypress { case 'spec:script:error': return this.emit('script:error', ...args) + // multidomain messages + // TODO: consider moving these elsewhere if they grow too + // large in number + case 'cy:expect:domain': + return this.emit('expect:domain', args[0]) + + case 'runner:cross:domain:bridge:ready': + return this.emit('cross:domain:bridge:ready') + + case 'cy:cross:domain:message': + return this.emit('cross:domain:message', ...args) + default: return } diff --git a/packages/driver/src/cypress/cy.js b/packages/driver/src/cypress/cy.js index a0a30325d86c..aa8eb17928c9 100644 --- a/packages/driver/src/cypress/cy.js +++ b/packages/driver/src/cypress/cy.js @@ -1054,15 +1054,7 @@ const create = function (specWindow, Cypress, Cookies, state, config, log) { // temporary hack so that other tests expecting cross-origin // failures still fail as expected if (state('anticipateMultidomain')) { - Cypress.once('cross:domain:window:load', () => { - Cypress.once('cross:domain:driver:ready', () => { - stability.isStable(true, 'load') - }) - - Cypress.action('cy:switch:domain', '127.0.0.1:3501') - }) - - return + return stability.isStable(true, 'load') } let e = err diff --git a/packages/driver/src/multidomain/index.js b/packages/driver/src/multidomain/index.js index 03d226350250..0b5ff8729ecc 100644 --- a/packages/driver/src/multidomain/index.js +++ b/packages/driver/src/multidomain/index.js @@ -3,7 +3,7 @@ import $Cy from '../cypress/cy' import $Commands from '../cypress/commands' import $Log from '../cypress/log' -export const initialize = (autWindow) => { +const onBeforeAppWindowLoad = (autWindow) => { const specWindow = { Error, } @@ -50,11 +50,12 @@ export const initialize = (autWindow) => { } }, false) - top.postMessage('cross:domain:driver:ready', '*') - + autWindow.Cypress = Cypress autWindow.cy = cy - return { - cy, - } + top.postMessage('cross:domain:window:before:load', '*') } + +window.__onBeforeAppWindowLoad = onBeforeAppWindowLoad + +top.postMessage('cross:domain:bridge:ready', '*') diff --git a/packages/runner-shared/src/event-manager.js b/packages/runner-shared/src/event-manager.js index 1201f0b22ed9..e387b47cfad9 100644 --- a/packages/runner-shared/src/event-manager.js +++ b/packages/runner-shared/src/event-manager.js @@ -25,7 +25,7 @@ const driverToReporterEvents = 'paused before:firefox:force:gc after:firefox:for const driverToLocalAndReporterEvents = 'run:start run:end'.split(' ') const driverToSocketEvents = 'backend:request automation:request mocha recorder:frame'.split(' ') const driverTestEvents = 'test:before:run:async test:after:run'.split(' ') -const driverToLocalEvents = 'viewport:changed config stop url:changed page:loading visit:failed switch:domain'.split(' ') +const driverToLocalEvents = 'viewport:changed config stop url:changed page:loading visit:failed expect:domain'.split(' ') const socketRerunEvents = 'runner:restart watched:file:changed'.split(' ') const socketToDriverEvents = 'net:event script:error'.split(' ') const localToReporterEvents = 'reporter:log:add reporter:log:state:changed reporter:log:remove'.split(' ') @@ -303,15 +303,15 @@ export const eventManager = { top.addEventListener('message', (event) => { switch (event.data) { - case 'app:cross:domain:window:load': - return Cypress.action('app:cross:domain:window:load') - case 'cross:domain:driver:ready': + case 'cross:domain:window:before:load': this.crossDomainDriverWindow = event.source - return Cypress.action('runner:cross:domain:driver:ready') + return + case 'cross:domain:bridge:ready': + return Cypress.action('runner:cross:domain:bridge:ready') default: // eslint-disable-next-line no-console - console.log('Unknown postMessage:', event.data) + console.log('Unexpected postMessage:', event.data) } }, false) }, diff --git a/packages/runner/injection/multidomain.js b/packages/runner/injection/multidomain.js index 92c122fe834d..69e10121ffd4 100644 --- a/packages/runner/injection/multidomain.js +++ b/packages/runner/injection/multidomain.js @@ -33,8 +33,9 @@ // timers.wrap() -// TODO: change this to be window:before:load once coordination with -// driver is fleshed out better -window.addEventListener('load', () => { - window.top.postMessage('app:cross:domain:window:load', '*') -}) +// TODO: don't hard-code the index. need it to be predictable or need +// to search for the right one somehow. will need to be fixed when we +// test out visiting a 3rd domain +const cyBridgeFrame = window.parent.frames[2] + +cyBridgeFrame.__onBeforeAppWindowLoad(window) diff --git a/packages/runner/multidomain/index.js b/packages/runner/multidomain/index.js index f77fe8efd366..bdf19ee12a87 100644 --- a/packages/runner/multidomain/index.js +++ b/packages/runner/multidomain/index.js @@ -1,24 +1 @@ -import { initialize } from '@packages/driver/src/multidomain' - -initialize(window.parent.frames[0]) - -/* - -Need: -- Cypress -- cy, with - - built-in commands - - user-defined commands - -Commands need: -- state -- config -- events - -Don't need: -- UI components -- spec runner -- mocha -- wasm / source map utils - -*/ +import '@packages/driver/src/multidomain' diff --git a/packages/runner/src/iframe/iframes.jsx b/packages/runner/src/iframe/iframes.jsx index f7a0b97da022..87c50e575050 100644 --- a/packages/runner/src/iframe/iframes.jsx +++ b/packages/runner/src/iframe/iframes.jsx @@ -91,7 +91,7 @@ export default class Iframes extends Component { this.props.eventManager.on('print:selector:elements:to:console', this._printSelectorElementsToConsole) - this.props.eventManager.on('switch:domain', this._addCrossDomainIframe) + this.props.eventManager.on('expect:domain', this._addCrossDomainIframe) this._disposers.push(autorun(() => { this.autIframe.toggleSelectorPlayground(selectorPlaygroundModel.isEnabled)