mirror of
https://github.com/cypress-io/cypress.git
synced 2026-04-21 06:29:16 -05:00
feat: experimental skip domain injection (#25307)
* feat: set up experimentalUseDefaultDocumentDomain to disallow document.domain overwritting * use default domain around experimentalUseDefaultDocumentDomain in main iframe and spec bridge iframes. Also adapt CORS policy to use same-origin if experimental flag is set * run ci * fix: add insertion of experimental flag where is was needed/missing * chore: add system test to exercise experimental flag for expected behavior * fix: fix issues with template updates to conform to squirrelly v7 * fix: update config tests to include new experimental flag * run ci * fix: trailing whitespace [run ci] * chore: update snapshot * run ci * fix: update proxy unit tests to account for experimentalUseDefaultDocumentDomain * run ci * fix: Allow component tests with special characters in filepath (#25299) feat: cut over experimental flag to take list of known problematic domains via string/glob pattern run ci chore: update system test and fix broken config * fix: fix server unit and integration tests. integration tests should no longer use google to test against injection as we do not inject document.domain on google domains * run ci * run ci * fix: server integration tests where google documents are expected to receive document.domain injection. Kept test same by changing URL * run ci * fix: update server test with mssing unupdated assertions * run ci * fix: turn off experimental flag by default while recommending sane defaults to users to configure * run ci * chore: fix typings [run ci] * run ci * chore: make experiment an e2e option only * run ci * chore: address comments in code review * chore: rename experimentalUseDefaultDocumentDomain to experimentalSkipDomainInjection * fix regression in shouldInjectionDocumentDomain utility function and add unit tests * run ci * chore: rename documentSuperDomainIfExists to superDomain [run ci] * chore: address comments from code review * chore: just pass opts through to policyForDomain * run ci Co-authored-by: Mike Plummer <mike-plummer@users.noreply.github.com>
This commit is contained in:
Vendored
+10
@@ -3019,6 +3019,16 @@ declare namespace Cypress {
|
||||
* @see https://on.cypress.io/configuration#experimentalModifyObstructiveThirdPartyCode
|
||||
*/
|
||||
experimentalModifyObstructiveThirdPartyCode: boolean
|
||||
/**
|
||||
* Disables setting document.domain to the applications super domain on injection.
|
||||
* This experiment is to be used for sites that do not work with setting document.domain
|
||||
* due to cross-origin issues. Enabling this option no longer allows for default subdomain
|
||||
* navigations, and will require the use of cy.origin(). This option takes an array of
|
||||
* strings/string globs.
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/Document/domain
|
||||
* @default null
|
||||
*/
|
||||
experimentalSkipDomainInjection: string[] | null
|
||||
/**
|
||||
* Enables AST-based JS/HTML rewriting. This may fix issues caused by the existing regex-based JS/HTML replacement algorithm.
|
||||
* @default false
|
||||
|
||||
@@ -38,6 +38,7 @@ exports['config/src/index .getDefaultValues returns list of public config keys 1
|
||||
'experimentalInteractiveRunEvents': false,
|
||||
'experimentalRunAllSpecs': false,
|
||||
'experimentalModifyObstructiveThirdPartyCode': false,
|
||||
'experimentalSkipDomainInjection': null,
|
||||
'experimentalOriginDependencies': false,
|
||||
'experimentalSourceRewriting': false,
|
||||
'experimentalSingleTabRunMode': false,
|
||||
@@ -123,6 +124,7 @@ exports['config/src/index .getDefaultValues returns list of public config keys f
|
||||
'experimentalInteractiveRunEvents': false,
|
||||
'experimentalRunAllSpecs': false,
|
||||
'experimentalModifyObstructiveThirdPartyCode': false,
|
||||
'experimentalSkipDomainInjection': null,
|
||||
'experimentalOriginDependencies': false,
|
||||
'experimentalSourceRewriting': false,
|
||||
'experimentalSingleTabRunMode': false,
|
||||
@@ -204,6 +206,7 @@ exports['config/src/index .getPublicConfigKeys returns list of public config key
|
||||
'experimentalInteractiveRunEvents',
|
||||
'experimentalRunAllSpecs',
|
||||
'experimentalModifyObstructiveThirdPartyCode',
|
||||
'experimentalSkipDomainInjection',
|
||||
'experimentalOriginDependencies',
|
||||
'experimentalSourceRewriting',
|
||||
'experimentalSingleTabRunMode',
|
||||
|
||||
@@ -215,6 +215,12 @@ const driverConfigOptions: Array<DriverConfigOption> = [
|
||||
validation: validate.isBoolean,
|
||||
isExperimental: true,
|
||||
requireRestartOnChange: 'server',
|
||||
}, {
|
||||
name: 'experimentalSkipDomainInjection',
|
||||
defaultValue: null,
|
||||
validation: validate.isNullOrArrayOfStrings,
|
||||
isExperimental: true,
|
||||
requireRestartOnChange: 'server',
|
||||
}, {
|
||||
name: 'experimentalOriginDependencies',
|
||||
defaultValue: false,
|
||||
@@ -679,6 +685,12 @@ export const breakingRootOptions: Array<BreakingOption> = [
|
||||
isWarning: false,
|
||||
testingTypes: ['e2e'],
|
||||
},
|
||||
{
|
||||
name: 'experimentalSkipDomainInjection',
|
||||
errorKey: 'EXPERIMENTAL_USE_DEFAULT_DOCUMENT_DOMAIN_E2E_ONLY',
|
||||
isWarning: false,
|
||||
testingTypes: ['e2e'],
|
||||
},
|
||||
]
|
||||
|
||||
export const testingTypeBreakingOptions: { e2e: Array<BreakingOption>, component: Array<BreakingOption> } = {
|
||||
@@ -720,5 +732,10 @@ export const testingTypeBreakingOptions: { e2e: Array<BreakingOption>, component
|
||||
errorKey: 'EXPERIMENTAL_ORIGIN_DEPENDENCIES_E2E_ONLY',
|
||||
isWarning: false,
|
||||
},
|
||||
{
|
||||
name: 'experimentalSkipDomainInjection',
|
||||
errorKey: 'EXPERIMENTAL_USE_DEFAULT_DOCUMENT_DOMAIN_E2E_ONLY',
|
||||
isWarning: false,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -328,3 +328,11 @@ export function isStringOrArrayOfStrings (key: string, value: any): ErrResult |
|
||||
|
||||
return errMsg(key, value, 'a string or an array of strings')
|
||||
}
|
||||
|
||||
export function isNullOrArrayOfStrings (key: string, value: any): ErrResult | true {
|
||||
if (_.isNull(value) || isArrayOfStrings(value)) {
|
||||
return true
|
||||
}
|
||||
|
||||
return errMsg(key, value, 'an array of strings or null')
|
||||
}
|
||||
|
||||
@@ -1052,6 +1052,7 @@ describe('config/src/project/utils', () => {
|
||||
env: {},
|
||||
execTimeout: { value: 60000, from: 'default' },
|
||||
experimentalModifyObstructiveThirdPartyCode: { value: false, from: 'default' },
|
||||
experimentalSkipDomainInjection: { value: null, from: 'default' },
|
||||
experimentalFetchPolyfill: { value: false, from: 'default' },
|
||||
experimentalInteractiveRunEvents: { value: false, from: 'default' },
|
||||
experimentalOriginDependencies: { value: false, from: 'default' },
|
||||
@@ -1147,6 +1148,7 @@ describe('config/src/project/utils', () => {
|
||||
downloadsFolder: { value: 'cypress/downloads', from: 'default' },
|
||||
execTimeout: { value: 60000, from: 'default' },
|
||||
experimentalModifyObstructiveThirdPartyCode: { value: false, from: 'default' },
|
||||
experimentalSkipDomainInjection: { value: null, from: 'default' },
|
||||
experimentalFetchPolyfill: { value: false, from: 'default' },
|
||||
experimentalInteractiveRunEvents: { value: false, from: 'default' },
|
||||
experimentalOriginDependencies: { value: false, from: 'default' },
|
||||
|
||||
@@ -85,10 +85,14 @@ export class Validator {
|
||||
}
|
||||
|
||||
// Users would be better off not using cy.origin if the origin is part of the same super domain.
|
||||
if (cors.urlMatchesPolicyBasedOnDomain(originLocation.href, specHref)) {
|
||||
if (cors.urlMatchesPolicyBasedOnDomain(originLocation.href, specHref, {
|
||||
skipDomainInjectionForDomains: Cypress.config('experimentalSkipDomainInjection'),
|
||||
})) {
|
||||
// this._isSameSuperDomainOriginWithExceptions({ originLocation, specLocation })) {
|
||||
|
||||
const policy = cors.policyForDomain(originLocation.href)
|
||||
const policy = cors.policyForDomain(originLocation.href, {
|
||||
skipDomainInjectionForDomains: Cypress.config('experimentalSkipDomainInjection'),
|
||||
})
|
||||
|
||||
$errUtils.throwErrByPath('origin.invalid_url_argument_same_origin', {
|
||||
onFail: this.log,
|
||||
|
||||
@@ -44,6 +44,7 @@ import { PrimaryOriginCommunicator, SpecBridgeCommunicator } from './cross-origi
|
||||
import { setupAutEventHandlers } from './cypress/aut_event_handlers'
|
||||
|
||||
import type { CachedTestState } from '@packages/types'
|
||||
import * as cors from '@packages/network/lib/cors'
|
||||
|
||||
const debug = debugFn('cypress:driver:cypress')
|
||||
|
||||
@@ -182,7 +183,11 @@ class $Cypress {
|
||||
|
||||
// set domainName but allow us to turn
|
||||
// off this feature in testing
|
||||
if (domainName && config.testingType === 'e2e') {
|
||||
const shouldInjectDocumentDomain = cors.shouldInjectDocumentDomain(window.location.origin, {
|
||||
skipDomainInjectionForDomains: config.experimentalSkipDomainInjection,
|
||||
})
|
||||
|
||||
if (domainName && config.testingType === 'e2e' && shouldInjectDocumentDomain) {
|
||||
document.domain = domainName
|
||||
}
|
||||
|
||||
|
||||
@@ -255,6 +255,7 @@ const commandCanCommunicateWithAUT = (cy: $Cy, err?): boolean => {
|
||||
const crossOriginCommandError = $errUtils.errByPath('miscellaneous.cross_origin_command', {
|
||||
commandOrigin: window.location.origin,
|
||||
autOrigin: cy.state('autLocation').origin,
|
||||
isSkipDomainInjectionEnabled: !!Cypress.config('experimentalSkipDomainInjection'),
|
||||
})
|
||||
|
||||
if (err) {
|
||||
|
||||
@@ -912,13 +912,15 @@ export default {
|
||||
return `Timed out retrying after ${ms}ms: `
|
||||
},
|
||||
test_stopped: 'Cypress test was stopped while running this command.',
|
||||
cross_origin_command ({ commandOrigin, autOrigin }) {
|
||||
cross_origin_command ({ commandOrigin, autOrigin, isSkipDomainInjectionEnabled }) {
|
||||
return {
|
||||
message: stripIndent`\
|
||||
The command was expected to run against origin \`${commandOrigin}\` but the application is at origin \`${autOrigin}\`.
|
||||
|
||||
This commonly happens when you have either not navigated to the expected origin or have navigated away unexpectedly.
|
||||
|
||||
${isSkipDomainInjectionEnabled ? `
|
||||
If \`experimentalSkipDomainInjection\` is enabled for this domain, a ${cmd('origin')} command is required.
|
||||
` : ''}
|
||||
Using ${cmd('origin')} to wrap the commands run on \`${autOrigin}\` will likely fix this issue.
|
||||
|
||||
\`cy.origin('${autOrigin}', () => {\`
|
||||
|
||||
@@ -1185,6 +1185,20 @@ export const AllCypressErrors = {
|
||||
|
||||
${fmt.code(code)}`
|
||||
},
|
||||
EXPERIMENTAL_USE_DEFAULT_DOCUMENT_DOMAIN_E2E_ONLY: () => {
|
||||
const code = errPartial`
|
||||
{
|
||||
e2e: {
|
||||
experimentalSkipDomainInjection: ['*.salesforce.com', '*.force.com', '*.google.com', 'google.com']
|
||||
},
|
||||
}`
|
||||
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight(`experimentalSkipDomainInjection`)} experiment is currently only supported for End to End Testing and must be configured as an e2e testing type property: ${fmt.highlightSecondary(`e2e.experimentalSkipDomainInjection`)}.
|
||||
The suggested values are only a recommendation.
|
||||
|
||||
${fmt.code(code)}`
|
||||
},
|
||||
FIREFOX_GC_INTERVAL_REMOVED: () => {
|
||||
return errTemplate`\
|
||||
The ${fmt.highlight(`firefoxGcInterval`)} configuration option was removed in ${fmt.cypressVersion(`8.0.0`)}. It was introduced to work around a bug in Firefox 79 and below.
|
||||
|
||||
@@ -1268,5 +1268,11 @@ describe('visual error templates', () => {
|
||||
default: [],
|
||||
}
|
||||
},
|
||||
|
||||
EXPERIMENTAL_USE_DEFAULT_DOCUMENT_DOMAIN_E2E_ONLY: () => {
|
||||
return {
|
||||
default: [],
|
||||
}
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
@@ -800,6 +800,7 @@ enum ErrorTypeEnum {
|
||||
EXPERIMENTAL_SINGLE_TAB_RUN_MODE
|
||||
EXPERIMENTAL_STUDIO_E2E_ONLY
|
||||
EXPERIMENTAL_STUDIO_REMOVED
|
||||
EXPERIMENTAL_USE_DEFAULT_DOCUMENT_DOMAIN_E2E_ONLY
|
||||
EXTENSION_NOT_LOADED
|
||||
FIREFOX_COULD_NOT_CONNECT
|
||||
FIREFOX_GC_INTERVAL_REMOVED
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import _ from 'lodash'
|
||||
import minimatch from 'minimatch'
|
||||
import * as uri from './uri'
|
||||
import debugModule from 'debug'
|
||||
import _parseDomain from '@cypress/parse-domain'
|
||||
@@ -11,6 +12,8 @@ const debug = debugModule('cypress:network:cors')
|
||||
// match IP addresses or anything following the last .
|
||||
const customTldsRe = /(^[\d\.]+$|\.[^\.]+$)/
|
||||
|
||||
// TODO: if experimentalSkipDomainInjection plans to go GA, we can likely lump this strictSameOriginDomains
|
||||
// into that config option by default. @see https://github.com/cypress-io/cypress/issues/25317
|
||||
const strictSameOriginDomains = Object.freeze(['google.com'])
|
||||
|
||||
export function getSuperDomain (url) {
|
||||
@@ -158,15 +161,58 @@ export const urlSameSiteMatch = (frameUrl: string, topUrl: string): boolean => {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param url - the url to check the policy against.
|
||||
* @param arrayOfStringOrGlobPatterns - an array of url strings or globs to match against
|
||||
* @returns {boolean} - whether or not a match was found
|
||||
*/
|
||||
const doesUrlHostnameMatchGlobArray = (url: string, arrayOfStringOrGlobPatterns: string[]): boolean => {
|
||||
let { hostname } = uri.parse(url)
|
||||
|
||||
return !!arrayOfStringOrGlobPatterns.find((globPattern) => {
|
||||
return minimatch(hostname || '', globPattern)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the policy that will be used for the specified url.
|
||||
* @param url - the url to check the policy against.
|
||||
* @param opts - an options object containing the skipDomainInjectionForDomains config. Default is undefined.
|
||||
* @returns a Policy string.
|
||||
*/
|
||||
export const policyForDomain = (url: string): Policy => {
|
||||
export const policyForDomain = (url: string, opts?: {
|
||||
skipDomainInjectionForDomains: string[] | null | undefined
|
||||
}): Policy => {
|
||||
const obj = parseUrlIntoHostProtocolDomainTldPort(url)
|
||||
let shouldUseSameOriginPolicy = strictSameOriginDomains.includes(`${obj.domain}.${obj.tld}`)
|
||||
|
||||
return strictSameOriginDomains.includes(`${obj.domain}.${obj.tld}`) ? 'same-origin' : 'same-super-domain-origin'
|
||||
if (!shouldUseSameOriginPolicy && _.isArray(opts?.skipDomainInjectionForDomains)) {
|
||||
// if the strict same origins matches came up false, we should check the user provided config value for skipDomainInjectionForDomains, if one exists
|
||||
shouldUseSameOriginPolicy = doesUrlHostnameMatchGlobArray(url, opts?.skipDomainInjectionForDomains as string[])
|
||||
}
|
||||
|
||||
return shouldUseSameOriginPolicy ?
|
||||
'same-origin' :
|
||||
'same-super-domain-origin'
|
||||
}
|
||||
|
||||
/**
|
||||
* @param url - The url to check for injection
|
||||
* @param opts - an options object containing the skipDomainInjectionForDomains config. Default is undefined.
|
||||
* @returns {boolean} whether or not document.domain should be injected solely based on the url.
|
||||
*/
|
||||
export const shouldInjectDocumentDomain = (url: string, opts?: {
|
||||
skipDomainInjectionForDomains: string[] | null
|
||||
}) => {
|
||||
// When determining if we want to injection document domain,
|
||||
// We need to make sure the experimentalSkipDomainInjection feature flag is off.
|
||||
// If on, we need to make sure the glob pattern doesn't exist in the array so we cover possible intersections (google).
|
||||
if (_.isArray(opts?.skipDomainInjectionForDomains)) {
|
||||
// if we match the glob, we want to return false
|
||||
return !doesUrlHostnameMatchGlobArray(url, opts?.skipDomainInjectionForDomains as string[])
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,11 +221,14 @@ export const policyForDomain = (url: string): Policy => {
|
||||
* in which case the policy is 'same-origin'
|
||||
* @param frameUrl - The url you are testing the policy for.
|
||||
* @param topUrl - The url you are testing the policy in context of.
|
||||
* @param opts - an options object containing the skipDomainInjectionForDomains config. Default is undefined.
|
||||
* @returns boolean, true if matching, false if not.
|
||||
*/
|
||||
export const urlMatchesPolicyBasedOnDomain = (frameUrl: string, topUrl: string): boolean => {
|
||||
export const urlMatchesPolicyBasedOnDomain = (frameUrl: string, topUrl: string, opts?: {
|
||||
skipDomainInjectionForDomains: string[] | null
|
||||
}): boolean => {
|
||||
return urlMatchesPolicy({
|
||||
policy: policyForDomain(frameUrl),
|
||||
policy: policyForDomain(frameUrl, opts),
|
||||
frameUrl,
|
||||
topUrl,
|
||||
})
|
||||
@@ -191,11 +240,13 @@ export const urlMatchesPolicyBasedOnDomain = (frameUrl: string, topUrl: string):
|
||||
* in which case the policy is 'same-origin'
|
||||
* @param frameUrl - The url you are testing the policy for.
|
||||
* @param topProps - The props of the url you are testing the policy in context of.
|
||||
* @param opts - an options object containing the skipDomainInjectionForDomains config. Default is undefined.
|
||||
* @returns boolean, true if matching, false if not.
|
||||
*/
|
||||
export const urlMatchesPolicyBasedOnDomainProps = (frameUrl: string, topProps: ParsedHostWithProtocolAndHost): boolean => {
|
||||
const obj = parseUrlIntoHostProtocolDomainTldPort(frameUrl)
|
||||
const policy = strictSameOriginDomains.includes(`${obj.domain}.${obj.tld}`) ? 'same-origin' : 'same-super-domain-origin'
|
||||
export const urlMatchesPolicyBasedOnDomainProps = (frameUrl: string, topProps: ParsedHostWithProtocolAndHost, opts?: {
|
||||
skipDomainInjectionForDomains: string[]
|
||||
}): boolean => {
|
||||
const policy = policyForDomain(frameUrl, opts)
|
||||
|
||||
return urlMatchesPolicyProps({
|
||||
policy,
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"debug": "^4.3.2",
|
||||
"fs-extra": "9.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
"minimatch": "3.0.5",
|
||||
"node-forge": "1.3.0",
|
||||
"proxy-from-env": "1.0.0"
|
||||
},
|
||||
|
||||
@@ -657,4 +657,86 @@ describe('lib/cors', () => {
|
||||
expect(cors.getOrigin('http://www.app.herokuapp.com:8080')).to.equal('http://www.app.herokuapp.com:8080')
|
||||
})
|
||||
})
|
||||
|
||||
context('.policyForDomain', () => {
|
||||
const recommendedSameOriginPolicyUrlGlobs = ['*.salesforce.com', '*.force.com', '*.google.com', 'google.com']
|
||||
|
||||
context('returns "same-origin" for google domains', () => {
|
||||
it('accounts.google.com', () => {
|
||||
expect(cors.policyForDomain('https://accounts.google.com', {
|
||||
skipDomainInjectionForDomains: recommendedSameOriginPolicyUrlGlobs,
|
||||
})).to.equal('same-origin')
|
||||
})
|
||||
|
||||
it('www.google.com', () => {
|
||||
expect(cors.policyForDomain('https://www.google.com', {
|
||||
skipDomainInjectionForDomains: recommendedSameOriginPolicyUrlGlobs,
|
||||
})).to.equal('same-origin')
|
||||
})
|
||||
})
|
||||
|
||||
context('returns "same-origin" for salesforce domains', () => {
|
||||
it('https://the-host.develop.lightning.force.com', () => {
|
||||
expect(cors.policyForDomain('https://the-host.develop.lightning.force.com', {
|
||||
skipDomainInjectionForDomains: recommendedSameOriginPolicyUrlGlobs,
|
||||
})).to.equal('same-origin')
|
||||
})
|
||||
|
||||
it('https://the-host.develop.my.salesforce.com', () => {
|
||||
expect(cors.policyForDomain('https://the-host.develop.my.salesforce.com', {
|
||||
skipDomainInjectionForDomains: recommendedSameOriginPolicyUrlGlobs,
|
||||
})).to.equal('same-origin')
|
||||
})
|
||||
|
||||
it('https://the-host.develop.file.force.com', () => {
|
||||
expect(cors.policyForDomain('https://the-host.develop.file.force.com', {
|
||||
skipDomainInjectionForDomains: recommendedSameOriginPolicyUrlGlobs,
|
||||
})).to.equal('same-origin')
|
||||
})
|
||||
|
||||
it('https://the-host.develop.my.salesforce.com', () => {
|
||||
expect(cors.policyForDomain('https://the-host.develop.my.salesforce.com', {
|
||||
skipDomainInjectionForDomains: recommendedSameOriginPolicyUrlGlobs,
|
||||
})).to.equal('same-origin')
|
||||
})
|
||||
})
|
||||
|
||||
describe('returns "same-super-domain-origin" for non exception urls', () => {
|
||||
it('www.cypress.io', () => {
|
||||
expect(cors.policyForDomain('http://www.cypress.io', {
|
||||
skipDomainInjectionForDomains: recommendedSameOriginPolicyUrlGlobs,
|
||||
})).to.equal('same-super-domain-origin')
|
||||
})
|
||||
|
||||
it('docs.cypress.io', () => {
|
||||
expect(cors.policyForDomain('http://docs.cypress.io', {
|
||||
skipDomainInjectionForDomains: recommendedSameOriginPolicyUrlGlobs,
|
||||
})).to.equal('same-super-domain-origin')
|
||||
})
|
||||
|
||||
it('stackoverflow.com', () => {
|
||||
expect(cors.policyForDomain('https://stackoverflow.com', {
|
||||
skipDomainInjectionForDomains: recommendedSameOriginPolicyUrlGlobs,
|
||||
})).to.equal('same-super-domain-origin')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('.shouldInjectDocumentDomain', () => {
|
||||
it('returns false when "skipDomainInjectionForDomains" is configured and contains a matching blob pattern ', () => {
|
||||
expect(cors.shouldInjectDocumentDomain('http://www.cypress.io', {
|
||||
skipDomainInjectionForDomains: ['*.cypress.io'],
|
||||
})).to.be.false
|
||||
})
|
||||
|
||||
it('returns true when "skipDomainInjectionForDomains" exists, but doesn\'t contain a matching glob pattern', () => {
|
||||
expect(cors.shouldInjectDocumentDomain('http://www.cypress.io', {
|
||||
skipDomainInjectionForDomains: ['*.foobar.com'],
|
||||
})).to.be.true
|
||||
})
|
||||
|
||||
it('returns true otherwise', () => {
|
||||
expect(cors.shouldInjectDocumentDomain('http://www.cypress.io')).to.be.true
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -162,8 +162,8 @@ const MaybeEndRequestWithBufferedResponse: RequestMiddleware = function () {
|
||||
|
||||
if (buffer) {
|
||||
this.debug('ending request with buffered response')
|
||||
// NOTE: Only inject fullCrossOrigin here if experimental is on and
|
||||
// the super domain origins do not match in order to keep parity with cypress application reloads
|
||||
|
||||
// NOTE: Only inject fullCrossOrigin here if the super domain origins do not match in order to keep parity with cypress application reloads
|
||||
this.res.wantsInjection = buffer.urlDoesNotMatchPolicyBasedOnDomain ? 'fullCrossOrigin' : 'full'
|
||||
|
||||
return this.onResponse(buffer.response, buffer.stream)
|
||||
|
||||
@@ -55,9 +55,11 @@ function getNodeCharsetFromResponse (headers: IncomingHttpHeaders, body: Buffer,
|
||||
return 'latin1'
|
||||
}
|
||||
|
||||
function reqMatchesPolicyBasedOnDomain (req: CypressIncomingRequest, remoteState) {
|
||||
function reqMatchesPolicyBasedOnDomain (req: CypressIncomingRequest, remoteState, skipDomainInjectionForDomains) {
|
||||
if (remoteState.strategy === 'http') {
|
||||
return cors.urlMatchesPolicyBasedOnDomainProps(req.proxiedUrl, remoteState.props)
|
||||
return cors.urlMatchesPolicyBasedOnDomainProps(req.proxiedUrl, remoteState.props, {
|
||||
skipDomainInjectionForDomains,
|
||||
})
|
||||
}
|
||||
|
||||
if (remoteState.strategy === 'file') {
|
||||
@@ -250,7 +252,7 @@ const SetInjectionLevel: ResponseMiddleware = function () {
|
||||
|
||||
this.debug('determine injection')
|
||||
|
||||
const isReqMatchSuperDomainOrigin = reqMatchesPolicyBasedOnDomain(this.req, this.remoteStates.current())
|
||||
const isReqMatchSuperDomainOrigin = reqMatchesPolicyBasedOnDomain(this.req, this.remoteStates.current(), this.config.experimentalSkipDomainInjection)
|
||||
const getInjectionLevel = () => {
|
||||
if (this.incomingRes.headers['x-cypress-file-server-error'] && !this.res.isInitial) {
|
||||
this.debug('- partial injection (x-cypress-file-server-error)')
|
||||
@@ -259,7 +261,7 @@ const SetInjectionLevel: ResponseMiddleware = function () {
|
||||
}
|
||||
|
||||
// NOTE: Only inject fullCrossOrigin if the super domain origins do not match in order to keep parity with cypress application reloads
|
||||
const urlDoesNotMatchPolicyBasedOnDomain = !reqMatchesPolicyBasedOnDomain(this.req, this.remoteStates.getPrimary())
|
||||
const urlDoesNotMatchPolicyBasedOnDomain = !reqMatchesPolicyBasedOnDomain(this.req, this.remoteStates.getPrimary(), this.config.experimentalSkipDomainInjection)
|
||||
const isAUTFrame = this.req.isAUTFrame
|
||||
const isHTMLLike = isHTML || isRenderedHTML
|
||||
|
||||
@@ -544,6 +546,9 @@ const MaybeInjectHtml: ResponseMiddleware = function () {
|
||||
isNotJavascript: !resContentTypeIsJavaScript(this.incomingRes),
|
||||
useAstSourceRewriting: this.config.experimentalSourceRewriting,
|
||||
modifyObstructiveThirdPartyCode: this.config.experimentalModifyObstructiveThirdPartyCode && !this.remoteStates.isPrimarySuperDomainOrigin(this.req.proxiedUrl),
|
||||
shouldInjectDocumentDomain: cors.shouldInjectDocumentDomain(this.req.proxiedUrl, {
|
||||
skipDomainInjectionForDomains: this.config.experimentalSkipDomainInjection,
|
||||
}),
|
||||
modifyObstructiveCode: this.config.modifyObstructiveCode,
|
||||
url: this.req.proxiedUrl,
|
||||
deferSourceMapRewrite: this.deferSourceMapRewrite,
|
||||
|
||||
@@ -2,25 +2,42 @@ import { oneLine } from 'common-tags'
|
||||
import { getRunnerInjectionContents, getRunnerCrossOriginInjectionContents } from '@packages/resolve-dist'
|
||||
import type { AutomationCookie } from '@packages/server/lib/automation/cookies'
|
||||
|
||||
interface InjectionOpts {
|
||||
shouldInjectDocumentDomain: boolean
|
||||
}
|
||||
interface FullCrossOriginOpts {
|
||||
modifyObstructiveThirdPartyCode: boolean
|
||||
modifyObstructiveCode: boolean
|
||||
simulatedCookies: AutomationCookie[]
|
||||
}
|
||||
|
||||
export function partial (domain) {
|
||||
export function partial (domain, options: InjectionOpts) {
|
||||
let documentDomainInjection = `document.domain = '${domain}';`
|
||||
|
||||
if (!options.shouldInjectDocumentDomain) {
|
||||
documentDomainInjection = ''
|
||||
}
|
||||
|
||||
// With useDefaultDocumentDomain=true we continue to inject an empty script tag in order to be consistent with our other forms of injection.
|
||||
// This is also diagnostic in nature is it will allow us to debug easily to make sure injection is still occurring.
|
||||
return oneLine`
|
||||
<script type='text/javascript'>
|
||||
document.domain = '${domain}';
|
||||
${documentDomainInjection}
|
||||
</script>
|
||||
`
|
||||
}
|
||||
|
||||
export function full (domain) {
|
||||
export function full (domain, options: InjectionOpts) {
|
||||
return getRunnerInjectionContents().then((contents) => {
|
||||
let documentDomainInjection = `document.domain = '${domain}';`
|
||||
|
||||
if (!options.shouldInjectDocumentDomain) {
|
||||
documentDomainInjection = ''
|
||||
}
|
||||
|
||||
return oneLine`
|
||||
<script type='text/javascript'>
|
||||
document.domain = '${domain}';
|
||||
${documentDomainInjection}
|
||||
|
||||
${contents}
|
||||
</script>
|
||||
@@ -28,12 +45,18 @@ export function full (domain) {
|
||||
})
|
||||
}
|
||||
|
||||
export async function fullCrossOrigin (domain, options: FullCrossOriginOpts) {
|
||||
export async function fullCrossOrigin (domain, options: InjectionOpts & FullCrossOriginOpts) {
|
||||
const contents = await getRunnerCrossOriginInjectionContents()
|
||||
|
||||
let documentDomainInjection = `document.domain = '${domain}';`
|
||||
|
||||
if (!options.shouldInjectDocumentDomain) {
|
||||
documentDomainInjection = ''
|
||||
}
|
||||
|
||||
return oneLine`
|
||||
<script type='text/javascript'>
|
||||
document.domain = '${domain}';
|
||||
${documentDomainInjection}
|
||||
|
||||
(function (cypressConfig) {
|
||||
${contents}
|
||||
|
||||
@@ -18,6 +18,7 @@ export type InjectionOpts = {
|
||||
wantsInjection: CypressWantsInjection
|
||||
wantsSecurityRemoved: any
|
||||
simulatedCookies: AutomationCookie[]
|
||||
shouldInjectDocumentDomain: boolean
|
||||
}
|
||||
|
||||
const doctypeRe = /<\!doctype.*?>/i
|
||||
@@ -36,19 +37,25 @@ function getHtmlToInject (opts: InjectionOpts & SecurityOpts) {
|
||||
modifyObstructiveThirdPartyCode,
|
||||
modifyObstructiveCode,
|
||||
simulatedCookies,
|
||||
shouldInjectDocumentDomain,
|
||||
} = opts
|
||||
|
||||
switch (wantsInjection) {
|
||||
case 'full':
|
||||
return inject.full(domainName)
|
||||
return inject.full(domainName, {
|
||||
shouldInjectDocumentDomain,
|
||||
})
|
||||
case 'fullCrossOrigin':
|
||||
return inject.fullCrossOrigin(domainName, {
|
||||
modifyObstructiveThirdPartyCode,
|
||||
modifyObstructiveCode,
|
||||
simulatedCookies,
|
||||
shouldInjectDocumentDomain,
|
||||
})
|
||||
case 'partial':
|
||||
return inject.partial(domainName)
|
||||
return inject.partial(domainName, {
|
||||
shouldInjectDocumentDomain,
|
||||
})
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1395,6 +1395,7 @@ describe('http/response-middleware', function () {
|
||||
'isNotJavascript': true,
|
||||
'modifyObstructiveCode': true,
|
||||
'modifyObstructiveThirdPartyCode': true,
|
||||
'shouldInjectDocumentDomain': true,
|
||||
'url': 'http://www.foobar.com:3501/primary-origin.html',
|
||||
'useAstSourceRewriting': undefined,
|
||||
'wantsInjection': 'full',
|
||||
@@ -1418,6 +1419,7 @@ describe('http/response-middleware', function () {
|
||||
'isNotJavascript': true,
|
||||
'modifyObstructiveCode': true,
|
||||
'modifyObstructiveThirdPartyCode': false,
|
||||
'shouldInjectDocumentDomain': true,
|
||||
'url': 'http://127.0.0.1:3501/primary-origin.html',
|
||||
'useAstSourceRewriting': undefined,
|
||||
'wantsInjection': 'full',
|
||||
@@ -1435,6 +1437,7 @@ describe('http/response-middleware', function () {
|
||||
config: {
|
||||
modifyObstructiveCode: false,
|
||||
experimentalModifyObstructiveThirdPartyCode: false,
|
||||
experimentalSkipDomainInjection: null,
|
||||
},
|
||||
simulatedCookies: [],
|
||||
})
|
||||
@@ -1448,6 +1451,7 @@ describe('http/response-middleware', function () {
|
||||
'isNotJavascript': true,
|
||||
'modifyObstructiveCode': false,
|
||||
'modifyObstructiveThirdPartyCode': false,
|
||||
'shouldInjectDocumentDomain': true,
|
||||
'url': 'http://www.foobar.com:3501/primary-origin.html',
|
||||
'useAstSourceRewriting': undefined,
|
||||
'wantsInjection': 'full',
|
||||
@@ -1485,6 +1489,7 @@ describe('http/response-middleware', function () {
|
||||
config: {
|
||||
modifyObstructiveCode: true,
|
||||
experimentalModifyObstructiveThirdPartyCode: true,
|
||||
experimentalSkipDomainInjection: null,
|
||||
},
|
||||
remoteStates,
|
||||
debug: (formatter, ...args) => {
|
||||
|
||||
Vendored
+1
@@ -22,6 +22,7 @@ export namespace CyServer {
|
||||
experimentalSourceRewriting: boolean
|
||||
modifyObstructiveCode: boolean
|
||||
experimentalModifyObstructiveThirdPartyCode: boolean
|
||||
experimentalSkipDomainInjection: string[] | null
|
||||
/**
|
||||
* URL to Cypress's runner.
|
||||
*/
|
||||
|
||||
@@ -26,9 +26,15 @@ module.exports = {
|
||||
|
||||
debug('all files to send %o', _.map(allFilesToSend, 'relative'))
|
||||
|
||||
const superDomain = cors.shouldInjectDocumentDomain(req.proxiedUrl, {
|
||||
skipDomainInjectionForDomains: config.experimentalSkipDomainInjection,
|
||||
}) ?
|
||||
remoteStates.getPrimary().domainName :
|
||||
undefined
|
||||
|
||||
const iframeOptions = {
|
||||
superDomain,
|
||||
title: this.getTitle(test),
|
||||
domain: remoteStates.getPrimary().domainName,
|
||||
scripts: JSON.stringify(allFilesToSend),
|
||||
}
|
||||
|
||||
@@ -38,14 +44,20 @@ module.exports = {
|
||||
})
|
||||
},
|
||||
|
||||
handleCrossOriginIframe (req, res, namespace) {
|
||||
handleCrossOriginIframe (req, res, config) {
|
||||
const iframePath = cwd('lib', 'html', 'spec-bridge-iframe.html')
|
||||
const domain = cors.getSuperDomain(req.proxiedUrl)
|
||||
const superDomain = cors.shouldInjectDocumentDomain(req.proxiedUrl, {
|
||||
skipDomainInjectionForDomains: config.experimentalSkipDomainInjection,
|
||||
}) ?
|
||||
cors.getSuperDomain(req.proxiedUrl) :
|
||||
undefined
|
||||
|
||||
const origin = cors.getOrigin(req.proxiedUrl)
|
||||
|
||||
const iframeOptions = {
|
||||
domain,
|
||||
title: `Cypress for ${domain}`,
|
||||
namespace,
|
||||
superDomain,
|
||||
title: `Cypress for ${origin}`,
|
||||
namespace: config.namespace,
|
||||
}
|
||||
|
||||
debug('cross origin iframe with options %o', iframeOptions)
|
||||
|
||||
@@ -54,6 +54,7 @@ const _summaries: StringValues = {
|
||||
experimentalFetchPolyfill: 'Polyfills `window.fetch` to enable Network spying and stubbing.',
|
||||
experimentalInteractiveRunEvents: 'Allows listening to the `before:run`, `after:run`, `before:spec`, and `after:spec` events in the plugins file during interactive mode.',
|
||||
experimentalModifyObstructiveThirdPartyCode: 'Applies `modifyObstructiveCode` to third party `.html` and `.js`, removes subresource integrity, and modifies the user agent in Electron.',
|
||||
experimentalSkipDomainInjection: 'Disables setting document.domain to the document\'s super domain on injection.',
|
||||
experimentalSourceRewriting: 'Enables AST-based JS/HTML rewriting. This may fix issues caused by the existing regex-based JS/HTML replacement algorithm.',
|
||||
experimentalSingleTabRunMode: 'Runs all component specs in a single tab, trading spec isolation for faster run mode execution.',
|
||||
experimentalStudio: 'Generate and save commands directly to your test suite by interacting with your app as an end user would.',
|
||||
@@ -76,6 +77,7 @@ const _names: StringValues = {
|
||||
experimentalFetchPolyfill: 'Fetch Polyfill',
|
||||
experimentalInteractiveRunEvents: 'Interactive Mode Run Events',
|
||||
experimentalModifyObstructiveThirdPartyCode: 'Modify Obstructive Third Party Code',
|
||||
experimentalSkipDomainInjection: 'Use Default document.domain',
|
||||
experimentalSingleTabRunMode: 'Single Tab Run Mode',
|
||||
experimentalSourceRewriting: 'Improved Source Rewriting',
|
||||
experimentalStudio: 'Studio',
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
document.domain = '{{domain}}';
|
||||
|
||||
{{if(options.superDomain)}}
|
||||
document.domain = '{{superDomain}}';
|
||||
{{/if}}
|
||||
|
||||
(function(parent) {
|
||||
var Cypress = window.Cypress = parent.Cypress;
|
||||
if (!Cypress) {
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
document.domain = '{{domain}}';
|
||||
{{if(options.superDomain)}}
|
||||
document.domain = '{{superDomain}}';
|
||||
{{/if}}
|
||||
</script>
|
||||
<script src="/{{namespace}}/runner/cypress_cross_origin_runner.js"></script>
|
||||
</body>
|
||||
|
||||
@@ -105,7 +105,7 @@ export const createRoutesE2E = ({
|
||||
// @see https://github.com/cypress-io/cypress/issues/25010
|
||||
res.setHeader('Origin-Agent-Cluster', '?0')
|
||||
|
||||
files.handleCrossOriginIframe(req, res, config.namespace)
|
||||
files.handleCrossOriginIframe(req, res, config)
|
||||
})
|
||||
|
||||
return routesE2E
|
||||
|
||||
@@ -45,6 +45,8 @@ const isResponseHtml = function (contentType, responseBuffer) {
|
||||
|
||||
export class ServerE2E extends ServerBase<SocketE2E> {
|
||||
private _urlResolver: Bluebird<Record<string, any>> | null
|
||||
// the initialization of this variable is only precautionary as the actual config value is applied when the server is created
|
||||
private skipDomainInjectionForDomains: string[] | null = null
|
||||
|
||||
constructor () {
|
||||
super()
|
||||
@@ -58,10 +60,10 @@ export class ServerE2E extends ServerBase<SocketE2E> {
|
||||
|
||||
createServer (app, config, onWarning): Bluebird<[number, WarningErr?]> {
|
||||
return new Bluebird((resolve, reject) => {
|
||||
const { port, fileServerFolder, socketIoRoute, baseUrl } = config
|
||||
const { port, fileServerFolder, socketIoRoute, baseUrl, experimentalSkipDomainInjection } = config
|
||||
|
||||
this._server = this._createHttpServer(app)
|
||||
|
||||
this.skipDomainInjectionForDomains = experimentalSkipDomainInjection
|
||||
const onError = (err) => {
|
||||
// if the server bombs before starting
|
||||
// and the err no is EADDRINUSE
|
||||
@@ -308,7 +310,9 @@ export class ServerE2E extends ServerBase<SocketE2E> {
|
||||
// TODO: think about moving this logic back into the frontend so that the driver can be in control
|
||||
// of when to buffer and set the remote state
|
||||
if (isOk && details.isHtml) {
|
||||
const urlDoesNotMatchPolicyBasedOnDomain = options.hasAlreadyVisitedUrl && !cors.urlMatchesPolicyBasedOnDomain(primaryRemoteState.origin, newUrl || '') || options.isFromSpecBridge
|
||||
const urlDoesNotMatchPolicyBasedOnDomain = options.hasAlreadyVisitedUrl
|
||||
&& !cors.urlMatchesPolicyBasedOnDomain(primaryRemoteState.origin, newUrl || '', { skipDomainInjectionForDomains: this.skipDomainInjectionForDomains })
|
||||
|| options.isFromSpecBridge
|
||||
|
||||
if (!handlingLocalFile) {
|
||||
this._remoteStates.set(newUrl as string, options, !urlDoesNotMatchPolicyBasedOnDomain)
|
||||
|
||||
@@ -2199,7 +2199,7 @@ describe('Routes', () => {
|
||||
|
||||
context('content injection', () => {
|
||||
beforeEach(function () {
|
||||
return this.setup('http://www.google.com')
|
||||
return this.setup('http://www.cypress.io')
|
||||
})
|
||||
|
||||
it('injects when head has attributes', async function () {
|
||||
@@ -2212,7 +2212,7 @@ describe('Routes', () => {
|
||||
const injection = await getRunnerInjectionContents()
|
||||
const contents = removeWhitespace(Fixtures.get('server/expected_head_inject.html').replace('{{injection}}', injection))
|
||||
const res = await this.rp({
|
||||
url: 'http://www.google.com/bar',
|
||||
url: 'http://www.cypress.io/bar',
|
||||
headers: {
|
||||
'Cookie': '__cypress.initial=true',
|
||||
},
|
||||
@@ -2234,7 +2234,7 @@ describe('Routes', () => {
|
||||
const contents = removeWhitespace(Fixtures.get('server/expected_no_head_tag_inject.html').replace('{{injection}}', injection))
|
||||
|
||||
const res = await this.rp({
|
||||
url: 'http://www.google.com/bar',
|
||||
url: 'http://www.cypress.io/bar',
|
||||
headers: {
|
||||
'Cookie': '__cypress.initial=true',
|
||||
},
|
||||
@@ -2253,7 +2253,7 @@ describe('Routes', () => {
|
||||
})
|
||||
|
||||
return this.rp({
|
||||
url: 'http://www.google.com/bar',
|
||||
url: 'http://www.cypress.io/bar',
|
||||
headers: {
|
||||
'Cookie': '__cypress.initial=true',
|
||||
},
|
||||
@@ -2261,7 +2261,7 @@ describe('Routes', () => {
|
||||
.then((res) => {
|
||||
expect(res.statusCode).to.eq(200)
|
||||
|
||||
expect(res.body).to.include('<HTML> <HEAD> <script type=\'text/javascript\'> document.domain = \'google.com\';')
|
||||
expect(res.body).to.include('<HTML> <HEAD> <script type=\'text/javascript\'> document.domain = \'cypress.io\';')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2273,7 +2273,7 @@ describe('Routes', () => {
|
||||
})
|
||||
|
||||
return this.rp({
|
||||
url: 'http://www.google.com/bar',
|
||||
url: 'http://www.cypress.io/bar',
|
||||
headers: {
|
||||
'Cookie': '__cypress.initial=true',
|
||||
},
|
||||
@@ -2281,7 +2281,7 @@ describe('Routes', () => {
|
||||
.then((res) => {
|
||||
expect(res.statusCode).to.eq(200)
|
||||
|
||||
expect(res.body).to.include('<html> <head> <script type=\'text/javascript\'> document.domain = \'google.com\';')
|
||||
expect(res.body).to.include('<html> <head> <script type=\'text/javascript\'> document.domain = \'cypress.io\';')
|
||||
|
||||
expect(res.body).to.include('</head> <body><nav>some nav</nav><header>header</header></body> </html>')
|
||||
})
|
||||
@@ -2295,7 +2295,7 @@ describe('Routes', () => {
|
||||
})
|
||||
|
||||
return this.rp({
|
||||
url: 'http://www.google.com/bar',
|
||||
url: 'http://www.cypress.io/bar',
|
||||
headers: {
|
||||
'Cookie': '__cypress.initial=true',
|
||||
},
|
||||
@@ -2315,7 +2315,7 @@ describe('Routes', () => {
|
||||
})
|
||||
|
||||
return this.rp({
|
||||
url: 'http://www.google.com/bar',
|
||||
url: 'http://www.cypress.io/bar',
|
||||
headers: {
|
||||
'Cookie': '__cypress.initial=true',
|
||||
},
|
||||
@@ -2337,7 +2337,7 @@ describe('Routes', () => {
|
||||
})
|
||||
|
||||
return this.rp({
|
||||
url: 'http://www.google.com/bar',
|
||||
url: 'http://www.cypress.io/bar',
|
||||
headers: {
|
||||
'Cookie': '__cypress.initial=true',
|
||||
},
|
||||
@@ -2359,7 +2359,7 @@ describe('Routes', () => {
|
||||
})
|
||||
|
||||
return this.rp({
|
||||
url: 'http://www.google.com/bar',
|
||||
url: 'http://www.cypress.io/bar',
|
||||
headers: {
|
||||
'Cookie': '__cypress.initial=true',
|
||||
},
|
||||
@@ -2379,7 +2379,7 @@ describe('Routes', () => {
|
||||
})
|
||||
|
||||
return this.rp({
|
||||
url: 'http://www.google.com/bar',
|
||||
url: 'http://www.cypress.io/bar',
|
||||
headers: {
|
||||
'Cookie': '__cypress.initial=false',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
||||
@@ -2388,7 +2388,7 @@ describe('Routes', () => {
|
||||
.then((res) => {
|
||||
expect(res.statusCode).to.eq(200)
|
||||
|
||||
expect(res.body).to.eq('<html> <head> <script type=\'text/javascript\'> document.domain = \'google.com\'; </script> </head> <body>hello from bar!</body> </html>')
|
||||
expect(res.body).to.eq('<html> <head> <script type=\'text/javascript\'> document.domain = \'cypress.io\'; </script> </head> <body>hello from bar!</body> </html>')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2397,7 +2397,7 @@ describe('Routes', () => {
|
||||
.get('/bar')
|
||||
.reply(302, undefined, {
|
||||
// redirect us to google.com!
|
||||
'Location': 'http://www.google.com/foo',
|
||||
'Location': 'http://www.cypress.io/foo',
|
||||
})
|
||||
|
||||
nock(this.server.remoteStates.current().origin)
|
||||
@@ -2407,14 +2407,14 @@ describe('Routes', () => {
|
||||
})
|
||||
|
||||
return this.rp({
|
||||
url: 'http://www.google.com/bar',
|
||||
url: 'http://www.cypress.io/bar',
|
||||
headers: {
|
||||
'Cookie': '__cypress.initial=true',
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
expect(res.statusCode).to.eq(302)
|
||||
expect(res.headers['location']).to.eq('http://www.google.com/foo')
|
||||
expect(res.headers['location']).to.eq('http://www.cypress.io/foo')
|
||||
expect(res.headers['set-cookie']).to.match(/initial=true/)
|
||||
|
||||
return this.rp(res.headers['location'])
|
||||
@@ -2437,7 +2437,7 @@ describe('Routes', () => {
|
||||
})
|
||||
|
||||
return this.rp({
|
||||
url: 'http://www.google.com/elements.html',
|
||||
url: 'http://www.cypress.io/elements.html',
|
||||
headers: {
|
||||
'Cookie': '__cypress.initial=true',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
||||
@@ -2446,7 +2446,7 @@ describe('Routes', () => {
|
||||
.then((res) => {
|
||||
expect(res.statusCode).to.eq(200)
|
||||
|
||||
expect(res.body).to.include('document.domain = \'google.com\';')
|
||||
expect(res.body).to.include('document.domain = \'cypress.io\';')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2479,7 +2479,7 @@ describe('Routes', () => {
|
||||
})
|
||||
|
||||
return this.rp({
|
||||
url: 'http://www.google.com/bar',
|
||||
url: 'http://www.cypress.io/bar',
|
||||
headers: {
|
||||
'Cookie': '__cypress.initial=false',
|
||||
},
|
||||
@@ -2534,10 +2534,10 @@ describe('Routes', () => {
|
||||
})
|
||||
|
||||
it('injects even on 5xx responses', function () {
|
||||
return this.setup('https://www.google.com')
|
||||
return this.setup('https://www.cypress.io')
|
||||
.then(() => {
|
||||
this.server.onRequest((req, res) => {
|
||||
return nock('https://www.google.com')
|
||||
return nock('https://www.cypress.io')
|
||||
.get('/')
|
||||
.reply(500, '<html><head></head><body>google</body></html>', {
|
||||
'Content-Type': 'text/html',
|
||||
@@ -2545,7 +2545,7 @@ describe('Routes', () => {
|
||||
})
|
||||
|
||||
return this.rp({
|
||||
url: 'https://www.google.com/',
|
||||
url: 'https://www.cypress.io/',
|
||||
headers: {
|
||||
'Accept': 'text/html, application/xhtml+xml, */*',
|
||||
},
|
||||
@@ -2553,7 +2553,7 @@ describe('Routes', () => {
|
||||
.then((res) => {
|
||||
expect(res.statusCode).to.eq(500)
|
||||
|
||||
expect(res.body).to.include('document.domain = \'google.com\'')
|
||||
expect(res.body).to.include('document.domain = \'cypress.io\'')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -2624,7 +2624,7 @@ describe('Routes', () => {
|
||||
})
|
||||
|
||||
return this.rp({
|
||||
url: 'http://www.google.com/iframe',
|
||||
url: 'http://www.cypress.io/iframe',
|
||||
headers: {
|
||||
'Cookie': '__cypress.initial=false',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
||||
@@ -2635,19 +2635,19 @@ describe('Routes', () => {
|
||||
|
||||
const body = cleanResponseBody(res.body)
|
||||
|
||||
expect(body).to.eq('<html><head> <script type=\'text/javascript\'> document.domain = \'google.com\'; </script></head></html>')
|
||||
expect(body).to.eq('<html><head> <script type=\'text/javascript\'> document.domain = \'cypress.io\'; </script></head></html>')
|
||||
})
|
||||
})
|
||||
|
||||
it('does not inject document.domain on matching super domains but different subdomain - when the domain is set to strict same origin (google)', function () {
|
||||
nock('http://mail.google.com')
|
||||
nock('http://www.google.com')
|
||||
.get('/iframe')
|
||||
.reply(200, '<html><head></head></html>', {
|
||||
'Content-Type': 'text/html',
|
||||
})
|
||||
|
||||
return this.rp({
|
||||
url: 'http://mail.google.com/iframe',
|
||||
url: 'http://www.google.com/iframe',
|
||||
headers: {
|
||||
'Cookie': '__cypress.initial=false',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
||||
@@ -2694,7 +2694,7 @@ describe('Routes', () => {
|
||||
})
|
||||
|
||||
return this.rp({
|
||||
url: 'http://www.google.com/json',
|
||||
url: 'http://www.cypress.io/json',
|
||||
json: true,
|
||||
headers: {
|
||||
'Cookie': '__cypress.initial=false',
|
||||
@@ -2734,7 +2734,7 @@ describe('Routes', () => {
|
||||
.reply(200, { foo: 'bar' })
|
||||
|
||||
return this.rp({
|
||||
url: 'http://www.google.com/json',
|
||||
url: 'http://www.cypress.io/json',
|
||||
headers: {
|
||||
'Cookie': '__cypress.initial=true',
|
||||
'Accept': 'application/json',
|
||||
@@ -2757,7 +2757,7 @@ describe('Routes', () => {
|
||||
})
|
||||
|
||||
return this.rp({
|
||||
url: 'http://www.google.com/iframe',
|
||||
url: 'http://www.cypress.io/iframe',
|
||||
headers: {
|
||||
'Cookie': '__cypress.initial=false',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
||||
@@ -2788,7 +2788,7 @@ describe('Routes', () => {
|
||||
headers['Accept'] = type
|
||||
|
||||
return this.rp({
|
||||
url: 'http://www.google.com/iframe',
|
||||
url: 'http://www.cypress.io/iframe',
|
||||
headers,
|
||||
})
|
||||
.then((res) => {
|
||||
|
||||
@@ -823,7 +823,7 @@ describe('Server', () => {
|
||||
})
|
||||
|
||||
it('can serve non 2xx status code requests when option set', function () {
|
||||
nock('http://google.com')
|
||||
nock('http://cypress.io')
|
||||
.matchHeader('user-agent', 'foobarbaz')
|
||||
.matchHeader('accept', 'text/html,*/*')
|
||||
.get('/foo')
|
||||
@@ -837,29 +837,29 @@ describe('Server', () => {
|
||||
|
||||
headers['user-agent'] = 'foobarbaz'
|
||||
|
||||
return this.server._onResolveUrl('http://google.com/foo', headers, this.automationRequest, { failOnStatusCode: false })
|
||||
return this.server._onResolveUrl('http://cypress.io/foo', headers, this.automationRequest, { failOnStatusCode: false })
|
||||
.then((obj = {}) => {
|
||||
return expectToEqDetails(obj, {
|
||||
isOkStatusCode: true,
|
||||
isPrimarySuperDomainOrigin: true,
|
||||
isHtml: true,
|
||||
contentType: 'text/html',
|
||||
url: 'http://google.com/foo',
|
||||
originalUrl: 'http://google.com/foo',
|
||||
url: 'http://cypress.io/foo',
|
||||
originalUrl: 'http://cypress.io/foo',
|
||||
status: 404,
|
||||
statusText: 'Not Found',
|
||||
redirects: [],
|
||||
cookies: [],
|
||||
})
|
||||
}).then(() => {
|
||||
return this.rp('http://google.com/foo')
|
||||
return this.rp('http://cypress.io/foo')
|
||||
.then((res) => {
|
||||
expect(res.statusCode).to.eq(404)
|
||||
expect(res.headers['set-cookie']).not.to.match(/initial=;/)
|
||||
expect(res.headers['x-foo-bar']).to.eq('true')
|
||||
expect(res.headers['cache-control']).to.eq('no-cache, no-store, must-revalidate')
|
||||
expect(res.body).to.include('content')
|
||||
expect(res.body).to.include('document.domain = \'google.com\'')
|
||||
expect(res.body).to.include('document.domain = \'cypress.io\'')
|
||||
|
||||
expect(res.body).to.include('.action("app:window:before:load",window)')
|
||||
expect(res.body).to.include('</head>content</html>')
|
||||
@@ -1132,7 +1132,7 @@ describe('Server', () => {
|
||||
})
|
||||
|
||||
it('can go from file -> http -> file', function () {
|
||||
nock('http://www.google.com')
|
||||
nock('http://www.cypress.io')
|
||||
.get('/')
|
||||
.reply(200, 'content page', {
|
||||
'Content-Type': 'text/html',
|
||||
@@ -1159,35 +1159,35 @@ describe('Server', () => {
|
||||
expect(res.statusCode).to.eq(200)
|
||||
})
|
||||
}).then(() => {
|
||||
return this.server._onResolveUrl('http://www.google.com/', {}, this.automationRequest)
|
||||
return this.server._onResolveUrl('http://www.cypress.io/', {}, this.automationRequest)
|
||||
}).then((obj = {}) => {
|
||||
return expectToEqDetails(obj, {
|
||||
isOkStatusCode: true,
|
||||
isPrimarySuperDomainOrigin: true,
|
||||
isHtml: true,
|
||||
contentType: 'text/html',
|
||||
url: 'http://www.google.com/',
|
||||
originalUrl: 'http://www.google.com/',
|
||||
url: 'http://www.cypress.io/',
|
||||
originalUrl: 'http://www.cypress.io/',
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
redirects: [],
|
||||
cookies: [],
|
||||
})
|
||||
}).then(() => {
|
||||
return this.rp('http://www.google.com/')
|
||||
return this.rp('http://www.cypress.io/')
|
||||
.then((res) => {
|
||||
expect(res.statusCode).to.eq(200)
|
||||
})
|
||||
}).then(() => {
|
||||
expect(this.server.remoteStates.current()).to.deep.eq({
|
||||
auth: undefined,
|
||||
origin: 'http://www.google.com',
|
||||
origin: 'http://www.cypress.io',
|
||||
strategy: 'http',
|
||||
domainName: 'google.com',
|
||||
domainName: 'cypress.io',
|
||||
fileServer: null,
|
||||
props: {
|
||||
domain: 'google',
|
||||
tld: 'com',
|
||||
domain: 'cypress',
|
||||
tld: 'io',
|
||||
port: '80',
|
||||
subdomain: 'www',
|
||||
protocol: 'http:',
|
||||
@@ -1228,50 +1228,50 @@ describe('Server', () => {
|
||||
})
|
||||
|
||||
it('can go from http -> file -> http', function () {
|
||||
nock('http://www.google.com')
|
||||
nock('http://www.cypress.io')
|
||||
.get('/')
|
||||
.reply(200, '<html><head></head><body>google</body></html>', {
|
||||
.reply(200, '<html><head></head><body>cypress</body></html>', {
|
||||
'Content-Type': 'text/html',
|
||||
})
|
||||
.get('/')
|
||||
.reply(200, '<html><head></head><body>google</body></html>', {
|
||||
.reply(200, '<html><head></head><body>cypress</body></html>', {
|
||||
'Content-Type': 'text/html',
|
||||
})
|
||||
|
||||
return this.server._onResolveUrl('http://www.google.com/', {}, this.automationRequest)
|
||||
return this.server._onResolveUrl('http://www.cypress.io/', {}, this.automationRequest)
|
||||
.then((obj = {}) => {
|
||||
return expectToEqDetails(obj, {
|
||||
isOkStatusCode: true,
|
||||
isPrimarySuperDomainOrigin: true,
|
||||
isHtml: true,
|
||||
contentType: 'text/html',
|
||||
url: 'http://www.google.com/',
|
||||
originalUrl: 'http://www.google.com/',
|
||||
url: 'http://www.cypress.io/',
|
||||
originalUrl: 'http://www.cypress.io/',
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
redirects: [],
|
||||
cookies: [],
|
||||
})
|
||||
}).then(() => {
|
||||
return this.rp('http://www.google.com/')
|
||||
return this.rp('http://www.cypress.io/')
|
||||
.then((res) => {
|
||||
expect(res.statusCode).to.eq(200)
|
||||
expect(res.body).to.include('document.domain')
|
||||
expect(res.body).to.include('google.com')
|
||||
expect(res.body).to.include('cypress.io')
|
||||
|
||||
expect(res.body).to.include('.action("app:window:before:load",window)')
|
||||
expect(res.body).to.include('</script></head><body>google</body></html>')
|
||||
expect(res.body).to.include('</script></head><body>cypress</body></html>')
|
||||
})
|
||||
}).then(() => {
|
||||
expect(this.server.remoteStates.current()).to.deep.eq({
|
||||
auth: undefined,
|
||||
origin: 'http://www.google.com',
|
||||
origin: 'http://www.cypress.io',
|
||||
strategy: 'http',
|
||||
domainName: 'google.com',
|
||||
domainName: 'cypress.io',
|
||||
fileServer: null,
|
||||
props: {
|
||||
domain: 'google',
|
||||
tld: 'com',
|
||||
domain: 'cypress',
|
||||
tld: 'io',
|
||||
port: '80',
|
||||
subdomain: 'www',
|
||||
protocol: 'http:',
|
||||
@@ -1313,40 +1313,40 @@ describe('Server', () => {
|
||||
props: null,
|
||||
})
|
||||
}).then(() => {
|
||||
return this.server._onResolveUrl('http://www.google.com/', {}, this.automationRequest)
|
||||
return this.server._onResolveUrl('http://www.cypress.io/', {}, this.automationRequest)
|
||||
.then((obj = {}) => {
|
||||
return expectToEqDetails(obj, {
|
||||
isOkStatusCode: true,
|
||||
isPrimarySuperDomainOrigin: true,
|
||||
isHtml: true,
|
||||
contentType: 'text/html',
|
||||
url: 'http://www.google.com/',
|
||||
originalUrl: 'http://www.google.com/',
|
||||
url: 'http://www.cypress.io/',
|
||||
originalUrl: 'http://www.cypress.io/',
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
redirects: [],
|
||||
cookies: [],
|
||||
})
|
||||
}).then(() => {
|
||||
return this.rp('http://www.google.com/')
|
||||
return this.rp('http://www.cypress.io/')
|
||||
.then((res) => {
|
||||
expect(res.statusCode).to.eq(200)
|
||||
expect(res.body).to.include('document.domain')
|
||||
expect(res.body).to.include('google.com')
|
||||
expect(res.body).to.include('cypress.io')
|
||||
|
||||
expect(res.body).to.include('.action("app:window:before:load",window)')
|
||||
expect(res.body).to.include('</script></head><body>google</body></html>')
|
||||
expect(res.body).to.include('</script></head><body>cypress</body></html>')
|
||||
})
|
||||
}).then(() => {
|
||||
expect(this.server.remoteStates.current()).to.deep.eq({
|
||||
auth: undefined,
|
||||
origin: 'http://www.google.com',
|
||||
origin: 'http://www.cypress.io',
|
||||
strategy: 'http',
|
||||
domainName: 'google.com',
|
||||
domainName: 'cypress.io',
|
||||
fileServer: null,
|
||||
props: {
|
||||
domain: 'google',
|
||||
tld: 'com',
|
||||
domain: 'cypress',
|
||||
tld: 'io',
|
||||
port: '80',
|
||||
subdomain: 'www',
|
||||
protocol: 'http:',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<html>
|
||||
<head prefix="og: foo">
|
||||
<script type='text/javascript'>
|
||||
document.domain = 'google.com';
|
||||
document.domain = 'cypress.io';
|
||||
|
||||
{{injection}}
|
||||
</script>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<script type='text/javascript'>
|
||||
document.domain = 'google.com';
|
||||
document.domain = 'cypress.io';
|
||||
|
||||
{{injection}}
|
||||
</script>
|
||||
|
||||
@@ -30,7 +30,7 @@ export interface FullConfig extends Partial<Cypress.RuntimeConfigOptions & Cypre
|
||||
// and are required when creating a project.
|
||||
export type ReceivedCypressOptions =
|
||||
Pick<Cypress.RuntimeConfigOptions, 'hosts' | 'projectName' | 'clientRoute' | 'devServerPublicPathRoute' | 'namespace' | 'report' | 'socketIoCookie' | 'configFile' | 'isTextTerminal' | 'isNewProject' | 'proxyUrl' | 'browsers' | 'browserUrl' | 'socketIoRoute' | 'arch' | 'platform' | 'spec' | 'specs' | 'browser' | 'version' | 'remote'>
|
||||
& Pick<Cypress.ResolvedConfigOptions, 'chromeWebSecurity' | 'supportFolder' | 'experimentalSourceRewriting' | 'fixturesFolder' | 'reporter' | 'reporterOptions' | 'screenshotsFolder' | 'supportFile' | 'baseUrl' | 'viewportHeight' | 'viewportWidth' | 'port' | 'experimentalInteractiveRunEvents' | 'userAgent' | 'downloadsFolder' | 'env' | 'excludeSpecPattern' | 'specPattern' | 'experimentalModifyObstructiveThirdPartyCode' | 'video' | 'videoCompression' | 'videosFolder' | 'videoUploadOnPasses' | 'resolvedNodeVersion' | 'resolvedNodePath' | 'trashAssetsBeforeRuns' | 'experimentalWebKitSupport'> // TODO: Figure out how to type this better.
|
||||
& Pick<Cypress.ResolvedConfigOptions, 'chromeWebSecurity' | 'supportFolder' | 'experimentalSourceRewriting' | 'fixturesFolder' | 'reporter' | 'reporterOptions' | 'screenshotsFolder' | 'supportFile' | 'baseUrl' | 'viewportHeight' | 'viewportWidth' | 'port' | 'experimentalInteractiveRunEvents' | 'userAgent' | 'downloadsFolder' | 'env' | 'excludeSpecPattern' | 'specPattern' | 'experimentalModifyObstructiveThirdPartyCode' | 'experimentalSkipDomainInjection' | 'video' | 'videoCompression' | 'videosFolder' | 'videoUploadOnPasses' | 'resolvedNodeVersion' | 'resolvedNodePath' | 'trashAssetsBeforeRuns' | 'experimentalWebKitSupport'> // TODO: Figure out how to type this better.
|
||||
|
||||
export interface SettingsOptions {
|
||||
testingType?: 'component' |'e2e'
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
exports['e2e experimentalSkipDomainInjection=true / passes'] = `
|
||||
|
||||
====================================================================================================
|
||||
|
||||
(Run Starting)
|
||||
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Cypress: 1.2.3 │
|
||||
│ Browser: FooBrowser 88 │
|
||||
│ Specs: 1 found (experimental_skip_domain_injection.cy.ts) │
|
||||
│ Searched: cypress/e2e/experimental_skip_domain_injection.cy.ts │
|
||||
│ Experiments: experimentalSkipDomainInjection=*.foobar.com │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
Running: experimental_skip_domain_injection.cy.ts (1 of 1)
|
||||
|
||||
|
||||
expected behavior when experimentalSkipDomainInjection=true
|
||||
✓ Handles cross-site/cross-origin navigation the same way without the experimental flag enabled
|
||||
✓ errors appropriately when doing a sub domain navigation w/o cy.origin()
|
||||
✓ allows sub-domain navigations with the use of cy.origin()
|
||||
|
||||
|
||||
3 passing
|
||||
|
||||
|
||||
(Results)
|
||||
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ Tests: 3 │
|
||||
│ Passing: 3 │
|
||||
│ Failing: 0 │
|
||||
│ Pending: 0 │
|
||||
│ Skipped: 0 │
|
||||
│ Screenshots: 0 │
|
||||
│ Video: true │
|
||||
│ Duration: X seconds │
|
||||
│ Spec Ran: experimental_skip_domain_injection.cy.ts │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
(Video)
|
||||
|
||||
- Started processing: Compressing to 32 CRF
|
||||
- Finished processing: /XXX/XXX/XXX/cypress/videos/experimental_skip_domain_inject (X second)
|
||||
ion.cy.ts.mp4
|
||||
|
||||
|
||||
====================================================================================================
|
||||
|
||||
(Run Finished)
|
||||
|
||||
|
||||
Spec Tests Passing Failing Pending Skipped
|
||||
┌────────────────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ ✔ experimental_skip_domain_injection. XX:XX 3 3 - - - │
|
||||
│ cy.ts │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
✔ All specs passed! XX:XX 3 3 - - -
|
||||
|
||||
|
||||
`
|
||||
@@ -0,0 +1,43 @@
|
||||
describe('expected behavior when experimentalSkipDomainInjection=true', () => {
|
||||
it('Handles cross-site/cross-origin navigation the same way without the experimental flag enabled', () => {
|
||||
cy.visit('/primary_origin.html')
|
||||
cy.get('a[data-cy="cross_origin_secondary_link"]').click()
|
||||
cy.origin('http://www.foobar.com:4466', () => {
|
||||
cy.get('[data-cy="dom-check"]').should('have.text', 'From a secondary origin')
|
||||
})
|
||||
})
|
||||
|
||||
it('errors appropriately when doing a sub domain navigation w/o cy.origin()', () => {
|
||||
const timeout = 500
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.name).to.equal('CypressError')
|
||||
expect(err.message).to.contain(`Timed out retrying after ${timeout}ms: The command was expected to run against origin \`http://app.foobar.com:4466\` but the application is at origin \`http://www.foobar.com:4466\`.`)
|
||||
expect(err.message).to.contain('This commonly happens when you have either not navigated to the expected origin or have navigated away unexpectedly.')
|
||||
expect(err.message).to.contain('Using `cy.origin()` to wrap the commands run on `http://www.foobar.com:4466` will likely fix this issue.')
|
||||
expect(err.message).to.include(`cy.origin('http://www.foobar.com:4466', () => {\`\n\` <commands targeting http://www.foobar.com:4466 go here>\`\n\`})`)
|
||||
expect(err.message).to.include('If `experimentalSkipDomainInjection` is enabled for this domain, a `cy.origin()` command is required.')
|
||||
|
||||
// make sure that the secondary origin 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`)
|
||||
})
|
||||
|
||||
// with experimentalSkipDomainInjection, sub domain navigations require a cy.origin() block
|
||||
cy.visit('http://app.foobar.com:4466/primary_origin.html')
|
||||
cy.get('a[data-cy="cross_origin_secondary_link"]').click()
|
||||
cy.get('[data-cy="dom-check"]', {
|
||||
timeout,
|
||||
}).should('have.text', 'From a secondary origin')
|
||||
})
|
||||
|
||||
it('allows sub-domain navigations with the use of cy.origin()', () => {
|
||||
cy.visit('http://app.foobar.com:4466/primary_origin.html')
|
||||
cy.get('a[data-cy="cross_origin_secondary_link"]').click()
|
||||
|
||||
// with experimentalSkipDomainInjection, sub domain navigations require a cy.origin() block
|
||||
cy.origin('http://www.foobar.com:4466', () => {
|
||||
cy.get('[data-cy="dom-check"]').should('have.text', 'From a secondary origin')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,44 @@
|
||||
import path from 'path'
|
||||
import systemTests from '../lib/system-tests'
|
||||
import Fixtures from '../lib/fixtures'
|
||||
|
||||
const e2ePath = Fixtures.projectPath('e2e')
|
||||
|
||||
const PORT = 3500
|
||||
const onServer = function (app) {
|
||||
app.get('/primary_origin.html', (_, res) => {
|
||||
res.sendFile(path.join(e2ePath, `primary_origin.html`))
|
||||
})
|
||||
|
||||
app.get('/secondary_origin.html', (_, res) => {
|
||||
res.sendFile(path.join(e2ePath, `secondary_origin.html`))
|
||||
})
|
||||
}
|
||||
|
||||
describe('e2e experimentalSkipDomainInjection=true', () => {
|
||||
systemTests.setup({
|
||||
servers: [{
|
||||
port: 4466,
|
||||
onServer,
|
||||
}],
|
||||
settings: {
|
||||
hosts: {
|
||||
'*.foobar.com': '127.0.0.1',
|
||||
},
|
||||
e2e: {},
|
||||
},
|
||||
})
|
||||
|
||||
systemTests.it('passes', {
|
||||
browser: '!webkit', // TODO(webkit): fix+unskip (needs multidomain support)
|
||||
// keep the port the same to prevent issues with the snapshot
|
||||
port: PORT,
|
||||
spec: 'experimental_skip_domain_injection.cy.ts',
|
||||
snapshot: true,
|
||||
expectedExitCode: 0,
|
||||
config: {
|
||||
retries: 0,
|
||||
experimentalSkipDomainInjection: ['*.foobar.com'],
|
||||
},
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user