Skip to content

Commit

Permalink
chore: Convert multi-domain file to TS and rename for consistency (#1…
Browse files Browse the repository at this point in the history
…9601)

* WIP: multi domain refactor event bus

* refactor multidomain setup so cy/cypress are created once and not on every page load

* use unique ids per origin for logs instead of trying to sync the counter

* refactor postMessage/eventBus methods into the multidomain communicator to consolidate messaging logic. Add basic JSDocs to classes and methods within the communicator.

* fix issue where event data being fed into the message listener is undefined

* remove forgot about commented out code

* use debug to log unexpected post messages

* refactor and update types

* move internal:window:load to internal types

* accept data argument in switchToDomain and validate arguments

* add experimentalMultiDomain flag and fail switchToDomain if not enabled

* add types for switchToDomain

* fix types

* add experimental flag

* remove comment

* update config suite titles and snapshots

* use message in error, update test for browser family

* remove unnecessary return

* convert src/multidomain/index.js to typescript

* use consistent naming for multi-domain

* remove some data

* Multidomain -> MultiDomain

* address PR feedback

Co-authored-by: Bill Glesias <bglesias@gmail.com>
  • Loading branch information
chrisbreiding and AtofStryker authored Jan 11, 2022
1 parent 7735c61 commit 7bce51a
Show file tree
Hide file tree
Showing 32 changed files with 105 additions and 89 deletions.
11 changes: 10 additions & 1 deletion cli/types/cypress.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ declare namespace Cypress {
* Trigger action
* @private
*/
action: (action: string, ...args: any[]) => void
action: (action: string, ...args: any[]) => any[] | void

/**
* Load files
Expand Down Expand Up @@ -5567,6 +5567,12 @@ declare namespace Cypress {
* @see https://on.cypress.io/catalog-of-events#App-Events
*/
(action: 'command:end', fn: (command: CommandQueue) => void): Cypress
/**
* Fires when a command is skipped, namely the `should` command.
* Useful for debugging and understanding how commands are handled.
* @see https://on.cypress.io/catalog-of-events#App-Events
*/
(action: 'skipped:command:end', fn: (command: CommandQueue) => void): Cypress
/**
* Fires whenever a command begins its retrying routines.
* This is called on the trailing edge after Cypress has internally
Expand Down Expand Up @@ -5657,10 +5663,13 @@ declare namespace Cypress {
}

interface EnqueuedCommand {
id: string
name: string
args: any[]
type: string
chainerId: string
injected: boolean
userInvocationStack?: string
fn(...args: any[]): any
}

Expand Down
8 changes: 8 additions & 0 deletions packages/driver/cypress/fixtures/multi-domain.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<a href="http://www.foobar.com:3500/fixtures/multi-domain-secondary.html">Go to different domain</a>
</body>
</html>
8 changes: 0 additions & 8 deletions packages/driver/cypress/fixtures/multidomain.html

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// @ts-ignore
describe('multidomain - rerun', { experimentalMultiDomain: true }, () => {
describe('multi-domain - rerun', { experimentalMultiDomain: true }, () => {
beforeEach(() => {
cy.visit('/fixtures/multidomain.html')
cy.visit('/fixtures/multi-domain.html')
cy.get('a').click()
})

// this test will hang without the fix for multidomain rerun
// this test will hang without the fix for multi-domain rerun
// https://github.com/cypress-io/cypress/issues/18043
it('successfully reruns tests', () => {
// @ts-ignore
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-ignore / session support is needed for visiting about:blank between tests
describe('multidomain', { experimentalSessionSupport: true, experimentalMultiDomain: true }, () => {
describe('multi-domain', { experimentalSessionSupport: true, experimentalMultiDomain: true }, () => {
const expectTextMessage = (expected, done) => {
const onMessage = (event) => {
if (event.data && event.data.actual !== undefined) {
Expand All @@ -16,7 +16,7 @@ describe('multidomain', { experimentalSessionSupport: true, experimentalMultiDom
}

beforeEach(() => {
cy.visit('/fixtures/multidomain.html')
cy.visit('/fixtures/multi-domain.html')
cy.get('a').click()
})

Expand Down Expand Up @@ -165,7 +165,7 @@ describe('multidomain', { experimentalSessionSupport: true, experimentalMultiDom
})

cy.window().then((window) => {
window.location.href = '/fixtures/multidomain.html'
window.location.href = '/fixtures/multi-domain.html'
})
})
})
Expand All @@ -181,7 +181,7 @@ describe('multidomain', { experimentalSessionSupport: true, experimentalMultiDom
})

cy.window().then((window) => {
window.location.href = '/fixtures/multidomain.html'
window.location.href = '/fixtures/multi-domain.html'
})
})
})
Expand Down
4 changes: 2 additions & 2 deletions packages/driver/cypress/plugins/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,9 @@ const createApp = (port) => {
.send('<html><body>server error</body></html>')
})

app.get('/cypress_multidomain_runner.js', (req, res) => {
app.get('/cypress_multi_domain_runner.js', (req, res) => {
res.type('application/javascript')
res.sendFile(getPathToDist('runner', 'cypress_multidomain_runner.js'))
res.sendFile(getPathToDist('runner', 'cypress_multi_domain_runner.js'))
})

let _var = ''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ export function addCommands (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy,
// will not continue until the page is stable, but this signals it to go
// ahead because we're anticipating multi-domain
// @ts-ignore
cy.isAnticipatingMultidomain(true)
cy.isAnticipatingMultiDomain(true)

// cy.isAnticipatingMultidomain(true) will free the queue to move forward.
// cy.isAnticipatingMultiDomain(true) will free the queue to move forward.
// if the next command isn't switchToDomain, this timeout will hit and
// the test will fail with a cross-origin error
timeoutId = setTimeout(() => {
Expand Down Expand Up @@ -137,7 +137,7 @@ 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', () => {
state('readyForMultidomain', true)
state('readyForMultiDomain', true)
// let the proxy know to let the response for the secondary
// domain html through, so the page will finish loading
Cypress.backend('ready:for:domain', { shouldInject: true })
Expand All @@ -162,7 +162,7 @@ export function addCommands (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy,
} finally {
state('readyForMultidomain', false)
// @ts-ignore
cy.isAnticipatingMultidomain(false)
cy.isAnticipatingMultiDomain(false)
}
})

Expand Down
20 changes: 10 additions & 10 deletions packages/driver/src/cy/stability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,22 @@ export const create = (Cypress, state) => ({
})
},

isAnticipatingMultidomain (anticipating) {
if (state('anticipatingMultidomain') === anticipating) {
isAnticipatingMultiDomain (anticipating) {
if (state('anticipatingMultiDomain') === anticipating) {
return
}

const whenAnticipatingMultidomain = state('whenAnticipatingMultidomain')
const whenAnticipatingMultiDomain = state('whenAnticipatingMultiDomain')

if (anticipating && whenAnticipatingMultidomain) {
whenAnticipatingMultidomain()
if (anticipating && whenAnticipatingMultiDomain) {
whenAnticipatingMultiDomain()
}

state('anticipatingMultidomain', anticipating)
state('anticipatingMultiDomain', anticipating)
},

whenStableOrAnticipatingMultidomain (fn) {
if (state('anticipatingMultidomain') || state('isStable') !== false) {
whenStableOrAnticipatingMultiDomain (fn) {
if (state('anticipatingMultiDomain') || state('isStable') !== false) {
return Promise.try(fn)
}

Expand All @@ -67,15 +67,15 @@ export const create = (Cypress, state) => ({
fulfilled = true

state('whenStable', null)
state('whenAnticipatingMultidomain', null)
state('whenAnticipatingMultiDomain', null)

Promise.try(fn)
.then(resolve)
.catch(reject)
}

state('whenStable', onSignal)
state('whenAnticipatingMultidomain', onSignal)
state('whenAnticipatingMultiDomain', onSignal)
})
},
})
Expand Down
2 changes: 1 addition & 1 deletion packages/driver/src/cypress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import ProxyLogging from './cypress/proxy-logging'
import * as $Events from './cypress/events'
import $Keyboard from './cy/keyboard'
import * as resolvers from './cypress/resolvers'
import { PrimaryDomainCommunicator } from './multidomain/communicator'
import { PrimaryDomainCommunicator } from './multi-domain/communicator'

const debug = debugFn('cypress:driver:cypress')

Expand Down
4 changes: 2 additions & 2 deletions packages/driver/src/cypress/command_queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export class CommandQueue extends Queue<Command> {
this.state('current', command)
this.state('chainerId', command.get('chainerId'))

return this.stability.whenStableOrAnticipatingMultidomain(() => {
return this.stability.whenStableOrAnticipatingMultiDomain(() => {
this.state('nestedIndex', this.state('index'))

return command.get('args')
Expand Down Expand Up @@ -324,7 +324,7 @@ export class CommandQueue extends Queue<Command> {
// finished running if the application under
// test is no longer stable because we cannot
// move onto the next test until its finished
return this.stability.whenStableOrAnticipatingMultidomain(() => {
return this.stability.whenStableOrAnticipatingMultiDomain(() => {
Cypress.action('cy:command:queue:end')

return null
Expand Down
4 changes: 2 additions & 2 deletions packages/driver/src/cypress/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import $stackUtils from './stack_utils'

import { allCommands } from '../cy/commands'
import { addCommand as addNetstubbingCommand } from '../cy/net-stubbing'
import { addCommands as addMultidomainCommands } from '../cy/multidomain'
import { addCommands as addMultiDomainCommands } from '../cy/multi-domain'

const builtInCommands = [
..._.toArray(allCommands).map((c) => c.default || c),
addNetstubbingCommand,
addMultidomainCommands,
addMultiDomainCommands,
]

const getTypeByPrevSubject = (prevSubject) => {
Expand Down
14 changes: 7 additions & 7 deletions packages/driver/src/cypress/cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@ export class $Cy extends EventEmitter2 implements ITimeouts, IStability, IAssert

isStable: IStability['isStable']
whenStable: IStability['whenStable']
isAnticipatingMultidomain: IStability['isAnticipatingMultidomain']
whenStableOrAnticipatingMultidomain: IStability['whenStableOrAnticipatingMultidomain']
isAnticipatingMultiDomain: IStability['isAnticipatingMultiDomain']
whenStableOrAnticipatingMultiDomain: IStability['whenStableOrAnticipatingMultiDomain']

assert: IAssertions['assert']
verifyUpcomingAssertions: IAssertions['verifyUpcomingAssertions']
Expand Down Expand Up @@ -251,8 +251,8 @@ export class $Cy extends EventEmitter2 implements ITimeouts, IStability, IAssert

this.isStable = stability.isStable
this.whenStable = stability.whenStable
this.isAnticipatingMultidomain = stability.isAnticipatingMultidomain
this.whenStableOrAnticipatingMultidomain = stability.whenStableOrAnticipatingMultidomain
this.isAnticipatingMultiDomain = stability.isAnticipatingMultiDomain
this.whenStableOrAnticipatingMultiDomain = stability.whenStableOrAnticipatingMultiDomain

const assertions = createAssertions(Cypress, this)

Expand Down Expand Up @@ -359,7 +359,7 @@ export class $Cy extends EventEmitter2 implements ITimeouts, IStability, IAssert

extendEvents(this)

Cypress.on('enqueue:command', (attrs) => {
Cypress.on('enqueue:command', (attrs: Cypress.EnqueuedCommand) => {
this.enqueue(attrs)
})
}
Expand Down Expand Up @@ -560,7 +560,7 @@ export class $Cy extends EventEmitter2 implements ITimeouts, IStability, IAssert
// we expect a cross-origin error and are setting things up
// elsewhere to handle running cross-domain, so don't fail
// because of it
if (this.state('readyForMultidomain')) {
if (this.state('readyForMultiDomain')) {
signalStable()

return
Expand Down Expand Up @@ -1131,7 +1131,7 @@ export class $Cy extends EventEmitter2 implements ITimeouts, IStability, IAssert
})
}

private enqueue (obj) {
private enqueue (obj: PartialBy<Cypress.EnqueuedCommand, 'id'>) {
// if we have a nestedIndex it means we're processing
// nested commands and need to insert them into the
// index past the current index as opposed to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export class PrimaryDomainCommunicator extends EventEmitter {
* @param {string} event - the name of the event to be sent.
* @param {any} data - any meta data to be sent with the event.
*/
toSpecBridge (event: string, data: any) {
toSpecBridge (event: string, data?: any) {
this.crossDomainDriverWindow.postMessage({
event,
data,
Expand Down Expand Up @@ -103,7 +103,7 @@ export class SpecBridgeDomainCommunicator extends EventEmitter {
* @param {string} event - the name of the event to be sent.
* @param {any} data - any meta data to be sent with the event.
*/
toPrimary (event: string, data: any) {
toPrimary (event: string, data?: any) {
let prefixedEvent = `${CROSS_DOMAIN_PREFIX}${event}`

this.windowReference.top.postMessage({ event: prefixedEvent, data }, '*')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ import { SpecBridgeDomainCommunicator } from './communicator'

const specBridgeCommunicator = new SpecBridgeDomainCommunicator()

const onCommandEnqueued = (commandAttrs) => {
const onCommandEnqueued = (commandAttrs: Cypress.EnqueuedCommand) => {
const { id, name } = commandAttrs

// it's not strictly necessary to send the name, but it can be useful
// for debugging purposes
specBridgeCommunicator.toPrimary('command:enqueued', { id, name })
}

const onCommandEnd = (command) => {
const onCommandEnd = (command: Cypress.CommandQueue) => {
const id = command.get('id')
const name = command.get('name')

Expand All @@ -41,6 +41,7 @@ const onLogChanged = (attrs) => {
}

const setup = () => {
// @ts-ignore
const Cypress = window.Cypress = $Cypress.create({
browser: {
channel: 'stable',
Expand All @@ -54,11 +55,14 @@ const setup = () => {
path: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
version: '90.0.4430.212',
},
})
}) as Cypress.Cypress

// @ts-ignore
const cy = window.cy = new $Cy(window, Cypress, Cypress.Cookies, Cypress.state, Cypress.config, false)

// @ts-ignore
Cypress.log = $Log.create(Cypress, cy, Cypress.state, Cypress.config)
// @ts-ignore
Cypress.runner = {
addLog () {},
}
Expand Down Expand Up @@ -111,9 +115,8 @@ const setup = () => {
}

// eslint-disable-next-line @cypress/dev/arrow-body-multiline-braces
const onBeforeAppWindowLoad = (cy, Cypress) => (autWindow) => {
const onBeforeAppWindowLoad = (cy: $Cy, Cypress: Cypress.Cypress) => (autWindow: Window) => {
autWindow.Cypress = Cypress
autWindow.cy = cy

Cypress.state('window', autWindow)
Cypress.state('document', autWindow.document)
Expand Down Expand Up @@ -156,7 +159,7 @@ const onBeforeAppWindowLoad = (cy, Cypress) => (autWindow) => {
return Cypress.action('app:window:alert', str)
},
onConfirm (str) {
const results = Cypress.action('app:window:confirm', str)
const results = Cypress.action('app:window:confirm', str) as any[]

// return false if ANY results are false
const ret = !results.some((result) => result === false)
Expand All @@ -174,7 +177,8 @@ const onBeforeAppWindowLoad = (cy, Cypress) => (autWindow) => {
// get re-created
const cy = setup()

window.__onBeforeAppWindowLoad = (autWindow) => {
// @ts-ignore
window.__onBeforeAppWindowLoad = (autWindow: Window) => {
cy.onBeforeAppWindowLoad(autWindow)
}

Expand Down
3 changes: 3 additions & 0 deletions packages/driver/types/internal-types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,6 @@ type AliasedRequest = {
alias: string
request: any
}

// utility types
type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
Loading

0 comments on commit 7bce51a

Please sign in to comment.