fix(testIsolation): improve the behavior, clarify config options and sync with session command (#24316)

Co-authored-by: Matt Henkes <mjhenkes@gmail.com>
Co-authored-by: Bill Glesias <bglesias@gmail.com>
This commit is contained in:
Emily Rohrbough
2022-10-24 18:05:58 -05:00
committed by GitHub
parent 851552cebd
commit 75cce8187c
20 changed files with 1389 additions and 636 deletions
+25 -5
View File
@@ -2808,12 +2808,32 @@ declare namespace Cypress {
*/
supportFile: string | false
/**
* The test isolation level applied to ensure a clean slate between tests.
* - legacy - resets/clears aliases, intercepts, clock, viewport, cookies, and local storage before each test.
* - strict - applies all resets/clears from legacy, plus clears the page by visiting 'about:blank' to ensure clean app state before each test.
* @default "legacy", however, when experimentalSessionAndOrigin=true, the default is "strict"
* The test isolation ensures a clean browser context between tests. This option is only available when
* `experimentalSessionAndOrigin=true`.
*
* Cypress will always reset/clear aliases, intercepts, clock, and viewport before each test
* to ensure a clean test slate; i.e. this configuration only impacts the browser context.
*
* Note: the [`cy.session()`](https://on.cypress.io/session) command will inherent this value to determine whether
* or not the page is cleared when the command executes. This command is only available in end-to-end testing.
*
* - on - The page is cleared before each test. Cookies, local storage and session storage in all domains are cleared
* before each test. The `cy.session()` command will also clear the page and current browser context when creating
* or restoring the browser session.
* - off - The current browser state will persist between tests. The page does not clear before the test and cookies, local
* storage and session storage will be available in the next test. The `cy.session()` command will only clear the
* current browser context when creating or restoring the browser session - the current page will not clear.
*
* Tradeoffs:
* Turning test isolation off may improve performance of end-to-end tests, however, previous tests could impact the
* browser state of the next test and cause inconsistency when using .only(). Be mindful to write isolated tests when
* test isolation is off. If a test in the suite impacts the state of other tests and it were to fail, you could see
* misleading errors in later tests which makes debugging clunky. See the [documentation](https://on.cypress.io/test-isolation)
* for more information.
*
* @default null, when experimentalSessionAndOrigin=false. The default is 'on' when experimentalSessionAndOrigin=true.
*/
testIsolation: 'legacy' | 'strict'
testIsolation: null | 'on' | 'off'
/**
* Path to folder where videos will be saved after a headless or CI run
* @default "cypress/videos"
@@ -70,7 +70,7 @@ exports['config/src/index .getDefaultValues returns list of public config keys 1
"supportFile": "cypress/support/e2e.{js,jsx,ts,tsx}",
"supportFolder": false,
"taskTimeout": 60000,
"testIsolation": "legacy",
"testIsolation": null,
"trashAssetsBeforeRuns": true,
"userAgent": null,
"video": true,
@@ -155,7 +155,7 @@ exports['config/src/index .getDefaultValues returns list of public config keys f
"supportFile": "cypress/support/e2e.{js,jsx,ts,tsx}",
"supportFolder": false,
"taskTimeout": 60000,
"testIsolation": "legacy",
"testIsolation": null,
"trashAssetsBeforeRuns": true,
"userAgent": null,
"video": true,
+9 -2
View File
@@ -155,7 +155,7 @@ export const matchesConfigKey = (key: string) => {
return
}
export const validate = (cfg: any, onErr: (property: ErrResult | string) => void) => {
export const validate = (cfg: any, onErr: (property: ErrResult | string) => void, testingType: TestingType | null) => {
debug('validating configuration')
return _.each(cfg, (value, key) => {
@@ -163,7 +163,11 @@ export const validate = (cfg: any, onErr: (property: ErrResult | string) => void
// key has a validation rule & value different from the default
if (validationFn && value !== defaultValues[key]) {
const result = validationFn(key, value)
const result = validationFn(key, value, {
testingType,
// TODO: remove with experimentalSessionAndOrigin. Fixed with: https://github.com/cypress-io/cypress/issues/21471
experimentalSessionAndOrigin: cfg.experimentalSessionAndOrigin,
})
if (result !== true) {
return onErr(result)
@@ -199,6 +203,9 @@ export const validateOverridableAtRunTime = (config: any, isSuiteLevelOverride:
return
}
// TODO: add a hook to ensure valid testing-type configuration is being set at runtime for all configuration values.
// https://github.com/cypress-io/cypress/issues/24365
if (overrideLevel === 'never' || (overrideLevel === 'suite' && !isSuiteLevelOverride)) {
onErr({
invalidConfigKey: configKey,
+38 -6
View File
@@ -31,6 +31,11 @@ const BREAKING_OPTION_ERROR_KEY: Readonly<AllCypressErrorNames[]> = [
'TEST_FILES_RENAMED',
] as const
type ValidationOptions = {
testingType: TestingType | null
experimentalSessionAndOrigin: boolean
}
export type BreakingOptionErrorKey = typeof BREAKING_OPTION_ERROR_KEY[number]
export type OverrideLevel = 'any' | 'suite' | 'never'
@@ -90,7 +95,7 @@ export interface BreakingOption {
showInLaunchpad?: boolean
}
const isValidConfig = (testingType: string, config: any) => {
const isValidConfig = (testingType: string, config: any, opts: ValidationOptions) => {
const status = validate.isPlainObject(testingType, config)
if (status !== true) {
@@ -99,7 +104,7 @@ const isValidConfig = (testingType: string, config: any) => {
for (const rule of options) {
if (rule.name in config && rule.validation) {
const status = rule.validation(`${testingType}.${rule.name}`, config[rule.name])
const status = rule.validation(`${testingType}.${rule.name}`, config[rule.name], opts)
if (status !== true) {
return status
@@ -200,6 +205,7 @@ const driverConfigOptions: Array<DriverConfigOption> = [
isExperimental: true,
requireRestartOnChange: 'server',
}, {
// TODO: remove with experimentalSessionAndOrigin. Fixed with: https://github.com/cypress-io/cypress/issues/21471
name: 'experimentalSessionAndOrigin',
defaultValue: false,
validation: validate.isBoolean,
@@ -373,11 +379,37 @@ const driverConfigOptions: Array<DriverConfigOption> = [
name: 'testIsolation',
// TODO: https://github.com/cypress-io/cypress/issues/23093
// When experimentalSessionAndOrigin is removed and released as GA,
// update the defaultValue from 'legacy' to 'strict' and
// update the defaultValue from undefined to 'on' and
// update this code to remove the check/override specific to enable
// strict by default when experimentalSessionAndOrigin=true
defaultValue: 'legacy',
validation: validate.isOneOf('legacy', 'strict'),
// 'on' by default when experimentalSessionAndOrigin=true
defaultValue: (options: Record<string, any> = {}) => {
if (options.testingType === 'component') {
return null
}
return options?.experimentalSessionAndOrigin || options?.config?.e2e?.experimentalSessionAndOrigin ? 'on' : null
},
validation: (key: string, value: any, opts: ValidationOptions) => {
const { testingType, experimentalSessionAndOrigin } = opts
if (testingType == null || testingType === 'component') {
return true
}
if (experimentalSessionAndOrigin && testingType === 'e2e') {
return validate.isOneOf('on', 'off')(key, value)
}
if (value == null) {
return true
}
return {
key,
value,
type: 'not set unless the experimentalSessionAndOrigin flag is turned on',
}
},
overrideLevel: 'suite',
}, {
name: 'trashAssetsBeforeRuns',
+1 -1
View File
@@ -60,7 +60,7 @@ export function updateWithPluginValues (cfg: FullConfig, modifiedConfig: any, te
}
return errors.throwErr('CONFIG_VALIDATION_ERROR', 'configFile', configFile, validationResult)
})
}, testingType)
debug('validate that there is no breaking config options added by setupNodeEvents')
+10 -6
View File
@@ -401,7 +401,11 @@ export function mergeDefaults (
config.baseUrl = url.replace(/\/\/+$/, '/')
}
const defaultsForRuntime = getDefaultValues(options)
const defaultsForRuntime = getDefaultValues({
...options,
// TODO: clean this up. Fixed with: https://github.com/cypress-io/cypress/issues/21471
experimentalSessionAndOrigin: config.experimentalSessionAndOrigin,
})
_.defaultsDeep(config, defaultsForRuntime)
@@ -454,7 +458,7 @@ export function mergeDefaults (
}
return errors.throwErr('CONFIG_VALIDATION_ERROR', null, null, validationResult)
})
}, testingType)
config = setAbsolutePaths(config)
@@ -477,15 +481,15 @@ export function mergeDefaults (
}, testingType)
// TODO: https://github.com/cypress-io/cypress/issues/23093
// testIsolation should equal 'strict' by default when experimentalSessionAndOrigin=true
// testIsolation should equal 'on' by default when experimentalSessionAndOrigin=true
// Once experimentalSessionAndOrigin is made GA, remove this logic and update the defaultValue
// to be be 'strict'
// to be be 'on'
if (testingType === 'e2e' && config.experimentalSessionAndOrigin) {
if (config.rawJson.testIsolation) {
config.resolved.testIsolation.from = 'config'
} else {
config.testIsolation = 'strict'
config.resolved.testIsolation.value = 'strict'
config.testIsolation = 'on'
config.resolved.testIsolation.value = 'on'
config.resolved.testIsolation.from === 'default'
}
}
+3 -3
View File
@@ -118,7 +118,7 @@ describe('config/src/index', () => {
configUtil.validate({
'baseUrl': 'https://',
}, errorFn)
}, errorFn, 'e2e')
expect(errorFn).to.have.callCount(0)
})
@@ -128,7 +128,7 @@ describe('config/src/index', () => {
configUtil.validate({
'baseUrl': ' ',
}, errorFn)
}, errorFn, 'e2e')
expect(errorFn).to.have.been.calledWithMatch({ key: 'baseUrl' })
expect(errorFn).to.have.been.calledWithMatch({ type: 'a fully qualified URL (starting with `http://` or `https://`)' })
@@ -195,7 +195,7 @@ describe('config/src/index', () => {
const isSuiteOverride = true
configUtil.validateOverridableAtRunTime({ testIsolation: 'strict' }, isSuiteOverride, errorFn)
configUtil.validateOverridableAtRunTime({ testIsolation: 'on' }, isSuiteOverride, errorFn)
expect(errorFn).to.have.callCount(0)
})
+6 -6
View File
@@ -1074,7 +1074,7 @@ describe('config/src/project/utils', () => {
supportFile: { value: false, from: 'config' },
supportFolder: { value: false, from: 'default' },
taskTimeout: { value: 60000, from: 'default' },
testIsolation: { value: 'legacy', from: 'default' },
testIsolation: { value: null, from: 'default' },
trashAssetsBeforeRuns: { value: true, from: 'default' },
userAgent: { value: null, from: 'default' },
video: { value: true, from: 'default' },
@@ -1190,7 +1190,7 @@ describe('config/src/project/utils', () => {
supportFile: { value: false, from: 'config' },
supportFolder: { value: false, from: 'default' },
taskTimeout: { value: 60000, from: 'default' },
testIsolation: { value: 'legacy', from: 'default' },
testIsolation: { value: null, from: 'default' },
trashAssetsBeforeRuns: { value: true, from: 'default' },
userAgent: { value: null, from: 'default' },
video: { value: true, from: 'default' },
@@ -1206,7 +1206,7 @@ describe('config/src/project/utils', () => {
})
})
it('sets testIsolation=strict by default when experimentalSessionAndOrigin=true and e2e testing', () => {
it('sets testIsolation=on by default when experimentalSessionAndOrigin=true and e2e testing', () => {
sinon.stub(utils, 'getProcessEnvVars').returns({})
const obj = {
@@ -1227,7 +1227,7 @@ describe('config/src/project/utils', () => {
expect(cfg.resolved).to.have.property('experimentalSessionAndOrigin')
expect(cfg.resolved.experimentalSessionAndOrigin).to.deep.eq({ value: true, from: 'config' })
expect(cfg.resolved).to.have.property('testIsolation')
expect(cfg.resolved.testIsolation).to.deep.eq({ value: 'strict', from: 'default' })
expect(cfg.resolved.testIsolation).to.deep.eq({ value: 'on', from: 'default' })
})
})
@@ -1239,7 +1239,7 @@ describe('config/src/project/utils', () => {
supportFile: false,
baseUrl: 'http://localhost:8080',
experimentalSessionAndOrigin: true,
testIsolation: 'legacy',
testIsolation: 'on',
}
const options = {
@@ -1253,7 +1253,7 @@ describe('config/src/project/utils', () => {
expect(cfg.resolved).to.have.property('experimentalSessionAndOrigin')
expect(cfg.resolved.experimentalSessionAndOrigin).to.deep.eq({ value: true, from: 'config' })
expect(cfg.resolved).to.have.property('testIsolation')
expect(cfg.resolved.testIsolation).to.deep.eq({ value: 'legacy', from: 'config' })
expect(cfg.resolved.testIsolation).to.deep.eq({ value: 'on', from: 'config' })
})
})
})
@@ -367,7 +367,7 @@ export class ProjectConfigManager {
}
throw getError('CONFIG_VALIDATION_ERROR', 'configFile', file || null, errMsg)
})
}, this._testingType)
return validateNoBreakingConfigLaunchpad(
config,
@@ -581,8 +581,8 @@ describe('src/cy/commands/navigation', () => {
})
})
describe('removes window:load listeners when testIsolation=legacy', { testIsolation: 'legacy' }, () => {
it('removes 2x for about:blank and first url visit', () => {
if (!Cypress.config('experimentalSessionAndOrigin')) {
it('removes window:load listeners 2x for about:blank and first url visit when experimentalSessionAndOrigin=false', () => {
const listeners = cy.listeners('window:load')
const winLoad = cy.spy(cy, 'once').withArgs('window:load')
@@ -593,17 +593,17 @@ describe('src/cy/commands/navigation', () => {
expect(cy.listeners('window:load')).to.deep.eq(listeners)
})
})
})
}
if (Cypress.config('experimentalSessionAndOrigin')) {
describe('removes window:load listeners when testIsolation=strict', () => {
describe('removes window:load listeners for first url visit when experimentalSessionAndOrigin=true', () => {
it('removes for first url visit', () => {
const listeners = cy.listeners('window:load')
const winLoad = cy.spy(cy, 'once').withArgs('window:load')
cy.visit('/fixtures/generic.html').then(() => {
expect(winLoad).to.be.calledOnce
expect(winLoad).to.be.calledOnce // once for $iframe src
expect(cy.listeners('window:load')).to.deep.eq(listeners)
})
})
@@ -768,46 +768,48 @@ describe('src/cy/commands/navigation', () => {
cy.get('div').should('contain', 'this should fail?')
})
describe('when only hashes are changing when testIsolation=legacy', { testIsolation: 'legacy' }, () => {
it('short circuits the visit if the page will not refresh', () => {
let count = 0
const urls = []
if (!Cypress.config('experimentalSessionAndOrigin')) {
describe('when only hashes are changing when experimentalSessionAndOrigin=false', () => {
it('short circuits the visit if the page will not refresh', () => {
let count = 0
const urls = []
cy.on('window:load', () => {
urls.push(cy.state('window').location.href)
cy.on('window:load', () => {
urls.push(cy.state('window').location.href)
count += 1
})
count += 1
})
cy
// about:blank yes (1)
.visit('/fixtures/generic.html?foo#bar') // yes (2)
.visit('/fixtures/generic.html?foo#foo') // no (2)
.visit('/fixtures/generic.html?bar#bar') // yes (3)
.visit('/fixtures/dimensions.html?bar#bar') // yes (4)
.visit('/fixtures/dimensions.html?baz#bar') // yes (5)
.visit('/fixtures/dimensions.html#bar') // yes (6)
.visit('/fixtures/dimensions.html') // yes (7)
.visit('/fixtures/dimensions.html#baz') // no (7)
.visit('/fixtures/dimensions.html#') // no (7)
.then(() => {
expect(count).to.eq(7)
cy
// about:blank yes (1)
.visit('/fixtures/generic.html?foo#bar') // yes (2)
.visit('/fixtures/generic.html?foo#foo') // no (2)
.visit('/fixtures/generic.html?bar#bar') // yes (3)
.visit('/fixtures/dimensions.html?bar#bar') // yes (4)
.visit('/fixtures/dimensions.html?baz#bar') // yes (5)
.visit('/fixtures/dimensions.html#bar') // yes (6)
.visit('/fixtures/dimensions.html') // yes (7)
.visit('/fixtures/dimensions.html#baz') // no (7)
.visit('/fixtures/dimensions.html#') // no (7)
.then(() => {
expect(count).to.eq(7)
expect(urls).to.deep.eq([
'about:blank',
'http://localhost:3500/fixtures/generic.html?foo#bar',
'http://localhost:3500/fixtures/generic.html?bar#bar',
'http://localhost:3500/fixtures/dimensions.html?bar#bar',
'http://localhost:3500/fixtures/dimensions.html?baz#bar',
'http://localhost:3500/fixtures/dimensions.html#bar',
'http://localhost:3500/fixtures/dimensions.html',
])
expect(urls).to.deep.eq([
'about:blank',
'http://localhost:3500/fixtures/generic.html?foo#bar',
'http://localhost:3500/fixtures/generic.html?bar#bar',
'http://localhost:3500/fixtures/dimensions.html?bar#bar',
'http://localhost:3500/fixtures/dimensions.html?baz#bar',
'http://localhost:3500/fixtures/dimensions.html#bar',
'http://localhost:3500/fixtures/dimensions.html',
])
})
})
})
})
}
if (Cypress.config('experimentalSessionAndOrigin')) {
describe('when only hashes are changing when testIsolation=strict', () => {
describe('when only hashes are changing when experimentalSessionAndOrigin=true', () => {
it('short circuits the visit if the page will not refresh', () => {
let count = 0
const urls = []
@@ -2588,109 +2590,111 @@ describe('src/cy/commands/navigation', () => {
})
})
describe('filters page load events when going back with window navigation when testIsolation=legacy', { testIsolation: 'legacy' }, () => {
if (!Cypress.config('experimentalSessionAndOrigin')) {
describe('filters page load events when going back with window navigation when experimentalSessionAndOrigin=false', () => {
// https://github.com/cypress-io/cypress/issues/19230
it('when going back with window navigation', () => {
const emit = cy.spy(Cypress, 'emit').log(false).withArgs('navigation:changed')
it('when going back with window navigation', () => {
const emit = cy.spy(Cypress, 'emit').log(false).withArgs('navigation:changed')
cy
.visit('/fixtures/generic.html')
.get('#hashchange').click()
.window().then((win) => {
return new Promise((resolve) => {
cy.once('navigation:changed', resolve)
win.history.back()
}).then(() => {
cy
.visit('/fixtures/generic.html')
.get('#hashchange').click()
.window().then((win) => {
return new Promise((resolve) => {
cy.once('navigation:changed', resolve)
win.history.forward()
win.history.back()
}).then(() => {
return new Promise((resolve) => {
cy.once('navigation:changed', resolve)
win.history.forward()
})
})
})
})
cy.get('#dimensions').click()
.window().then((win) => {
return new Promise((resolve) => {
cy.on('navigation:changed', (event) => {
if (event.includes('(load)')) {
resolve()
}
})
win.history.back()
})
.then(() => {
cy.get('#dimensions').click()
.window().then((win) => {
return new Promise((resolve) => {
cy.on('navigation:changed', resolve)
cy.on('navigation:changed', (event) => {
if (event.includes('(load)')) {
resolve()
}
})
win.history.back()
})
})
.then(() => {
expect(emit.getCall(0)).to.be.calledWith(
'navigation:changed',
'page navigation event (load)',
)
.then(() => {
return new Promise((resolve) => {
cy.on('navigation:changed', resolve)
win.history.back()
})
})
.then(() => {
expect(emit.getCall(0)).to.be.calledWith(
'navigation:changed',
'page navigation event (load)',
)
expect(emit.getCall(1)).to.be.calledWith(
'navigation:changed',
'page navigation event (before:load)',
)
expect(emit.getCall(1)).to.be.calledWith(
'navigation:changed',
'page navigation event (before:load)',
)
expect(emit.getCall(2)).to.be.calledWith(
'navigation:changed',
'page navigation event (load)',
)
expect(emit.getCall(2)).to.be.calledWith(
'navigation:changed',
'page navigation event (load)',
)
expect(emit.getCall(3)).to.be.calledWithMatch(
'navigation:changed',
'hashchange',
)
expect(emit.getCall(3)).to.be.calledWithMatch(
'navigation:changed',
'hashchange',
)
expect(emit.getCall(4)).to.be.calledWithMatch(
'navigation:changed',
'hashchange',
)
expect(emit.getCall(4)).to.be.calledWithMatch(
'navigation:changed',
'hashchange',
)
expect(emit.getCall(5)).to.be.calledWithMatch(
'navigation:changed',
'hashchange',
)
expect(emit.getCall(5)).to.be.calledWithMatch(
'navigation:changed',
'hashchange',
)
expect(emit.getCall(6)).to.be.calledWith(
'navigation:changed',
'page navigation event (before:load)',
)
expect(emit.getCall(6)).to.be.calledWith(
'navigation:changed',
'page navigation event (before:load)',
)
expect(emit.getCall(7)).to.be.calledWith(
'navigation:changed',
'page navigation event (load)',
)
expect(emit.getCall(7)).to.be.calledWith(
'navigation:changed',
'page navigation event (load)',
)
expect(emit.getCall(8)).to.be.calledWith(
'navigation:changed',
'page navigation event (before:load)',
)
expect(emit.getCall(8)).to.be.calledWith(
'navigation:changed',
'page navigation event (before:load)',
)
expect(emit.getCall(9)).to.be.calledWith(
'navigation:changed',
'page navigation event (load)',
)
expect(emit.getCall(9)).to.be.calledWith(
'navigation:changed',
'page navigation event (load)',
)
expect(emit.getCall(10)).to.be.calledWithMatch(
'navigation:changed',
'hashchange',
)
expect(emit.getCall(10)).to.be.calledWithMatch(
'navigation:changed',
'hashchange',
)
expect(emit.callCount).to.eq(11)
expect(emit.callCount).to.eq(11)
})
})
})
})
})
}
if (Cypress.config('experimentalSessionAndOrigin')) {
describe('filters page load events when going back with window navigation when testIsolation=strict', () => {
describe('filters page load events when going back with window navigation when experimentalSessionAndOrigin=true', () => {
// https://github.com/cypress-io/cypress/issues/19230
it('when going back with window navigation', () => {
const emit = cy.spy(Cypress, 'emit').log(false).withArgs('navigation:changed')
File diff suppressed because it is too large Load Diff
@@ -110,7 +110,8 @@ describe('driver/src/cypress/validate_config', () => {
expect(overrideLevel).to.eq('suite')
expect(() => {
validateConfig(state, { testIsolation: 'strict' })
// TODO: remove with experimentalSessionAndOrigin. Fixed with: https://github.com/cypress-io/cypress/issues/21471
validateConfig(state, { testIsolation: Cypress.config('experimentalSessionAndOrigin') ? 'on' : null })
}).not.to.throw()
})
@@ -127,7 +128,7 @@ describe('driver/src/cypress/validate_config', () => {
expect(overrideLevel).to.eq('test')
expect(() => {
validateConfig(state, { testIsolation: 'strict' })
validateConfig(state, { testIsolation: 'on' })
}).to.throw(`The \`testIsolation\` configuration can only be overridden from a suite-level override.`)
})
})
@@ -192,7 +193,8 @@ describe('driver/src/cypress/validate_config', () => {
})
expect(() => {
validateConfig(state, { testIsolation: 'legacy' })
// TODO: remove with experimentalSessionAndOrigin. Fixed with: https://github.com/cypress-io/cypress/issues/21471
validateConfig(state, { testIsolation: Cypress.config('experimentalSessionAndOrigin') ? 'off' : null })
}).not.to.throw()
})
@@ -35,11 +35,12 @@ const reset = (test: any = {}) => {
// before each test run!
previouslyVisitedLocation = undefined
const { experimentalSessionAndOrigin, testIsolation } = Cypress.config()
// TODO: remove with experimentalSessionAndOrigin. Fixed with: https://github.com/cypress-io/cypress/issues/21471
const { experimentalSessionAndOrigin } = Cypress.config()
// make sure we reset that we haven't visited about blank again
// strict test isolation resets the navigation history for us.
hasVisitedAboutBlank = experimentalSessionAndOrigin && testIsolation === 'strict'
hasVisitedAboutBlank = experimentalSessionAndOrigin
currentlyVisitingAboutBlank = false
@@ -1220,6 +1221,10 @@ export default (Commands, Cypress, cy, state, config) => {
}
const visit = () => {
// REMOVE THIS ONCE GA HITS. Sessions will handle visiting
// about blank.
// Fixed with: https://github.com/cypress-io/cypress/issues/21471
//
// if we've visiting for the first time during
// a test then we want to first visit about:blank
// so that we nuke the previous state. subsequent
@@ -49,7 +49,12 @@ export default function (Commands, Cypress, cy) {
Cypress.on('test:before:run:async', () => {
if (Cypress.config('experimentalSessionAndOrigin')) {
const clearPage = Cypress.config('testIsolation') === 'strict' ? navigateAboutBlank(false) : new Cypress.Promise.resolve()
if (Cypress.config('testIsolation') === 'off') {
return
}
// Component testing does not support navigation and handles clearing the page via mount utils
const clearPage = Cypress.testingType === 'e2e' ? navigateAboutBlank(false) : new Cypress.Promise.resolve()
return clearPage
.then(() => sessions.clearCurrentSessionData())
@@ -184,6 +184,10 @@ const getPostMessageLocalStorage = (specWindow, origins): Promise<any[]> => {
}
function navigateAboutBlank (session: boolean = true) {
if (Cypress.config('testIsolation') === 'off') {
return
}
Cypress.action('cy:url:changed', '')
return Cypress.action('cy:visit:blank', { type: session ? 'session' : 'session-lifecycle' }) as unknown as Promise<void>
+7 -1
View File
@@ -113,6 +113,12 @@ export const validateConfig = (state: State, config: Record<string, any>, skipCo
})
}
config = {
// TODO: remove with experimentalSessionAndOrigin. Fixed with: https://github.com/cypress-io/cypress/issues/21471
experimentalSessionAndOrigin: Cypress.originalConfig.experimentalSessionAndOrigin,
...config,
}
validateConfigValues(config, (errResult: ErrResult | string) => {
const stringify = (str) => format(JSON.stringify(str))
@@ -126,5 +132,5 @@ export const validateConfig = (state: State, config: Record<string, any>, skipCo
: `Expected ${format(errResult.key)} to be ${errResult.type}.\n\nInstead the value was: ${stringify(errResult.value)}`
throw new (state('specWindow').Error)(errMsg)
})
}, Cypress.testingType)
}
@@ -1195,10 +1195,11 @@ exports['testConfigOverrides / successfully runs valid suite-level-only override
(Run Starting)
Cypress: 1.2.3
Browser: FooBrowser 88
Specs: 1 found (valid-suite-only.js)
Searched: cypress/e2e/testConfigOverrides/valid-suite-only.js
Cypress: 1.2.3
Browser: FooBrowser 88
Specs: 1 found (valid-suite-only.js)
Searched: cypress/e2e/testConfigOverrides/valid-suite-only.js
Experiments: experimentalSessionAndOrigin=true
@@ -54,18 +54,18 @@ describe('throws error correctly when beforeEach hook', () => {
})
})
it('throws error when invalid test-level override', { testIsolation: 'legacy' }, () => {
it('throws error when invalid test-level override', { testIsolation: 'off' }, () => {
shouldNotExecute()
})
it('throws error when invalid config opt in Cypress.config() in test', () => {
Cypress.config({ testIsolation: 'legacy' })
Cypress.config({ testIsolation: 'off' })
shouldNotExecute()
})
describe('throws error when invalid config opt in Cypress.config() in before hook', () => {
before(() => {
Cypress.config({ testIsolation: 'legacy' })
Cypress.config({ testIsolation: 'off' })
})
it('4', () => {
@@ -75,7 +75,7 @@ describe('throws error when invalid config opt in Cypress.config() in before hoo
describe('throws error when invalid config opt in Cypress.config() in beforeEach hook', () => {
beforeEach(() => {
Cypress.config({ testIsolation: 'legacy' })
Cypress.config({ testIsolation: 'off' })
})
it('5', () => {
@@ -85,7 +85,7 @@ describe('throws error when invalid config opt in Cypress.config() in beforeEach
describe('throws error when invalid config opt in Cypress.config() in after hook', () => {
after(() => {
Cypress.config({ testIsolation: 'legacy' })
Cypress.config({ testIsolation: 'off' })
})
it('5', () => {
@@ -95,7 +95,7 @@ describe('throws error when invalid config opt in Cypress.config() in after hook
describe('throws error when invalid config opt in Cypress.config() in afterEach hook', () => {
afterEach(() => {
Cypress.config({ testIsolation: 'legacy' })
Cypress.config({ testIsolation: 'off' })
})
it('5', () => {
@@ -1,4 +1,4 @@
describe('suite-level-only overrides run as expected', { testIsolation: 'legacy' }, () => {
describe('suite-level-only overrides run as expected', { testIsolation: 'off' }, () => {
it('1st test passes', () => {
cy.visit('https://example.cypress.io')
})
@@ -13,7 +13,7 @@ describe('suite-level-only overrides run as expected', { testIsolation: 'legacy'
})
describe('nested contexts ', () => {
describe('nested suite-level-only overrides run as expected', { testIsolation: 'legacy' }, () => {
describe('nested suite-level-only overrides run as expected', { testIsolation: 'off' }, () => {
it('1st test passes', () => {
cy.visit('https://example.cypress.io')
})
@@ -16,6 +16,7 @@ describe('testConfigOverrides', () => {
expectedExitCode: 0,
browser: 'electron',
config: {
experimentalSessionAndOrigin: true,
video: false,
},
})