mirror of
https://github.com/cypress-io/cypress.git
synced 2026-02-23 07:39:52 -06:00
feat: Add after:spec event (#14178)
This commit is contained in:
@@ -1,4 +1,13 @@
|
||||
exports['e2e plugin run events / sends server events'] = `
|
||||
exports['e2e plugin run events / fails if experimentalRunEvents is not enabled'] = `
|
||||
The following validation error was thrown by your plugins file (\`/foo/bar/.projects/plugin-run-events/cypress/plugins/index.js\`).
|
||||
|
||||
Error: The \`before:spec\` event requires the experimentalRunEvents flag to be enabled.
|
||||
|
||||
To enable it, set \`"experimentalRunEvents": true\` in your cypress.json
|
||||
[stack trace lines]
|
||||
`
|
||||
|
||||
exports['e2e plugin run events / sends events'] = `
|
||||
|
||||
====================================================================================================
|
||||
|
||||
@@ -39,6 +48,8 @@ before:spec is awaited
|
||||
│ Spec Ran: run_events_spec_1.js │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
spec:end: cypress/integration/run_events_spec_1.js { tests: 1, passes: 1, failures: 0 }
|
||||
after:spec is awaited
|
||||
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -66,6 +77,8 @@ before:spec is awaited
|
||||
│ Spec Ran: run_events_spec_2.js │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
spec:end: cypress/integration/run_events_spec_2.js { tests: 1, passes: 1, failures: 0 }
|
||||
after:spec is awaited
|
||||
|
||||
====================================================================================================
|
||||
|
||||
@@ -83,7 +96,7 @@ before:spec is awaited
|
||||
|
||||
`
|
||||
|
||||
exports['e2e plugin run events / fails run if server event handler throws'] = `
|
||||
exports['e2e plugin run events / fails run if event handler throws'] = `
|
||||
|
||||
====================================================================================================
|
||||
|
||||
@@ -110,12 +123,3 @@ Error: error thrown in before:spec
|
||||
|
||||
|
||||
`
|
||||
|
||||
exports['e2e plugin run events / fails if experimentalRunEvents is not enabled'] = `
|
||||
The following validation error was thrown by your plugins file (\`/foo/bar/.projects/plugin-run-events/cypress/plugins/index.js\`).
|
||||
|
||||
Error: The \`before:spec\` event requires the experimentalRunEvents flag to be enabled.
|
||||
|
||||
To enable it, set \`"experimentalRunEvents": true\` in your cypress.json
|
||||
[stack trace lines]
|
||||
`
|
||||
|
||||
@@ -53,7 +53,7 @@ interface StringValues {
|
||||
const _summaries: StringValues = {
|
||||
experimentalComponentTesting: 'Framework-specific component testing, uses `componentFolder` to load component specs.',
|
||||
experimentalFetchPolyfill: 'Polyfills `window.fetch` to enable Network spying and stubbing.',
|
||||
experimentalRunEvents: 'Allows listening to the `before:spec` event in the plugins file.',
|
||||
experimentalRunEvents: 'Allows listening to the `before:spec` and `after:spec` events in the plugins file.',
|
||||
experimentalSourceRewriting: 'Enables AST-based JS/HTML rewriting. This may fix issues caused by the existing regex-based JS/HTML replacement algorithm.',
|
||||
}
|
||||
|
||||
|
||||
@@ -1080,7 +1080,7 @@ module.exports = {
|
||||
},
|
||||
|
||||
waitForTestsToFinishRunning (options = {}) {
|
||||
const { project, screenshots, startedVideoCapture, endVideoCapture, videoName, compressedVideoName, videoCompression, videoUploadOnPasses, exit, spec, estimated, quiet } = options
|
||||
const { project, screenshots, startedVideoCapture, endVideoCapture, videoName, compressedVideoName, videoCompression, videoUploadOnPasses, exit, spec, estimated, quiet, config } = options
|
||||
|
||||
// https://github.com/cypress-io/cypress/issues/2370
|
||||
// delay 1 second if we're recording a video to give
|
||||
@@ -1090,8 +1090,8 @@ module.exports = {
|
||||
|
||||
return this.listenForProjectEnd(project, exit)
|
||||
.delay(delay)
|
||||
.then(async (obj) => {
|
||||
_.defaults(obj, {
|
||||
.then(async (results) => {
|
||||
_.defaults(results, {
|
||||
error: null,
|
||||
hooks: null,
|
||||
tests: null,
|
||||
@@ -1101,27 +1101,23 @@ module.exports = {
|
||||
})
|
||||
|
||||
if (startedVideoCapture) {
|
||||
obj.video = videoName
|
||||
results.video = videoName
|
||||
}
|
||||
|
||||
if (screenshots) {
|
||||
obj.screenshots = screenshots
|
||||
results.screenshots = screenshots
|
||||
}
|
||||
|
||||
obj.spec = spec
|
||||
|
||||
const finish = () => {
|
||||
return obj
|
||||
}
|
||||
results.spec = spec
|
||||
|
||||
if (!quiet) {
|
||||
this.displayResults(obj, estimated)
|
||||
this.displayResults(results, estimated)
|
||||
if (screenshots && screenshots.length) {
|
||||
this.displayScreenshots(screenshots)
|
||||
}
|
||||
}
|
||||
|
||||
const { tests, stats } = obj
|
||||
const { tests, stats } = results
|
||||
|
||||
const attempts = _.flatMap(tests, (test) => test.attempts)
|
||||
|
||||
@@ -1137,7 +1133,7 @@ module.exports = {
|
||||
// or if we have any failures and have started the video
|
||||
const suv = Boolean(videoUploadOnPasses === true || (startedVideoCapture && hasFailingTests))
|
||||
|
||||
obj.shouldUploadVideo = suv
|
||||
results.shouldUploadVideo = suv
|
||||
|
||||
let videoCaptureFailed = false
|
||||
|
||||
@@ -1147,6 +1143,8 @@ module.exports = {
|
||||
.catch(warnVideoRecordingFailed)
|
||||
}
|
||||
|
||||
await runEvents.execute('after:spec', config, _.cloneDeep(spec), _.cloneDeep(results))
|
||||
|
||||
// always close the browser now as opposed to letting
|
||||
// it exit naturally with the parent process due to
|
||||
// electron bug in windows
|
||||
@@ -1154,7 +1152,7 @@ module.exports = {
|
||||
await openProject.closeBrowser()
|
||||
|
||||
if (endVideoCapture && !videoCaptureFailed) {
|
||||
const ffmpegChaptersConfig = videoCapture.generateFfmpegChaptersConfig(obj.tests)
|
||||
const ffmpegChaptersConfig = videoCapture.generateFfmpegChaptersConfig(results.tests)
|
||||
|
||||
await this.postProcessRecording(
|
||||
videoName,
|
||||
@@ -1167,7 +1165,7 @@ module.exports = {
|
||||
.catch(warnVideoRecordingFailed)
|
||||
}
|
||||
|
||||
return finish()
|
||||
return results
|
||||
})
|
||||
},
|
||||
|
||||
@@ -1322,7 +1320,7 @@ module.exports = {
|
||||
|
||||
const screenshots = []
|
||||
|
||||
return runEvents.execute('before:spec', config, spec)
|
||||
return runEvents.execute('before:spec', config, _.cloneDeep(spec))
|
||||
.then(() => {
|
||||
// we know we're done running headlessly
|
||||
// when the renderer has connected and
|
||||
@@ -1340,6 +1338,7 @@ module.exports = {
|
||||
return Promise.props({
|
||||
results: this.waitForTestsToFinishRunning({
|
||||
spec,
|
||||
config,
|
||||
project,
|
||||
estimated,
|
||||
screenshots,
|
||||
|
||||
@@ -111,6 +111,9 @@ const execute = (ipc, event, ids, args = []) => {
|
||||
'after:screenshot' () {
|
||||
util.wrapChildPromise(ipc, invoke, ids, args)
|
||||
},
|
||||
'after:spec' () {
|
||||
util.wrapChildPromise(ipc, invoke, ids, args)
|
||||
},
|
||||
'before:browser:launch' () {
|
||||
browserLaunch.wrap(ipc, invoke, ids, args)
|
||||
},
|
||||
|
||||
@@ -34,8 +34,13 @@ const eventValidators = {
|
||||
'_get:task:body': isFunction,
|
||||
}
|
||||
|
||||
const runEvents = {
|
||||
'after:spec': true,
|
||||
'before:spec': true,
|
||||
}
|
||||
|
||||
const validateEvent = (event, handler, config) => {
|
||||
if (event === 'before:spec') {
|
||||
if (runEvents[event]) {
|
||||
return isValidRunEvent(event, handler, config)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ const errors = require('../errors')
|
||||
const plugins = require('../plugins')
|
||||
|
||||
module.exports = {
|
||||
execute: Promise.method((eventName, config, ...args) => {
|
||||
execute: Promise.method((eventName, config = {}, ...args) => {
|
||||
if (!config.experimentalRunEvents) return
|
||||
|
||||
if (!plugins.has(eventName)) return
|
||||
|
||||
@@ -4,7 +4,7 @@ import Fixtures from '../support/helpers/fixtures'
|
||||
describe('e2e plugin run events', () => {
|
||||
e2e.setup()
|
||||
|
||||
e2e.it('sends server events', {
|
||||
e2e.it('sends events', {
|
||||
browser: 'electron',
|
||||
project: Fixtures.projectPath('plugin-run-events'),
|
||||
spec: '*',
|
||||
@@ -26,7 +26,7 @@ describe('e2e plugin run events', () => {
|
||||
},
|
||||
})
|
||||
|
||||
e2e.it('fails run if server event handler throws', {
|
||||
e2e.it('fails run if event handler throws', {
|
||||
browser: 'electron',
|
||||
project: Fixtures.projectPath('plugin-run-event-throws'),
|
||||
spec: '*',
|
||||
|
||||
@@ -9,4 +9,15 @@ module.exports = (on) => {
|
||||
return console.log('before:spec is awaited')
|
||||
})
|
||||
})
|
||||
|
||||
on('after:spec', (spec, results) => {
|
||||
const { stats } = results
|
||||
const { tests, passes, failures } = stats
|
||||
|
||||
console.log('spec:end:', spec.relative, { tests, passes, failures })
|
||||
|
||||
return Promise.delay(10).then(() => {
|
||||
return console.log('after:spec is awaited')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -68,26 +68,33 @@ The following are valid events:
|
||||
})
|
||||
|
||||
describe('run events', () => {
|
||||
it('returns error when before:spec event is registered without experimentalRunEvents flag enabled', () => {
|
||||
const { isValid, error } = validateEvent('before:spec', {}, { experimentalRunEvents: false })
|
||||
const runEvents = [
|
||||
'before:spec',
|
||||
'after:spec',
|
||||
]
|
||||
|
||||
expect(isValid).to.be.false
|
||||
expect(error.message).to.equal(`The \`before:spec\` event requires the experimentalRunEvents flag to be enabled.
|
||||
_.each(runEvents, (event) => {
|
||||
it(`returns error when ${event} event is registed without experimentalRunEvents flag enabled`, () => {
|
||||
const { isValid, error } = validateEvent(event, {}, { experimentalRunEvents: false })
|
||||
|
||||
expect(isValid).to.be.false
|
||||
expect(error.message).to.equal(`The \`${event}\` event requires the experimentalRunEvents flag to be enabled.
|
||||
|
||||
To enable it, set \`"experimentalRunEvents": true\` in your cypress.json`)
|
||||
})
|
||||
})
|
||||
|
||||
it('returns error when event handler of before:spec is not a function', () => {
|
||||
const { isValid, error } = validateEvent('before:spec', 'invalid type', { experimentalRunEvents: true })
|
||||
it(`returns error when event handler of ${event} is not a function`, () => {
|
||||
const { isValid, error } = validateEvent(event, 'invalid type', { experimentalRunEvents: true })
|
||||
|
||||
expect(isValid).to.be.false
|
||||
expect(error.message).to.equal(`The handler for the event \`before:spec\` must be a function`)
|
||||
})
|
||||
expect(isValid).to.be.false
|
||||
expect(error.message).to.equal(`The handler for the event \`${event}\` must be a function`)
|
||||
})
|
||||
|
||||
it('returns success when event handler of before:spec is a function', () => {
|
||||
const { isValid } = validateEvent('before:spec', () => {}, { experimentalRunEvents: true })
|
||||
it(`returns success when event handler of ${event} is a function`, () => {
|
||||
const { isValid } = validateEvent(event, () => {}, { experimentalRunEvents: true })
|
||||
|
||||
expect(isValid).to.be.true
|
||||
expect(isValid).to.be.true
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user