Skip to content

Commit

Permalink
chore: Inject into hard-coded secondary domain (#16873)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisbreiding committed Jun 15, 2021
1 parent 69deb3e commit b8658cf
Show file tree
Hide file tree
Showing 15 changed files with 126 additions and 64 deletions.
15 changes: 0 additions & 15 deletions packages/driver/cypress/fixtures/multidomain-aut.html

This file was deleted.

8 changes: 0 additions & 8 deletions packages/driver/cypress/fixtures/multidomain-sibling.html

This file was deleted.

2 changes: 1 addition & 1 deletion packages/driver/cypress/fixtures/multidomain.html
Expand Up @@ -3,6 +3,6 @@
<head>
</head>
<body>
<a href="http://localhost:3501/fixtures/multidomain-aut.html">Go to localhost:3501</a>
<a href="http://127.0.0.1:3501/fixtures/generic.html">Go to 127.0.0.1:3501</a>
</body>
</html>
9 changes: 5 additions & 4 deletions packages/driver/cypress/integration/e2e/multidomain_spec.ts
Expand Up @@ -2,19 +2,20 @@
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('Some text in the cross-domain AUT')
expect(event.data.host).to.equal('localhost:3501')
expect(event.data.text).to.equal('Foo')
expect(event.data.host).to.equal('127.0.0.1:3501')
done()
}
}, false)

cy.state('anticipateMultidomain', true)
cy.viewport(900, 300)
cy.visit('/fixtures/multidomain.html')
cy.get('a').click()
// @ts-ignore
cy.switchToDomain('localhost:3501', () => {
cy.switchToDomain('127.0.0.1:3501', () => {
// @ts-ignore
cy.now('get', 'p').then(($el) => {
cy.now('get', '.foo').then(($el) => {
top.postMessage({ host: location.host, text: $el.text() }, '*')
})
})
Expand Down
36 changes: 20 additions & 16 deletions packages/driver/src/cypress/cy.js
Expand Up @@ -1043,26 +1043,30 @@ const create = function (specWindow, Cypress, Cookies, state, config, log) {

Cypress.action('app:window:load', state('window'))

// FIXME: temporary hard-coded hack to get multidomain working
if (!autWindow?.location?.pathname?.includes('multidomain-aut')) {
// we are now stable again which is purposefully
// the last event we call here, to give our event
// listeners time to be invoked prior to moving on
return stability.isStable(true, 'load')
}

Cypress.once('cross:domain:window:load', () => {
Cypress.once('cross:domain:driver:ready', () => {
stability.isStable(true, 'load')
// we are now stable again which is purposefully
// the last event we call here, to give our event
// listeners time to be invoked prior to moving on
return stability.isStable(true, 'load')
} catch (err) {
// we failed setting the remote window props which
// means the page navigated to a different domain

// 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')
})

Cypress.action('cy:switch:domain', 'localhost:3501')
})
} catch (err) {
return
}

let e = err

// we failed setting the remote window props
// which means we're in a cross domain failure
// check first to see if you have a callback function
// defined and let the page load change the error
onpl = state('onPageLoadErr')
Expand Down
6 changes: 6 additions & 0 deletions packages/proxy/lib/http/response-middleware.ts
Expand Up @@ -48,6 +48,8 @@ function getNodeCharsetFromResponse (headers: IncomingHttpHeaders, body: Buffer)

function reqMatchesOriginPolicy (req: CypressIncomingRequest, remoteState) {
if (remoteState.strategy === 'http') {
if (req.proxiedUrl.includes('127.0.0.1:3501')) return true

return cors.urlMatchesOriginPolicyProps(req.proxiedUrl, remoteState.props)
}

Expand Down Expand Up @@ -238,6 +240,10 @@ const SetInjectionLevel: ResponseMiddleware = function () {
return false
}

if (this.req.proxiedUrl.includes('127.0.0.1:3501')) {
return 'fullMultidomain'
}

if (this.res.isInitial) {
return 'full'
}
Expand Down
12 changes: 12 additions & 0 deletions packages/proxy/lib/http/util/inject.ts
Expand Up @@ -20,3 +20,15 @@ export function full (domain) {
`
})
}

export function fullMultidomain (domain) {
return runner.getMultidomainInjectionContents().then((contents) => {
return oneLine`
<script type='text/javascript'>
document.domain = '127.0.0.1';
${contents}
</script>
`
})
}
7 changes: 4 additions & 3 deletions packages/proxy/lib/http/util/rewriter.ts
@@ -1,6 +1,7 @@
import * as inject from './inject'
import * as astRewriter from './ast-rewriter'
import * as regexRewriter from './regex-rewriter'
import { CypressWantsInjection } from '../../types'

export type SecurityOpts = {
isHtml?: boolean
Expand All @@ -11,7 +12,7 @@ export type SecurityOpts = {

export type InjectionOpts = {
domainName: string
wantsInjection: WantsInjection
wantsInjection: CypressWantsInjection
wantsSecurityRemoved: any
}

Expand All @@ -20,8 +21,6 @@ const headRe = /(<head(?!er).*?>)/i
const bodyRe = /(<body.*?>)/i
const htmlRe = /(<html.*?>)/i

type WantsInjection = 'full' | 'partial' | false

function getRewriter (useAstSourceRewriting: boolean) {
return useAstSourceRewriting ? astRewriter : regexRewriter
}
Expand All @@ -30,6 +29,8 @@ function getHtmlToInject ({ domainName, wantsInjection }: InjectionOpts) {
switch (wantsInjection) {
case 'full':
return inject.full(domainName)
case 'fullMultidomain':
return inject.fullMultidomain(domainName)
case 'partial':
return inject.partial(domainName)
default:
Expand Down
4 changes: 3 additions & 1 deletion packages/proxy/lib/types.ts
Expand Up @@ -14,12 +14,14 @@ export type CypressIncomingRequest = Request & {
followRedirect?: boolean
}

export type CypressWantsInjection = 'full' | 'fullMultidomain' | 'partial' | false

/**
* An outgoing response to an incoming request to the Cypress web server.
*/
export type CypressOutgoingResponse = Response & {
isInitial: null | boolean
wantsInjection: 'full' | 'partial' | false
wantsInjection: CypressWantsInjection
wantsSecurityRemoved: null | boolean
body?: string | Readable
}
Expand Down
File renamed without changes.
40 changes: 40 additions & 0 deletions packages/runner/injection/multidomain.js
@@ -0,0 +1,40 @@
/**
* This is the entry point for the script that gets injected into
* the AUT on a secondary domain. It gets bundled on its own and injected
* into the <head> of the AUT by `packages/proxy`.
*
* If adding to this bundle, try to keep it light and free of
* dependencies.
*/

// TODO: uncomment the following code once the timing is worked out to have
// the sibling Cypress global available before this injection code runs

// import { createTimers } from './timers'

// const Cypress = window.Cypress = parent.Cypress

// if (!Cypress) {
// throw new Error('Something went terribly wrong and we cannot proceed. We expected to find the global Cypress in the parent window but it is missing!. This should never happen and likely is a bug. Please open an issue!')
// }

// // We wrap timers in the injection code because if we do it in the driver (like
// // we used to do), any uncaught errors thrown in the timer callbacks would
// // get picked up by the top frame's 'error' handler instead of the AUT's.
// // We need to wrap the timer callbacks in the AUT itself for errors to
// // propagate properly.
// const timers = createTimers()

// Cypress.removeAllListeners('app:timers:reset')
// Cypress.removeAllListeners('app:timers:pause')

// Cypress.on('app:timers:reset', timers.reset)
// Cypress.on('app:timers:pause', timers.pause)

// 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', '*')
})
10 changes: 9 additions & 1 deletion packages/runner/lib/resolve-dist.js
Expand Up @@ -7,13 +7,21 @@ function dist (...args) {
return path.join(...paths)
}

function getContents (filename) {
return fs.readFile(dist(filename))
}

module.exports = {
getPathToDist (...args) {
return dist(...args)
},

getInjectionContents () {
return fs.readFile(dist('injection.js'))
return getContents('injection.js')
},

getMultidomainInjectionContents () {
return getContents('injection_multidomain.js')
},

getPathToIndex () {
Expand Down
30 changes: 24 additions & 6 deletions packages/runner/webpack.config.ts
Expand Up @@ -79,11 +79,24 @@ mainConfig.resolve = {
}

// @ts-ignore
const injectionConfig: webpack.Configuration = {
const multiDomainConfig: webpack.Configuration = {
mode: 'development',
...getSimpleConfig(),
entry: {
cypress_multidomain_runner: [path.resolve(__dirname, 'multidomain/index.js')],
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
},
}

// @ts-ignore
const mainInjectionConfig: webpack.Configuration = {
...getSimpleConfig(),
mode: 'production',
entry: {
injection: [path.resolve(__dirname, 'injection/index.js')],
injection: [path.resolve(__dirname, 'injection/main.js')],
},
output: {
path: path.resolve(__dirname, 'dist'),
Expand All @@ -92,16 +105,21 @@ const injectionConfig: webpack.Configuration = {
}

// @ts-ignore
const multiDomainConfig: webpack.Configuration = {
mode: 'development',
const multidomainInjectionConfig: webpack.Configuration = {
...getSimpleConfig(),
mode: 'production',
entry: {
cypress_multidomain_runner: [path.resolve(__dirname, 'multidomain/index.js')],
injection_multidomain: [path.resolve(__dirname, 'injection/multidomain.js')],
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
},
}

export default [mainConfig, injectionConfig, multiDomainConfig]
export default [
mainConfig,
mainInjectionConfig,
multiDomainConfig,
multidomainInjectionConfig,
]
2 changes: 1 addition & 1 deletion packages/server/lib/controllers/files.js
Expand Up @@ -56,7 +56,7 @@ module.exports = {
const domain = decodeURI(req.params.domain)

const iframeOptions = {
domain: 'localhost',
domain: '127.0.0.1',
title: `Cypress for ${domain}`,
}

Expand Down
9 changes: 1 addition & 8 deletions yarn.lock
Expand Up @@ -40206,20 +40206,13 @@ ws@3.3.x, ws@^3.2.0:
safe-buffer "~5.1.0"
ultron "~1.1.0"

ws@5.2.3:
ws@5.2.3, ws@^5.2.0:
version "5.2.3"
resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.3.tgz#05541053414921bc29c63bee14b8b0dd50b07b3d"
integrity sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA==
dependencies:
async-limiter "~1.0.0"

ws@^5.2.0:
version "5.2.2"
resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f"
integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==
dependencies:
async-limiter "~1.0.0"

ws@^6.0.0, ws@^6.1.2, ws@^6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb"
Expand Down

0 comments on commit b8658cf

Please sign in to comment.