Merge branch 'release/13.0.0' of https://github.com/cypress-io/cypress into chore/merge_develop_into_release_13

This commit is contained in:
Bill Glesias
2023-08-14 09:32:41 -04:00
14 changed files with 267 additions and 46 deletions

View File

@@ -1,3 +1,3 @@
# Bump this version to force CI to re-create the cache from scratch.
08-10-23
08-10-23

View File

@@ -31,7 +31,7 @@ mainBuildFilters: &mainBuildFilters
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- 'update-v8-snapshot-cache-on-develop'
- 'publish-binary'
- 'chore/merge_develop_into_release_13'
- 'ryanm/feat/remove-protocol-environment-variable-from-binary'
# usually we don't build Mac app - it takes a long time
# but sometimes we want to really confirm we are doing the right thing
@@ -42,7 +42,7 @@ macWorkflowFilters: &darwin-workflow-filters
- equal: [ develop, << pipeline.git.branch >> ]
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
- equal: [ 'chore/merge_develop_into_release_13', << pipeline.git.branch >> ]
- equal: [ 'ryanm/feat/remove-protocol-environment-variable-from-binary', << pipeline.git.branch >> ]
- matches:
pattern: /^release\/\d+\.\d+\.\d+$/
value: << pipeline.git.branch >>
@@ -53,6 +53,11 @@ linuxArm64WorkflowFilters: &linux-arm64-workflow-filters
- equal: [ develop, << pipeline.git.branch >> ]
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
- equal: [ 'publish-binary', << pipeline.git.branch >> ]
- equal: [ 'ryanm/feat/remove-protocol-environment-variable-from-binary', << pipeline.git.branch >> ]
- matches:
pattern: /^release\/\d+\.\d+\.\d+$/
value: << pipeline.git.branch >>
# uncomment & add to the branch conditions below to disable the main linux
# flow if we don't want to test it for a certain branch
@@ -69,7 +74,7 @@ windowsWorkflowFilters: &windows-workflow-filters
- equal: [ develop, << pipeline.git.branch >> ]
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
- equal: [ 'chore/merge_develop_into_release_13', << pipeline.git.branch >> ]
- equal: [ 'ryanm/feat/remove-protocol-environment-variable-from-binary', << pipeline.git.branch >> ]
- matches:
pattern: /^release\/\d+\.\d+\.\d+$/
value: << pipeline.git.branch >>
@@ -139,7 +144,7 @@ commands:
name: Set environment variable to determine whether or not to persist artifacts
command: |
echo "Setting SHOULD_PERSIST_ARTIFACTS variable"
echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "publish-binary" && "$CIRCLE_BRANCH" != "update-v8-snapshot-cache-on-develop" && "$CIRCLE_BRANCH" != "chore/merge_develop_into_release_13" ]]; then
echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "publish-binary" && "$CIRCLE_BRANCH" != "update-v8-snapshot-cache-on-develop" && "$CIRCLE_BRANCH" != "ryanm/feat/remove-protocol-environment-variable-from-binary" ]]; then
export SHOULD_PERSIST_ARTIFACTS=true
fi' >> "$BASH_ENV"
# You must run `setup_should_persist_artifacts` command and be using bash before running this command

View File

@@ -13,7 +13,7 @@ describe('Reporter Header', () => {
cy.get('body').type('f')
cy.get('[data-selected-spec="true"]').should('contain', 'dom-content').should('have.length', '1')
cy.get('[data-selected-spec="false"]').should('have.length', '29')
cy.get('[data-selected-spec="false"]').should('have.length', '30')
})
// TODO: Reenable as part of https://github.com/cypress-io/cypress/issues/23902

View File

@@ -152,7 +152,7 @@ describe('App: Spec List (E2E)', () => {
it('displays only matching spec', function () {
cy.get('button')
.contains('25 matches')
.contains('26 matches')
.should('not.contain.text', 'of')
clearSearchAndType('content')
@@ -160,13 +160,13 @@ describe('App: Spec List (E2E)', () => {
.should('have.length', 3)
.and('contain', 'dom-content.spec.js')
cy.get('button').contains('3 of 25 matches')
cy.get('button').contains('3 of 26 matches')
cy.findByLabelText('Search specs').clear().type('asdf')
cy.findAllByTestId('spec-item')
.should('have.length', 0)
cy.get('button').contains('0 of 25 matches')
cy.get('button').contains('0 of 26 matches')
})
it('only shows matching folders', () => {
@@ -217,7 +217,7 @@ describe('App: Spec List (E2E)', () => {
cy.findByLabelText('Search specs')
.should('have.value', '')
cy.get('button').contains('25 matches')
cy.get('button').contains('26 matches')
})
it('clears the filter if the user presses ESC key', function () {
@@ -226,7 +226,7 @@ describe('App: Spec List (E2E)', () => {
cy.get('@searchField').should('have.value', '')
cy.get('button').contains('25 matches')
cy.get('button').contains('26 matches')
})
it('shows empty message if no results', function () {
@@ -242,7 +242,7 @@ describe('App: Spec List (E2E)', () => {
cy.findByText('Clear search').click()
cy.focused().should('have.id', 'spec-filter')
cy.get('button').contains('25 matches')
cy.get('button').contains('26 matches')
})
it('normalizes directory path separators for Windows', function () {

View File

@@ -76,6 +76,7 @@ describe('specChange subscription', () => {
getPathForPlatform('cypress/e2e/admin_users/admin_users_list.spec.js'),
getPathForPlatform('cypress/e2e/admin_users/admin.user/foo_list.spec.js'),
getPathForPlatform('cypress/e2e/test-isolation.spec.js'),
getPathForPlatform('cypress/e2e/test-isolation-describe-config.spec.js'),
getPathForPlatform('cypress/e2e/z001.spec.js'),
getPathForPlatform('cypress/e2e/z002.spec.js'),
getPathForPlatform('cypress/e2e/z003.spec.js'),
@@ -120,6 +121,7 @@ describe('specChange subscription', () => {
getPathForPlatform('cypress/e2e/admin_users/admin_users_list.spec.js'),
getPathForPlatform('cypress/e2e/admin_users/admin.user/foo_list.spec.js'),
getPathForPlatform('cypress/e2e/test-isolation.spec.js'),
getPathForPlatform('cypress/e2e/test-isolation-describe-config.spec.js'),
getPathForPlatform('cypress/e2e/z001.spec.js'),
getPathForPlatform('cypress/e2e/z002.spec.js'),
getPathForPlatform('cypress/e2e/z003.spec.js'),
@@ -190,7 +192,7 @@ e2e: {
cy.get('body').type('f')
cy.get('[data-cy="spec-file-item"]')
.should('have.length', 25)
.should('have.length', 26)
.should('contain', 'blank-contents.spec.js')
.should('contain', 'dom-container.spec.js')
.should('contain', 'dom-content.spec.js')
@@ -201,7 +203,7 @@ e2e: {
}, { path: getPathForPlatform('cypress/e2e/new-file.spec.js') })
cy.get('[data-cy="spec-file-item"]')
.should('have.length', 26)
.should('have.length', 27)
.should('contain', 'blank-contents.spec.js')
.should('contain', 'dom-container.spec.js')
.should('contain', 'dom-content.spec.js')
@@ -216,7 +218,7 @@ e2e: {
cy.get('body').type('f')
cy.get('[data-cy="spec-file-item"]')
.should('have.length', 25)
.should('have.length', 26)
.should('contain', 'blank-contents.spec.js')
.should('contain', 'dom-container.spec.js')
.should('contain', 'dom-content.spec.js')
@@ -227,7 +229,7 @@ e2e: {
}, { path: getPathForPlatform('cypress/e2e/dom-list.spec.js') })
cy.get('[data-cy="spec-file-item"]')
.should('have.length', 24)
.should('have.length', 25)
.should('contain', 'blank-contents.spec.js')
.should('contain', 'dom-container.spec.js')
.should('contain', 'dom-content.spec.js')
@@ -258,6 +260,7 @@ e2e: {
getPathForPlatform('cypress/e2e/admin_users/admin_users_list.spec.js'),
getPathForPlatform('cypress/e2e/admin_users/admin.user/foo_list.spec.js'),
getPathForPlatform('cypress/e2e/test-isolation.spec.js'),
getPathForPlatform('cypress/e2e/test-isolation-describe-config.spec.js'),
getPathForPlatform('cypress/e2e/z001.spec.js'),
getPathForPlatform('cypress/e2e/z002.spec.js'),
getPathForPlatform('cypress/e2e/z003.spec.js'),
@@ -289,7 +292,7 @@ e2e: {
cy.get('body').type('f')
cy.get('[data-cy="spec-file-item"]')
.should('have.length', 25)
.should('have.length', 26)
.should('contain', 'blank-contents.spec.js')
.should('contain', 'dom-container.spec.js')
.should('contain', 'dom-content.spec.js')
@@ -332,14 +335,14 @@ e2e: {
cy.get('[data-cy="spec-pattern"]').contains('cypress/e2e/**/*.spec.{js,ts}')
cy.get('[data-cy="file-match-indicator"]')
.should('contain', '25 matches')
.should('contain', '26 matches')
cy.withCtx(async (ctx, o) => {
await ctx.actions.file.writeFileInProject(o.path, '')
}, { path: getPathForPlatform('cypress/e2e/new-file.spec.js') })
cy.get('[data-cy="file-match-indicator"]')
.should('contain', '26 matches')
.should('contain', '27 matches')
})
it('responds to specChange event for a removed file', () => {
@@ -349,14 +352,14 @@ e2e: {
cy.get('[data-cy="spec-pattern"]').contains('cypress/e2e/**/*.spec.{js,ts}')
cy.get('[data-cy="file-match-indicator"]')
.should('contain', '25 matches')
.should('contain', '26 matches')
cy.withCtx(async (ctx, o) => {
await ctx.actions.file.removeFileInProject(o.path)
}, { path: getPathForPlatform('cypress/e2e/dom-list.spec.js') })
cy.get('[data-cy="file-match-indicator"]')
.should('contain', '24 matches')
.should('contain', '25 matches')
})
it('handles removing the last file', () => {
@@ -384,6 +387,7 @@ e2e: {
getPathForPlatform('cypress/e2e/admin_users/admin_users_list.spec.js'),
getPathForPlatform('cypress/e2e/admin_users/admin.user/foo_list.spec.js'),
getPathForPlatform('cypress/e2e/test-isolation.spec.js'),
getPathForPlatform('cypress/e2e/test-isolation-describe-config.spec.js'),
getPathForPlatform('cypress/e2e/z001.spec.js'),
getPathForPlatform('cypress/e2e/z002.spec.js'),
getPathForPlatform('cypress/e2e/z003.spec.js'),
@@ -414,7 +418,7 @@ e2e: {
cy.get('[data-cy="spec-pattern"]').contains('cypress/e2e/**/*.spec.{js,ts}')
cy.get('[data-cy="file-match-indicator"]')
.should('contain', '25 matches')
.should('contain', '26 matches')
cy.withCtx(async (ctx) => {
await ctx.actions.file.writeFileInProject('cypress.config.js',

View File

@@ -59,7 +59,7 @@ describe('cy.session', { retries: 0 }, () => {
.then(async () => {
cy.spy(Cypress, 'action').log(false)
await Cypress.action('runner:test:before:after:run:async', {}, Cypress.state('runnable'))
await Cypress.action('runner:test:before:after:run:async', {}, Cypress.state('runnable'), { nextTestHasTestIsolationOn: true })
expect(Cypress.action).to.be.calledWith('cy:url:changed', '')
expect(Cypress.action).to.be.calledWith('cy:visit:blank', { testIsolation: true })
@@ -68,7 +68,21 @@ describe('cy.session', { retries: 0 }, () => {
.should('eq', 'about:blank')
})
it('clears the browser cookie before each run', () => {
it('does not clear the page before the end of each run if the next test has test isolation off', () => {
cy.visit('/fixtures/form.html')
.then(async () => {
cy.spy(Cypress, 'action').log(false)
await Cypress.action('runner:test:before:after:run:async', {}, Cypress.state('runnable'), { nextTestHasTestIsolationOn: false })
expect(Cypress.action).not.to.be.calledWith('cy:url:changed', '')
expect(Cypress.action).not.to.be.calledWith('cy:visit:blank', { testIsolation: true })
})
.url()
.should('not.eq', 'about:blank')
})
it('clears the browser cookie after each run', () => {
cy.window()
.then((win) => {
win.cookie = 'key=value; SameSite=Strict; Secure; Path=/fixtures'
@@ -76,11 +90,25 @@ describe('cy.session', { retries: 0 }, () => {
.then(async () => {
cy.spy(Cypress, 'action').log(false)
await Cypress.action('runner:test:before:after:run:async', {}, Cypress.state('runnable'))
await Cypress.action('runner:test:before:after:run:async', {}, Cypress.state('runnable'), { nextTestHasTestIsolationOn: true })
})
cy.window().its('cookie').should('be.undefined')
})
it('does not clear the browser cookie after each run if the next test has test isolation off', () => {
cy.window()
.then((win) => {
win.cookie = 'key=value; SameSite=Strict; Secure; Path=/fixtures'
})
.then(async () => {
cy.spy(Cypress, 'action').log(false)
await Cypress.action('runner:test:before:after:run:async', {}, Cypress.state('runnable'), { nextTestHasTestIsolationOn: false })
})
cy.window().its('cookie').should('eq', 'key=value; SameSite=Strict; Secure; Path=/fixtures')
})
})
describe('test:before:run:async', () => {

View File

@@ -32,12 +32,12 @@ export default function (Commands, Cypress, cy) {
}
})
Cypress.on('test:before:after:run:async', () => {
if (!Cypress.config('testIsolation')) {
return
Cypress.on('test:before:after:run:async', (test, Cypress, { nextTestHasTestIsolationOn }: {nextTestHasTestIsolationOn?: boolean} = {}) => {
if (nextTestHasTestIsolationOn) {
return navigateAboutBlank({ inBetweenTestsAndNextTestHasTestIsolationOn: true })
}
return navigateAboutBlank()
return
})
Cypress.on('test:before:run:async', async () => {

View File

@@ -191,9 +191,11 @@ const getPostMessageLocalStorage = (specWindow, origins): Promise<any[]> => {
})
}
function navigateAboutBlank () {
// Component testing does not support navigation and handles clearing the page via mount utils
if (Cypress.testingType === 'component' || !Cypress.config('testIsolation')) {
function navigateAboutBlank ({ inBetweenTestsAndNextTestHasTestIsolationOn }: { inBetweenTestsAndNextTestHasTestIsolationOn?: boolean } = {}) {
// Component testing never supports navigating to about:blank as that is handled by its unmount mechanism
// When test isolation is off we typically don't navigate to about blank; however if we are in between tests and the next
// test has test isolation on, we need to navigate to about blank to ensure the next test is not affected by the previous test
if (Cypress.testingType === 'component' || (!Cypress.config('testIsolation') && !inBetweenTestsAndNextTestHasTestIsolationOn)) {
return Promise.resolve()
}

View File

@@ -46,7 +46,7 @@ const duration = (before: Date, after: Date) => {
return Number(before) - Number(after)
}
const fire = (event: typeof RUNNER_EVENTS[number], runnable, Cypress) => {
const fire = (event: typeof RUNNER_EVENTS[number], runnable, Cypress, ...args) => {
debug('fire: %o', { event })
if (runnable._fired == null) {
runnable._fired = {}
@@ -59,7 +59,7 @@ const fire = (event: typeof RUNNER_EVENTS[number], runnable, Cypress) => {
return
}
return Cypress.action(event, wrap(runnable), runnable)
return Cypress.action(event, wrap(runnable), runnable, ...args)
}
const fired = (event: typeof RUNNER_EVENTS[number], runnable) => {
@@ -74,10 +74,10 @@ const testBeforeRunAsync = (test, Cypress) => {
})
}
const testBeforeAfterRunAsync = (test, Cypress) => {
const testBeforeAfterRunAsync = (test, Cypress, ...args) => {
return Promise.try(() => {
if (!fired(TEST_BEFORE_AFTER_RUN_ASYNC_EVENT, test)) {
return fire(TEST_BEFORE_AFTER_RUN_ASYNC_EVENT, test, Cypress)
return fire(TEST_BEFORE_AFTER_RUN_ASYNC_EVENT, test, Cypress, ...args)
}
})
}
@@ -369,6 +369,16 @@ const lastTestThatWillRunInSuite = (test, tests) => {
return isLastTest(test, tests) || (test.failedFromHookId && (test.hookName === 'before all'))
}
const nextTestThatWillRunInSuite = (test, tests) => {
if (test.failedFromHookId && (test.hookName === 'before all')) {
return null
}
const index = _.findIndex(tests, { id: test.id })
return index < tests.length - 1 ? tests[index + 1] : null
}
const isLastTest = (test, tests) => {
return test.id === _.get(_.last(tests), 'id')
}
@@ -497,6 +507,11 @@ const overrideRunnerHook = (Cypress, _runner, getTestById, getTest, setTest, get
// If we're not in open mode or we're in open mode and not the last test we reset state.
// The last test will needs to stay so that the user can see what the end result of the AUT was.
if (shouldAlwaysResetPage || !lastTestThatWillRunInSuite(test, getAllSiblingTests(topSuite, getTestById))) {
const nextTest = nextTestThatWillRunInSuite(test, getAllSiblingTests(topSuite, getTestById))
const nextTestIsolationOverride = nextTest?._testConfig.unverifiedTestConfig.testIsolation
const topLevelTestIsolation = Cypress.originalConfig['testIsolation']
const nextTestHasTestIsolationOn = nextTestIsolationOverride || (nextTestIsolationOverride === undefined && topLevelTestIsolation)
cy.state('duringUserTestExecution', false)
Cypress.primaryOriginCommunicator.toAllSpecBridges('sync:state', { 'duringUserTestExecution': false })
// Remove window:load and window:before:load listeners so that navigating to about:blank doesn't fire in user code.
@@ -505,7 +520,7 @@ const overrideRunnerHook = (Cypress, _runner, getTestById, getTest, setTest, get
cy.removeAllListeners('window:load')
// This will navigate to about:blank if test isolation is on
await testBeforeAfterRunAsync(test, Cypress)
await testBeforeAfterRunAsync(test, Cypress, { nextTestHasTestIsolationOn })
}
testAfterRun(test, Cypress)

View File

@@ -633,7 +633,6 @@ module.exports = {
},
getCaptureProtocolScript (url: string) {
// TODO(protocol): Ensure this is removed in production
if (process.env.CYPRESS_LOCAL_PROTOCOL_PATH) {
debugProtocol(`Loading protocol via script at local path %s`, process.env.CYPRESS_LOCAL_PROTOCOL_PATH)

View File

@@ -6,7 +6,7 @@ const path = require('path')
const { setupV8Snapshots } = require('@tooling/v8-snapshot')
const { flipFuses, FuseVersion, FuseV1Options } = require('@electron/fuses')
const { buildEntryPointAndCleanup } = require('./binary/binary-cleanup')
const { getIntegrityCheckSource, getBinaryEntryPointSource, getEncryptionFileSource, getCloudApiFileSource, validateEncryptionFile } = require('./binary/binary-sources')
const { getIntegrityCheckSource, getBinaryEntryPointSource, getEncryptionFileSource, getCloudEnvironmentFileSource, validateEncryptionFile, getProtocolFileSource, validateCloudEnvironmentFile, validateProtocolFile } = require('./binary/binary-sources')
const CY_ROOT_DIR = path.join(__dirname, '..')
@@ -61,18 +61,26 @@ module.exports = async function (params) {
const binaryEntryPointSource = await getBinaryEntryPointSource()
const encryptionFilePath = path.join(CY_ROOT_DIR, 'packages/server/lib/cloud/encryption.ts')
const encryptionFileSource = await getEncryptionFileSource(encryptionFilePath)
const cloudApiFilePath = path.join(CY_ROOT_DIR, 'packages/server/lib/cloud/environment.ts')
const cloudApiFileSource = await getCloudApiFileSource(cloudApiFilePath)
const cloudEnvironmentFilePath = path.join(CY_ROOT_DIR, 'packages/server/lib/cloud/environment.ts')
const cloudEnvironmentFileSource = await getCloudEnvironmentFileSource(cloudEnvironmentFilePath)
const cloudApiFilePath = path.join(CY_ROOT_DIR, 'packages/server/lib/cloud/api.ts')
const cloudApiFileSource = await getProtocolFileSource(cloudApiFilePath)
const cloudProtocolFilePath = path.join(CY_ROOT_DIR, 'packages/server/lib/cloud/protocol.ts')
const cloudProtocolFileSource = await getProtocolFileSource(cloudProtocolFilePath)
await Promise.all([
fs.writeFile(encryptionFilePath, encryptionFileSource),
fs.writeFile(cloudEnvironmentFilePath, cloudEnvironmentFileSource),
fs.writeFile(cloudApiFilePath, cloudApiFileSource),
fs.writeFile(cloudProtocolFilePath, cloudProtocolFileSource),
fs.writeFile(path.join(outputFolder, 'index.js'), binaryEntryPointSource),
])
await Promise.all([
validateEncryptionFile(encryptionFilePath),
validateEncryptionFile(cloudApiFilePath),
validateCloudEnvironmentFile(cloudEnvironmentFilePath),
validateProtocolFile(cloudApiFilePath),
validateProtocolFile(cloudProtocolFilePath),
])
await flipFuses(

View File

@@ -58,7 +58,7 @@ const validateEncryptionFile = async (encryptionFilePath) => {
}
}
const getCloudApiFileSource = async (cloudApiFilePath) => {
const getCloudEnvironmentFileSource = async (cloudApiFilePath) => {
const fileContents = await fs.readFile(cloudApiFilePath, 'utf8')
if (!fileContents.includes('process.env.CYPRESS_ENV_DEPENDENCIES')) {
@@ -72,7 +72,7 @@ const getCloudApiFileSource = async (cloudApiFilePath) => {
return fileContents
}
const validateCloudApiFile = async (cloudApiFilePath) => {
const validateCloudEnvironmentFile = async (cloudApiFilePath) => {
if (process.env.CYPRESS_ENV_DEPENDENCIES) {
const afterReplaceCloudApi = await fs.readFile(cloudApiFilePath, 'utf8')
@@ -82,11 +82,31 @@ const validateCloudApiFile = async (cloudApiFilePath) => {
}
}
const getProtocolFileSource = async (protocolFilePath) => {
const fileContents = await fs.readFile(protocolFilePath, 'utf8')
if (!fileContents.includes('process.env.CYPRESS_LOCAL_PROTOCOL_PATH')) {
throw new Error(`Expected to find CYPRESS_LOCAL_PROTOCOL_PATH in protocol file`)
}
return fileContents.replaceAll('process.env.CYPRESS_LOCAL_PROTOCOL_PATH', 'undefined')
}
const validateProtocolFile = async (protocolFilePath) => {
const afterReplaceProtocol = await fs.readFile(protocolFilePath, 'utf8')
if (afterReplaceProtocol.includes('process.env.CYPRESS_LOCAL_PROTOCOL_PATH')) {
throw new Error(`Expected process.env.CYPRESS_LOCAL_PROTOCOL_PATH to be stripped from protocol file`)
}
}
module.exports = {
getBinaryEntryPointSource,
getIntegrityCheckSource,
getEncryptionFileSource,
getCloudApiFileSource,
validateCloudApiFile,
validateEncryptionFile,
getCloudEnvironmentFileSource,
validateCloudEnvironmentFile,
getProtocolFileSource,
validateProtocolFile,
}

View File

@@ -0,0 +1,132 @@
const shouldAlwaysResetPage = (config) => {
const isRunMode = !config('isInteractive')
const isHeadedNoExit = config('browser').isHeaded && !config('exit')
return isRunMode && !isHeadedNoExit
}
const TEST_METADATA = {
'passes 1': {
start: 'about:blank',
firesTestBeforeAfterRunAsync: true,
end: 'about:blank',
},
'passes 2': {
start: 'about:blank',
firesTestBeforeAfterRunAsync: true,
end: '/cypress/e2e/dom-content.html',
},
'passes 3': {
start: '/cypress/e2e/dom-content.html',
firesTestBeforeAfterRunAsync: true,
end: '/cypress/e2e/dom-content.html',
},
'passes 4': {
start: '/cypress/e2e/dom-content.html',
firesTestBeforeAfterRunAsync: true,
end: 'about:blank',
},
'passes 5': {
start: 'about:blank',
firesTestBeforeAfterRunAsync: true,
end: 'about:blank',
},
'passes 6': {
start: 'about:blank',
firesTestBeforeAfterRunAsync: true,
end: shouldAlwaysResetPage(Cypress.config) ? 'about:blank' : '/cypress/e2e/dom-content.html',
},
}
let cypressEventsHandled = 0
const testBeforeRun = (Cypress, ...args) => {
expect(Cypress.state('window').location.href.endsWith(TEST_METADATA[args[1].title].start)).to.equal(true)
cypressEventsHandled += 1
}
const testBeforeRunAsync = (Cypress, ...args) => {
expect(Cypress.state('window').location.href.endsWith(TEST_METADATA[args[1].title].start)).to.equal(true)
cypressEventsHandled += 1
}
const testBeforeAfterRunAsync = (Cypress, ...args) => {
expect(TEST_METADATA[args[1].title].firesTestBeforeAfterRunAsync).to.be.true
cypressEventsHandled += 1
}
const testAfterRun = (Cypress, ...args) => {
expect(Cypress.state('window').location.href.endsWith(TEST_METADATA[args[1].title].end)).to.equal(true)
cypressEventsHandled += 1
}
const testAfterRunAsync = (Cypress, ...args) => {
expect(Cypress.state('window').location.href.endsWith(TEST_METADATA[args[1].title].end)).to.equal(true)
cypressEventsHandled += 1
}
const cypressEvents = [
['test:before:run', testBeforeRun],
['test:before:run:async', testBeforeRunAsync],
['test:before:after:run:async', testBeforeAfterRunAsync],
['test:after:run', testAfterRun],
['test:after:run:async', testAfterRunAsync],
]
cypressEvents.forEach(([event, handler]) => {
Cypress.prependListener(event, (...args) => {
handler(Cypress, ...args)
})
})
Cypress.on('test:after:run:async', async (test) => {
if (test.title === 'passes 1') {
expect(cypressEventsHandled).to.equal(5)
} else if (test.title === 'passes 2') {
expect(cypressEventsHandled).to.equal(10)
} else if (test.title === 'passes 3') {
expect(cypressEventsHandled).to.equal(15)
} else if (test.title === 'passes 4') {
expect(cypressEventsHandled).to.equal(20)
} else if (test.title === 'passes 5') {
expect(cypressEventsHandled).to.equal(25)
} else if (test.title === 'passes 6') {
expect(cypressEventsHandled).to.equal(!shouldAlwaysResetPage(Cypress.config) ? 29 : 30)
}
})
describe('test isolation', () => {
beforeEach(() => {
cy.visit('cypress/e2e/dom-content.html')
})
describe('suite 1', { testIsolation: true }, () => {
it('passes 1', () => {
expect(true).to.equal(true)
})
it('passes 2', () => {
expect(true).to.equal(true)
})
})
describe('suite 2', { testIsolation: false }, () => {
it('passes 3', () => {
expect(true).to.equal(true)
})
it('passes 4', () => {
expect(true).to.equal(true)
})
})
describe('suite 3', { testIsolation: true }, () => {
it('passes 5', () => {
expect(true).to.equal(true)
})
it('passes 6', () => {
expect(true).to.equal(true)
})
})
})

View File

@@ -12,6 +12,14 @@ describe('Test Isolation', () => {
browser: 'chrome',
})
systemTests.it('fires events in the right order with the right arguments when overridden within the spec - run mode', {
project: 'cypress-in-cypress',
spec: 'test-isolation-describe-config.spec.js',
expectedExitCode: 0,
timeout: 20000,
browser: 'chrome',
})
systemTests.it('fires events in the right order with the right arguments - headed: true - noExit: true', {
config: {
env: {