Skip to content

Commit

Permalink
chore: [Multi-domain]: Support spec bridges with same domain (#20829)
Browse files Browse the repository at this point in the history
* chore: [Multi-domain]: Support spec bridges with same domain

* Add a little test

* Fix spec bridge tests

* make sure we grab the origin policy

* Update tests and origin policy

* moving tests

Co-authored-by: Bill Glesias <bglesias@gmail.com>
  • Loading branch information
mjhenkes and AtofStryker committed Mar 31, 2022
1 parent 8c9bd2a commit b3e66e7
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 101 deletions.
Expand Up @@ -227,52 +227,3 @@ describe('multi-domain', { experimentalSessionSupport: true }, () => {
})
})
})

// @ts-ignore
describe('domain validation', { experimentalSessionSupport: true }, () => {
it('finds the right spec bridge with a subdomain', () => {
cy.visit('/fixtures/auth/index.html') // Establishes Primary Domain
cy.window().then((win) => {
win.location.href = 'http://baz.foobar.com:3500/fixtures/auth/idp.html'
})

cy.switchToDomain('http://foobar.com:3500', () => {
cy.get('[data-cy="username"]').type('TJohnson')
cy.get('[data-cy="login"]').click()
})

cy.get('[data-cy="welcome"]')
.invoke('text')
.should('equal', 'Welcome TJohnson')
})

it('uses switchToDomain twice', () => {
cy.visit('/fixtures/auth/index.html') // Establishes Primary Domain
cy.get('[data-cy="login-idp"]').click() // Takes you to idp.com
cy.switchToDomain('http://idp.com:3500', () => {
cy.get('[data-cy="username"]').type('BJohnson')
cy.get('[data-cy="login"]').click()
}) // Trailing edge wait, waiting to return to the primary domain

// Verify that the user has logged in on /siteA
cy.get('[data-cy="welcome"]')
.invoke('text')
.should('equal', 'Welcome BJohnson')

cy.get('[data-cy="logout"]').click()

cy.window().then((win) => {
win.location.href = 'http://baz.foobar.com:3500/fixtures/auth/idp.html'
})

cy.switchToDomain('http://foobar.com:3500', () => {
cy.get('[data-cy="username"]').type('TJohnson')
cy.get('[data-cy="login"]').click()
}) // Trailing edge wait, waiting to return to the primary domain

// Verify that the user has logged in on /siteA
cy.get('[data-cy="welcome"]')
.invoke('text')
.should('equal', 'Welcome TJohnson')
})
})
Expand Up @@ -5,7 +5,7 @@ describe('multi-domain', { experimentalSessionSupport: true }, () => {
cy.switchToDomain('localhost', () => undefined)
cy.then(() => {
const expectedSrc = `https://localhost/__cypress/multi-domain-iframes`
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ localhost') as HTMLIFrameElement
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ https://localhost') as HTMLIFrameElement

expect(iframe.src).to.equal(expectedSrc)
})
Expand All @@ -15,7 +15,7 @@ describe('multi-domain', { experimentalSessionSupport: true }, () => {
cy.switchToDomain('127.0.0.1', () => undefined)
cy.then(() => {
const expectedSrc = `https://127.0.0.1/__cypress/multi-domain-iframes`
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ 127.0.0.1') as HTMLIFrameElement
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ https://127.0.0.1') as HTMLIFrameElement

expect(iframe.src).to.equal(expectedSrc)
})
Expand All @@ -26,7 +26,7 @@ describe('multi-domain', { experimentalSessionSupport: true }, () => {
cy.switchToDomain('0000:0000:0000:0000:0000:0000:0000:0001', () => undefined)
cy.then(() => {
const expectedSrc = `https://[::1]/__cypress/multi-domain-iframes`
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ [::1]') as HTMLIFrameElement
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ https://[::1]') as HTMLIFrameElement

expect(iframe.src).to.equal(expectedSrc)
})
Expand All @@ -36,7 +36,7 @@ describe('multi-domain', { experimentalSessionSupport: true }, () => {
cy.switchToDomain('はじめよう.みんな', () => undefined)
cy.then(() => {
const expectedSrc = `https://xn--p8j9a0d9c9a.xn--q9jyb4c/__cypress/multi-domain-iframes`
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ xn--p8j9a0d9c9a.xn--q9jyb4c') as HTMLIFrameElement
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ https://xn--p8j9a0d9c9a.xn--q9jyb4c') as HTMLIFrameElement

expect(iframe.src).to.equal(expectedSrc)
})
Expand All @@ -46,7 +46,7 @@ describe('multi-domain', { experimentalSessionSupport: true }, () => {
cy.switchToDomain('http://foobar1.com:3500', () => {})
cy.then(() => {
const expectedSrc = `http://foobar1.com:3500/__cypress/multi-domain-iframes`
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ foobar1.com') as HTMLIFrameElement
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ http://foobar1.com:3500') as HTMLIFrameElement

expect(iframe.src).to.equal(expectedSrc)
})
Expand All @@ -56,7 +56,7 @@ describe('multi-domain', { experimentalSessionSupport: true }, () => {
cy.switchToDomain('https://foobar2.com:3500', () => {})
cy.then(() => {
const expectedSrc = `https://foobar2.com:3500/__cypress/multi-domain-iframes`
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ foobar2.com') as HTMLIFrameElement
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ https://foobar2.com:3500') as HTMLIFrameElement

expect(iframe.src).to.equal(expectedSrc)
})
Expand All @@ -66,7 +66,7 @@ describe('multi-domain', { experimentalSessionSupport: true }, () => {
cy.switchToDomain('foobar3.com:3500', () => {})
cy.then(() => {
const expectedSrc = `https://foobar3.com:3500/__cypress/multi-domain-iframes`
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ foobar3.com') as HTMLIFrameElement
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ https://foobar3.com:3500') as HTMLIFrameElement

expect(iframe.src).to.equal(expectedSrc)
})
Expand All @@ -76,7 +76,7 @@ describe('multi-domain', { experimentalSessionSupport: true }, () => {
cy.switchToDomain('http://foobar4.com', () => {})
cy.then(() => {
const expectedSrc = `http://foobar4.com/__cypress/multi-domain-iframes`
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ foobar4.com') as HTMLIFrameElement
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ http://foobar4.com') as HTMLIFrameElement

expect(iframe.src).to.equal(expectedSrc)
})
Expand All @@ -86,7 +86,7 @@ describe('multi-domain', { experimentalSessionSupport: true }, () => {
cy.switchToDomain('app.foobar5.com', () => {})
cy.then(() => {
const expectedSrc = `https://foobar5.com/__cypress/multi-domain-iframes`
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ foobar5.com') as HTMLIFrameElement
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ https://foobar5.com') as HTMLIFrameElement

expect(iframe.src).to.equal(expectedSrc)
})
Expand All @@ -96,7 +96,7 @@ describe('multi-domain', { experimentalSessionSupport: true }, () => {
cy.switchToDomain('foobar6.com', () => undefined)
cy.then(() => {
const expectedSrc = `https://foobar6.com/__cypress/multi-domain-iframes`
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ foobar6.com') as HTMLIFrameElement
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ https://foobar6.com') as HTMLIFrameElement

expect(iframe.src).to.equal(expectedSrc)
})
Expand All @@ -106,7 +106,7 @@ describe('multi-domain', { experimentalSessionSupport: true }, () => {
cy.switchToDomain('app.foobar.herokuapp.com', () => {})
cy.then(() => {
const expectedSrc = `https://foobar.herokuapp.com/__cypress/multi-domain-iframes`
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ foobar.herokuapp.com') as HTMLIFrameElement
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ https://foobar.herokuapp.com') as HTMLIFrameElement

expect(iframe.src).to.equal(expectedSrc)
})
Expand All @@ -116,11 +116,73 @@ describe('multi-domain', { experimentalSessionSupport: true }, () => {
cy.switchToDomain('machine-name', () => undefined)
cy.then(() => {
const expectedSrc = `https://machine-name/__cypress/multi-domain-iframes`
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ machine-name') as HTMLIFrameElement
const iframe = window.top?.document.getElementById('Spec\ Bridge:\ https://machine-name') as HTMLIFrameElement

expect(iframe.src).to.equal(expectedSrc)
})
})

it('finds the right spec bridge with a subdomain', () => {
cy.visit('/fixtures/auth/index.html') // Establishes Primary Domain
cy.window().then((win) => {
win.location.href = 'http://baz.foobar.com:3500/fixtures/auth/idp.html'
})

cy.switchToDomain('http://foobar.com:3500', () => {
cy.get('[data-cy="username"]').type('TJohnson')
cy.get('[data-cy="login"]').click()
})

cy.get('[data-cy="welcome"]')
.invoke('text')
.should('equal', 'Welcome TJohnson')
})

it('uses switchToDomain twice', () => {
cy.visit('/fixtures/auth/index.html') // Establishes Primary Domain
cy.get('[data-cy="login-idp"]').click() // Takes you to idp.com
cy.switchToDomain('http://idp.com:3500', () => {
cy.get('[data-cy="username"]').type('BJohnson')
cy.get('[data-cy="login"]').click()
}) // Trailing edge wait, waiting to return to the primary domain

// Verify that the user has logged in on /siteA
cy.get('[data-cy="welcome"]')
.invoke('text')
.should('equal', 'Welcome BJohnson')

cy.get('[data-cy="logout"]').click()

cy.window().then((win) => {
win.location.href = 'http://baz.foobar.com:3500/fixtures/auth/idp.html'
})

cy.switchToDomain('http://foobar.com:3500', () => {
cy.get('[data-cy="username"]').type('TJohnson')
cy.get('[data-cy="login"]').click()
}) // Trailing edge wait, waiting to return to the primary domain

// Verify that the user has logged in on /siteA
cy.get('[data-cy="welcome"]')
.invoke('text')
.should('equal', 'Welcome TJohnson')
})

it('creates a spec bridge for https://idp.com:3502', () => {
cy.visit('/fixtures/auth/index.html') // Establishes Primary Domain
cy.switchToDomain('idp.com:3502', () => {
cy.visit('https://www.idp.com:3502/fixtures/auth/index.html')
cy.get('[data-cy="login-idp"]').invoke('text').should('equal', 'Login IDP')
})
})

it('creates a spec bridge for http://idp.com:3500', () => {
cy.visit('/fixtures/auth/index.html') // Establishes Primary Domain
cy.switchToDomain('http://idp.com:3500', () => {
cy.visit('http://www.idp.com:3500/fixtures/auth/index.html')
cy.get('[data-cy="login-idp"]').invoke('text').should('equal', 'Login IDP')
})
})
})

describe('errors', () => {
Expand Down
Expand Up @@ -247,7 +247,7 @@ describe('errors', { experimentalSessionSupport: true }, () => {
expect(err.message).to.include(`Your page did not fire its \`load\` event within \`5000ms\`.`)
expect(err.message).to.include(`A cross origin request for \`http://www.foobar.com:3500/fixtures/auth/idp.html?redirect=http%3A%2F%2Flocalhost%3A3500%2Ffixtures%2Fauth%2Findex.html\` was detected.`)
expect(err.message).to.include(`A command that triggers cross origin navigation must be immediately followed by a \`cy.switchToDomain()\` command:`)
expect(err.message).to.include(`\`\ncy.switchToDomain(\'http://www.foobar.com:3500\', () => {\n <commands targeting http://www.foobar.com:3500 go here>\n})\n\``)
expect(err.message).to.include(`\`\ncy.switchToDomain(\'http://foobar.com:3500\', () => {\n <commands targeting http://www.foobar.com:3500 go here>\n})\n\``)
expect(err.message).to.include(`If the cross origin request was an intermediary state, you can try increasing the \`pageLoadTimeout\` value in \`cypress.json\` to wait longer`)

expect(err.message).not.to.include(`The following error originated from your test code, not from Cypress`)
Expand Down Expand Up @@ -285,9 +285,9 @@ describe('errors', { experimentalSessionSupport: true }, () => {
it('redirects to the wrong subdomain', { pageLoadTimeout: 5000 }, (done) => {
cy.on('fail', (err) => {
expect(err.message).to.include(`Timed out after waiting \`5000ms\` for your remote page to load on origin(s):`)
expect(err.message).to.include(`\n- \`idp.com\`\n`)
expect(err.message).to.include(`\n- \`http://idp.com:3500\`\n`)
expect(err.message).to.include(`A cross origin request for \`http://www.foobar.com:3500/fixtures/auth/idp.html?redirect=http%3A%2F%2Flocalhost%3A3500%2Ffixtures%2Fauth%2Findex.html\` was detected.`)
expect(err.message).to.include(`\`\ncy.switchToDomain(\'http://www.foobar.com:3500\', () => {\n <commands targeting http://www.foobar.com:3500 go here>\n})\n\``)
expect(err.message).to.include(`\`\ncy.switchToDomain(\'http://foobar.com:3500\', () => {\n <commands targeting http://www.foobar.com:3500 go here>\n})\n\``)

expect(err.message).not.to.include(`The following error originated from your test code, not from Cypress`)
expect(err.message).not.to.include(`The following error originated from your application code, not from Cypress`)
Expand Down Expand Up @@ -334,7 +334,7 @@ describe('errors', { experimentalSessionSupport: true }, () => {
expect(err.message).to.include(`Timed out after waiting \`5000ms\` for your remote page to load on origin(s):`)
expect(err.message).to.include(`\n- \`http://localhost:3500\`\n`)
expect(err.message).to.include(`A cross origin request for \`http://www.foobar.com:3500/fixtures/auth/index.html\` was detected.`)
expect(err.message).to.include(`\`\ncy.switchToDomain(\'http://www.foobar.com:3500\', () => {\n <commands targeting http://www.foobar.com:3500 go here>\n})\n\``)
expect(err.message).to.include(`\`\ncy.switchToDomain(\'http://foobar.com:3500\', () => {\n <commands targeting http://www.foobar.com:3500 go here>\n})\n\``)

expect(err.message).not.to.include(`The following error originated from your test code, not from Cypress`)
expect(err.message).not.to.include(`The following error originated from your application code, not from Cypress`)
Expand All @@ -361,7 +361,7 @@ describe('errors', { experimentalSessionSupport: true }, () => {
expect(err.message).to.include(`Timed out after waiting \`5000ms\` for your remote page to load on origin(s):`)
expect(err.message).to.include(`\n- \`http://idp.com:3500\`\n`)
expect(err.message).to.include(`A cross origin request for \`http://www.foobar.com:3500/fixtures/auth/index.html\` was detected.`)
expect(err.message).to.include(`\`\ncy.switchToDomain(\'http://www.foobar.com:3500\', () => {\n <commands targeting http://www.foobar.com:3500 go here>\n})\n\``)
expect(err.message).to.include(`\`\ncy.switchToDomain(\'http://foobar.com:3500\', () => {\n <commands targeting http://www.foobar.com:3500 go here>\n})\n\``)

expect(err.message).not.to.include(`The following error originated from your test code, not from Cypress`)
expect(err.message).not.to.include(`The following error originated from your application code, not from Cypress`)
Expand Down Expand Up @@ -434,7 +434,7 @@ describe('errors', { experimentalSessionSupport: true }, () => {
expect(err.message).to.include(`Timed out after waiting \`5000ms\` for your remote page to load on origin(s):`)
expect(err.message).to.include(`\n- \`http://localhost:3500\`\n`)
expect(err.message).to.include(`A cross origin request for \`http://www.foobar.com:3500/fixtures/auth/index.html\` was detected.`)
expect(err.message).to.include(`\`\ncy.switchToDomain(\'http://www.foobar.com:3500\', () => {\n <commands targeting http://www.foobar.com:3500 go here>\n})\n\``)
expect(err.message).to.include(`\`\ncy.switchToDomain(\'http://foobar.com:3500\', () => {\n <commands targeting http://www.foobar.com:3500 go here>\n})\n\``)

expect(err.message).not.to.include(`The following error originated from your test code, not from Cypress`)
expect(err.message).not.to.include(`The following error originated from your application code, not from Cypress`)
Expand Down Expand Up @@ -483,7 +483,7 @@ describe('errors', { experimentalSessionSupport: true }, () => {
expect(err.message).to.include(`Timed out after waiting \`5000ms\` for your remote page to load on origin(s):`)
expect(err.message).to.include(`\n- \`http://localhost:3500\`\n`)
expect(err.message).to.include(`A cross origin request for \`http://www.foobar.com:3500/fixtures/auth/index.html\` was detected.`)
expect(err.message).to.include(`\`\ncy.switchToDomain(\'http://www.foobar.com:3500\', () => {\n <commands targeting http://www.foobar.com:3500 go here>\n})\n\``)
expect(err.message).to.include(`\`\ncy.switchToDomain(\'http://foobar.com:3500\', () => {\n <commands targeting http://www.foobar.com:3500 go here>\n})\n\``)

expect(err.message).not.to.include(`The following error originated from your test code, not from Cypress`)
expect(err.message).not.to.include(`The following error originated from your application code, not from Cypress`)
Expand Down
4 changes: 2 additions & 2 deletions packages/driver/src/cy/commands/navigation.ts
Expand Up @@ -58,7 +58,7 @@ const timedOutWaitingForPageLoad = (ms, log) => {
cy.isAnticipatingMultiDomainFor(undefined)

// By default origins is just this location.
let origins = [location.origin]
let origins = [$Location.create(location.href).originPolicy]

const currentCommand = cy.queue.state('current')

Expand All @@ -74,7 +74,7 @@ const timedOutWaitingForPageLoad = (ms, log) => {
args: {
configFile: Cypress.config('configFile'),
ms,
crossOriginUrl: new URL(anticipatedCrossOriginHref),
crossOriginUrl: $Location.create(anticipatedCrossOriginHref),
origins,
},
onFail: log,
Expand Down
12 changes: 6 additions & 6 deletions packages/driver/src/cy/multi-domain/index.ts
Expand Up @@ -93,9 +93,9 @@ export function addCommands (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy,

validator.validateLocation(location, originOrDomain)

const domain = location.superDomain
const originPolicy = location.originPolicy

cy.state('latestActiveDomain', domain)
cy.state('latestActiveDomain', originPolicy)

return new Bluebird((resolve, reject, onCancel) => {
const cleanup = () => {
Expand Down Expand Up @@ -172,17 +172,17 @@ export function addCommands (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy,

// fired once the spec bridge is set up and ready to receive messages
communicator.once('bridge:ready', (_data, bridgeReadyDomain) => {
if (bridgeReadyDomain === domain) {
if (bridgeReadyDomain === originPolicy) {
// now that the spec bridge is ready, instantiate Cypress with the current app config and environment variables for initial sync when creating the instance
communicator.toSpecBridge(domain, 'initialize:cypress', {
communicator.toSpecBridge(originPolicy, 'initialize:cypress', {
config: preprocessConfig(Cypress.config()),
env: preprocessEnv(Cypress.env()),
})

// once the secondary domain page loads, send along the
// user-specified callback to run in that domain
try {
communicator.toSpecBridge(domain, 'run:domain:fn', {
communicator.toSpecBridge(originPolicy, 'run:domain:fn', {
args: options?.args || undefined,
fn: callbackFn.toString(),
// let the spec bridge version of Cypress know if config read-only values can be overwritten since window.top cannot be accessed in cross-origin iframes
Expand All @@ -197,7 +197,7 @@ export function addCommands (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy,
hookId: state('hookId'),
hasVisitedAboutBlank: state('hasVisitedAboutBlank'),
multiDomainBaseUrl: location.origin,
parentOrigins: [window.location.origin],
parentOrigins: [cy.getRemoteLocation('originPolicy')],
isStable: state('isStable'),
autOrigin: state('autOrigin'),
},
Expand Down

2 comments on commit b3e66e7

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on b3e66e7 Mar 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/9.6.0/linux-x64/feature-multidomain-b3e66e79ab1217dc353022d2a303538fb863337e/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on b3e66e7 Mar 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/9.6.0/darwin-x64/feature-multidomain-b3e66e79ab1217dc353022d2a303538fb863337e/cypress.tgz

Please sign in to comment.