Skip to content

Commit

Permalink
chore: [Multi-domain] add retry error message for cross domain comman…
Browse files Browse the repository at this point in the history
…ds (#20835)

* chore: [Multi-domain]: add retry error message for cross domain commands

* fix a couple of merge bugs

* this change is for a different pr

* If no autOrigin is defined, don't add the additional message.

* ensure we're checking if the origin policies are the same.

Co-authored-by: Bill Glesias <bglesias@gmail.com>
  • Loading branch information
mjhenkes and AtofStryker committed Mar 30, 2022
1 parent b77f675 commit 9098744
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ describe('errors', { experimentalSessionSupport: true }, () => {
it('never redirects to the subdomain', { defaultCommandTimeout: 50 }, (done) => {
cy.on('fail', (err) => {
expect(err.message).to.include(`Timed out retrying after 50ms: Expected to find element: \`[data-cy="username"]\`, but never found it`)
expect(err.message).to.include(`The command was expected to run against origin: \`http://idp.com:3500\` but the application is at origin: \`http://localhost:3500\`.`)
// make sure that the secondary domain failures do NOT show up as spec failures or AUT failures
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 @@ -309,6 +310,7 @@ describe('errors', { experimentalSessionSupport: true }, () => {
it('never returns to the primary domain', { defaultCommandTimeout: 50 }, (done) => {
cy.on('fail', (err) => {
expect(err.message).to.include(`Timed out retrying after 50ms: Expected to find element: \`[data-cy="welcome"]\`, but never found it`)
expect(err.message).to.include(`The command was expected to run against origin: \`http://localhost:3500\` but the application is at origin: \`http://idp.com:3500\`.`)
// make sure that the secondary domain failures do NOT show up as spec failures or AUT failures
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 @@ -386,6 +388,7 @@ describe('errors', { experimentalSessionSupport: true }, () => {
it('fails in switchToDomain when a command is run after we return to localhost', { defaultCommandTimeout: 50 }, (done) => {
cy.on('fail', (err) => {
expect(err.message).to.include(`Timed out retrying after 50ms: Expected to find element: \`[data-cy="cannot_find"]\`, but never found it`)
expect(err.message).to.include(`The command was expected to run against origin: \`http://idp.com:3500\` but the application is at origin: \`http://localhost:3500\`.`)
// make sure that the secondary domain failures do NOT show up as spec failures or AUT failures
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 @@ -406,6 +409,23 @@ describe('errors', { experimentalSessionSupport: true }, () => {
.should('equal', 'Welcome BJohnson')
})

it('fails with a normal timeout', { defaultCommandTimeout: 50 }, (done) => {
cy.on('fail', (err) => {
expect(err.message).to.include(`Timed out retrying after 50ms: Expected to find element: \`[data-cy="cannot_find"]\`, but never found it`)
// make sure that the secondary domain failures do NOT show up as spec failures or AUT failures
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`)
expect(err.message).not.to.include(`The command was expected to run against origin:`)
done()
})

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="cannot_find"]') // Timeout here on command stability achieved by primary domain, this command times out.
})
})

describe('Pre established spec bridge', () => {
// These next three tests test and edge case where we want to prevent a load event from an established spec bridge that is not part of the test.
// This test removes the foobar spec bridge, navigates to idp, then navigates to foobar and attempts to access selectors on localhost.
Expand Down
1 change: 1 addition & 0 deletions packages/driver/src/cy/multi-domain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ export function addCommands (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy,
multiDomainBaseUrl: location.origin,
parentOrigins: [window.location.origin],
isStable: state('isStable'),
autOrigin: state('autOrigin'),
},
config: preprocessConfig(Cypress.config()),
env: preprocessEnv(Cypress.env()),
Expand Down
13 changes: 13 additions & 0 deletions packages/driver/src/cy/retries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import _ from 'lodash'
import Promise from 'bluebird'

import $errUtils from '../cypress/error_utils'
import * as cors from '@packages/network/lib/cors'

const { errByPath, modifyErrMsg, throwErr, mergeErrProps } = $errUtils

Expand Down Expand Up @@ -73,6 +74,18 @@ export const create = (Cypress, state, timeout, clearTimeout, whenStable, finish
}).message

const retryErrProps = modifyErrMsg(error, prependMsg, (msg1, msg2) => {
const autOrigin = Cypress.state('autOrigin')
const commandOrigin = window.location.origin

if (autOrigin && !cors.urlOriginsMatch(commandOrigin, autOrigin)) {
const appendMsg = errByPath('miscellaneous.cross_origin_command', {
commandOrigin,
autOrigin,
}).message

return `${msg2}${msg1}\n\n${appendMsg}`
}

return `${msg2}${msg1}`
})

Expand Down
5 changes: 4 additions & 1 deletion packages/driver/src/cypress/cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,10 @@ export class $Cy extends EventEmitter2 implements ITimeouts, IStability, IAssert
// not utilized
try {
this.Cypress.action('app:window:load', this.state('window'))
this.Cypress.multiDomainCommunicator.toAllSpecBridges('window:load', { url: this.getRemoteLocation('href') })
const remoteLocation = this.getRemoteLocation()

cy.state('autOrigin', remoteLocation.originPolicy)
this.Cypress.multiDomainCommunicator.toAllSpecBridges('window:load', { url: remoteLocation.href })

signalStable()
} catch (err: any) {
Expand Down
3 changes: 3 additions & 0 deletions packages/driver/src/cypress/error_messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,9 @@ export default {
retry_timed_out ({ ms }) {
return `Timed out retrying after ${ms}ms: `
},
cross_origin_command ({ commandOrigin, autOrigin }) {
return `The command was expected to run against origin: \`${commandOrigin }\` but the application is at origin: \`${autOrigin}\`.`
},
},

mocha: {
Expand Down
9 changes: 8 additions & 1 deletion packages/driver/src/multi-domain/cypress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { handleTestEvents } from './events/test'
import { handleMiscEvents } from './events/misc'
import { handleUnsupportedAPIs } from './unsupported_apis'
import $Mocha from '../cypress/mocha'
import * as cors from '@packages/network/lib/cors'

const createCypress = () => {
// @ts-ignore
Expand Down Expand Up @@ -97,6 +98,8 @@ const onBeforeAppWindowLoad = (Cypress: Cypress.Cypress, cy: $Cy) => (autWindow:

const onWindowLoadPrimary = ({ url }) => {
cy.isStable(true, 'primary onload')

cy.state('autOrigin', cors.getOriginPolicy(url))
Cypress.emit('internal:window:load', { type: 'cross:domain', url })
}

Expand Down Expand Up @@ -128,7 +131,11 @@ const onBeforeAppWindowLoad = (Cypress: Cypress.Cypress, cy: $Cy) => (autWindow:
// This is also call on the on 'load' event in cy
Cypress.action('app:window:load', autWindow)

Cypress.specBridgeCommunicator.toPrimary('window:load', { url: cy.getRemoteLocation('href') })
const remoteLocation = cy.getRemoteLocation()

cy.state('autOrigin', remoteLocation.originPolicy)

Cypress.specBridgeCommunicator.toPrimary('window:load', { url: remoteLocation.href })
cy.isStable(true, 'load')

// If load happened in this spec bridge stop listening.
Expand Down
1 change: 1 addition & 0 deletions packages/runner-shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"@cypress/design-system": "0.0.0-development",
"@cypress/react-tooltip": "0.5.3",
"@packages/driver": "0.0.0-development",
"@packages/network": "0.0.0-development",
"@packages/socket": "0.0.0-development",
"@packages/web-config": "0.0.0-development",
"@popperjs/core": "2.9.2",
Expand Down
2 changes: 2 additions & 0 deletions packages/runner-shared/src/event-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { logger } from './logger'
import { selectorPlaygroundModel } from './selector-playground'

import $Cypress from '@packages/driver'
import * as cors from '@packages/network/lib/cors'

const $ = $Cypress.$
const ws = client.connect({
Expand Down Expand Up @@ -537,6 +538,7 @@ export const eventManager = {
// established spec bridge, but one that is not the current or next switchToDomain command.
if (cy.state('latestActiveDomain') === domain) {
// We remain in an anticipating state until either a load even happens or a timeout.
cy.state('autOrigin', cy.state('autOrigin', cors.getOriginPolicy(url)))
cy.isAnticipatingMultiDomainFor(undefined)
cy.isStable(true, 'load')
// Prints out the newly loaded URL
Expand Down

0 comments on commit 9098744

Please sign in to comment.