codeceptjs 4.0.0-beta.3 → 4.0.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +134 -119
- package/bin/codecept.js +12 -2
- package/bin/test-server.js +53 -0
- package/docs/webapi/clearCookie.mustache +1 -1
- package/lib/actor.js +66 -102
- package/lib/ai.js +130 -121
- package/lib/assert/empty.js +3 -5
- package/lib/assert/equal.js +4 -7
- package/lib/assert/include.js +4 -6
- package/lib/assert/throws.js +2 -4
- package/lib/assert/truth.js +2 -2
- package/lib/codecept.js +141 -86
- package/lib/command/check.js +201 -0
- package/lib/command/configMigrate.js +2 -4
- package/lib/command/definitions.js +8 -26
- package/lib/command/dryRun.js +30 -35
- package/lib/command/generate.js +10 -14
- package/lib/command/gherkin/snippets.js +75 -73
- package/lib/command/gherkin/steps.js +1 -1
- package/lib/command/info.js +42 -8
- package/lib/command/init.js +13 -12
- package/lib/command/interactive.js +10 -2
- package/lib/command/list.js +1 -1
- package/lib/command/run-multiple/chunk.js +48 -45
- package/lib/command/run-multiple.js +12 -35
- package/lib/command/run-workers.js +21 -58
- package/lib/command/utils.js +5 -6
- package/lib/command/workers/runTests.js +263 -222
- package/lib/container.js +386 -238
- package/lib/data/context.js +10 -13
- package/lib/data/dataScenarioConfig.js +8 -8
- package/lib/data/dataTableArgument.js +6 -6
- package/lib/data/table.js +5 -11
- package/lib/effects.js +223 -0
- package/lib/element/WebElement.js +327 -0
- package/lib/els.js +158 -0
- package/lib/event.js +21 -17
- package/lib/heal.js +88 -80
- package/lib/helper/AI.js +2 -1
- package/lib/helper/ApiDataFactory.js +4 -7
- package/lib/helper/Appium.js +50 -57
- package/lib/helper/FileSystem.js +3 -3
- package/lib/helper/GraphQLDataFactory.js +4 -4
- package/lib/helper/JSONResponse.js +75 -37
- package/lib/helper/Mochawesome.js +31 -9
- package/lib/helper/Nightmare.js +37 -58
- package/lib/helper/Playwright.js +267 -272
- package/lib/helper/Protractor.js +56 -87
- package/lib/helper/Puppeteer.js +247 -264
- package/lib/helper/REST.js +29 -17
- package/lib/helper/TestCafe.js +22 -47
- package/lib/helper/WebDriver.js +157 -368
- package/lib/helper/extras/PlaywrightPropEngine.js +2 -2
- package/lib/helper/extras/Popup.js +22 -22
- package/lib/helper/network/utils.js +1 -1
- package/lib/helper/testcafe/testcafe-utils.js +27 -28
- package/lib/listener/emptyRun.js +55 -0
- package/lib/listener/exit.js +7 -10
- package/lib/listener/{retry.js → globalRetry.js} +5 -5
- package/lib/listener/globalTimeout.js +165 -0
- package/lib/listener/helpers.js +15 -15
- package/lib/listener/mocha.js +1 -1
- package/lib/listener/result.js +12 -0
- package/lib/listener/retryEnhancer.js +85 -0
- package/lib/listener/steps.js +32 -18
- package/lib/listener/store.js +20 -0
- package/lib/locator.js +1 -1
- package/lib/mocha/asyncWrapper.js +231 -0
- package/lib/{interfaces → mocha}/bdd.js +3 -3
- package/lib/mocha/cli.js +308 -0
- package/lib/mocha/factory.js +104 -0
- package/lib/{interfaces → mocha}/featureConfig.js +32 -12
- package/lib/{interfaces → mocha}/gherkin.js +26 -28
- package/lib/mocha/hooks.js +112 -0
- package/lib/mocha/index.js +12 -0
- package/lib/mocha/inject.js +29 -0
- package/lib/{interfaces → mocha}/scenarioConfig.js +31 -7
- package/lib/mocha/suite.js +82 -0
- package/lib/mocha/test.js +181 -0
- package/lib/mocha/types.d.ts +42 -0
- package/lib/mocha/ui.js +232 -0
- package/lib/output.js +93 -65
- package/lib/pause.js +160 -138
- package/lib/plugin/analyze.js +396 -0
- package/lib/plugin/auth.js +435 -0
- package/lib/plugin/autoDelay.js +8 -8
- package/lib/plugin/autoLogin.js +3 -338
- package/lib/plugin/commentStep.js +6 -1
- package/lib/plugin/coverage.js +10 -22
- package/lib/plugin/customLocator.js +3 -3
- package/lib/plugin/customReporter.js +52 -0
- package/lib/plugin/eachElement.js +1 -1
- package/lib/plugin/fakerTransform.js +1 -1
- package/lib/plugin/heal.js +36 -9
- package/lib/plugin/htmlReporter.js +1947 -0
- package/lib/plugin/pageInfo.js +140 -0
- package/lib/plugin/retryFailedStep.js +17 -18
- package/lib/plugin/retryTo.js +2 -113
- package/lib/plugin/screenshotOnFail.js +17 -58
- package/lib/plugin/selenoid.js +15 -35
- package/lib/plugin/standardActingHelpers.js +4 -1
- package/lib/plugin/stepByStepReport.js +56 -17
- package/lib/plugin/stepTimeout.js +5 -12
- package/lib/plugin/subtitles.js +4 -4
- package/lib/plugin/tryTo.js +3 -102
- package/lib/plugin/wdio.js +8 -10
- package/lib/recorder.js +155 -124
- package/lib/rerun.js +43 -42
- package/lib/result.js +161 -0
- package/lib/secret.js +1 -2
- package/lib/step/base.js +239 -0
- package/lib/step/comment.js +10 -0
- package/lib/step/config.js +50 -0
- package/lib/step/func.js +46 -0
- package/lib/step/helper.js +50 -0
- package/lib/step/meta.js +99 -0
- package/lib/step/record.js +74 -0
- package/lib/step/retry.js +11 -0
- package/lib/step/section.js +55 -0
- package/lib/step.js +21 -332
- package/lib/steps.js +50 -0
- package/lib/store.js +37 -5
- package/lib/template/heal.js +2 -11
- package/lib/test-server.js +323 -0
- package/lib/timeout.js +66 -0
- package/lib/utils.js +351 -218
- package/lib/within.js +75 -55
- package/lib/workerStorage.js +2 -1
- package/lib/workers.js +386 -277
- package/package.json +81 -75
- package/translations/de-DE.js +5 -3
- package/translations/fr-FR.js +5 -4
- package/translations/index.js +1 -0
- package/translations/it-IT.js +4 -3
- package/translations/ja-JP.js +4 -3
- package/translations/nl-NL.js +76 -0
- package/translations/pl-PL.js +4 -3
- package/translations/pt-BR.js +4 -3
- package/translations/ru-RU.js +4 -3
- package/translations/utils.js +9 -0
- package/translations/zh-CN.js +4 -3
- package/translations/zh-TW.js +4 -3
- package/typings/index.d.ts +197 -187
- package/typings/promiseBasedTypes.d.ts +53 -903
- package/typings/types.d.ts +372 -1042
- package/lib/cli.js +0 -257
- package/lib/helper/ExpectHelper.js +0 -391
- package/lib/helper/MockServer.js +0 -221
- package/lib/helper/SoftExpectHelper.js +0 -381
- package/lib/listener/artifacts.js +0 -19
- package/lib/listener/timeout.js +0 -109
- package/lib/mochaFactory.js +0 -113
- package/lib/plugin/debugErrors.js +0 -67
- package/lib/scenario.js +0 -224
- package/lib/ui.js +0 -236
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const event = require('../event')
|
|
2
|
+
const { enhanceMochaTest } = require('../mocha/test')
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Enhance retried tests by copying CodeceptJS-specific properties from the original test
|
|
6
|
+
* This fixes the issue where Mocha's shallow clone during retries loses CodeceptJS properties
|
|
7
|
+
*/
|
|
8
|
+
module.exports = function () {
|
|
9
|
+
event.dispatcher.on(event.test.before, test => {
|
|
10
|
+
// Check if this test is a retry (has a reference to the original test)
|
|
11
|
+
const originalTest = test.retriedTest && test.retriedTest()
|
|
12
|
+
|
|
13
|
+
if (originalTest) {
|
|
14
|
+
// This is a retried test - copy CodeceptJS-specific properties from the original
|
|
15
|
+
copyCodeceptJSProperties(originalTest, test)
|
|
16
|
+
|
|
17
|
+
// Ensure the test is enhanced with CodeceptJS functionality
|
|
18
|
+
enhanceMochaTest(test)
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Copy CodeceptJS-specific properties from the original test to the retried test
|
|
25
|
+
* @param {CodeceptJS.Test} originalTest - The original test object
|
|
26
|
+
* @param {CodeceptJS.Test} retriedTest - The retried test object
|
|
27
|
+
*/
|
|
28
|
+
function copyCodeceptJSProperties(originalTest, retriedTest) {
|
|
29
|
+
// Copy CodeceptJS-specific properties
|
|
30
|
+
if (originalTest.opts !== undefined) {
|
|
31
|
+
retriedTest.opts = originalTest.opts ? { ...originalTest.opts } : {}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (originalTest.tags !== undefined) {
|
|
35
|
+
retriedTest.tags = originalTest.tags ? [...originalTest.tags] : []
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (originalTest.notes !== undefined) {
|
|
39
|
+
retriedTest.notes = originalTest.notes ? [...originalTest.notes] : []
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (originalTest.meta !== undefined) {
|
|
43
|
+
retriedTest.meta = originalTest.meta ? { ...originalTest.meta } : {}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (originalTest.artifacts !== undefined) {
|
|
47
|
+
retriedTest.artifacts = originalTest.artifacts ? [...originalTest.artifacts] : []
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (originalTest.steps !== undefined) {
|
|
51
|
+
retriedTest.steps = originalTest.steps ? [...originalTest.steps] : []
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (originalTest.config !== undefined) {
|
|
55
|
+
retriedTest.config = originalTest.config ? { ...originalTest.config } : {}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (originalTest.inject !== undefined) {
|
|
59
|
+
retriedTest.inject = originalTest.inject ? { ...originalTest.inject } : {}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Copy methods that might be missing
|
|
63
|
+
if (originalTest.addNote && !retriedTest.addNote) {
|
|
64
|
+
retriedTest.addNote = function (type, note) {
|
|
65
|
+
this.notes = this.notes || []
|
|
66
|
+
this.notes.push({ type, text: note })
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (originalTest.applyOptions && !retriedTest.applyOptions) {
|
|
71
|
+
retriedTest.applyOptions = originalTest.applyOptions.bind(retriedTest)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (originalTest.simplify && !retriedTest.simplify) {
|
|
75
|
+
retriedTest.simplify = originalTest.simplify.bind(retriedTest)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Preserve the uid if it exists
|
|
79
|
+
if (originalTest.uid !== undefined) {
|
|
80
|
+
retriedTest.uid = originalTest.uid
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Mark as enhanced
|
|
84
|
+
retriedTest.codeceptjs = true
|
|
85
|
+
}
|
package/lib/listener/steps.js
CHANGED
|
@@ -2,47 +2,55 @@ const debug = require('debug')('codeceptjs:steps')
|
|
|
2
2
|
const event = require('../event')
|
|
3
3
|
const store = require('../store')
|
|
4
4
|
const output = require('../output')
|
|
5
|
+
const { BeforeHook, AfterHook, BeforeSuiteHook, AfterSuiteHook } = require('../mocha/hooks')
|
|
6
|
+
const recorder = require('../recorder')
|
|
5
7
|
|
|
6
8
|
let currentTest
|
|
7
9
|
let currentHook
|
|
8
10
|
|
|
11
|
+
// Session names that should not contribute steps to the main test trace
|
|
12
|
+
const EXCLUDED_SESSIONS = ['tryTo', 'hopeThat']
|
|
13
|
+
|
|
9
14
|
/**
|
|
10
15
|
* Register steps inside tests
|
|
11
16
|
*/
|
|
12
17
|
module.exports = function () {
|
|
13
|
-
event.dispatcher.on(event.test.before,
|
|
18
|
+
event.dispatcher.on(event.test.before, test => {
|
|
14
19
|
test.startedAt = +new Date()
|
|
15
|
-
test.artifacts = {}
|
|
16
20
|
})
|
|
17
21
|
|
|
18
|
-
event.dispatcher.on(event.test.started,
|
|
22
|
+
event.dispatcher.on(event.test.started, test => {
|
|
19
23
|
currentTest = test
|
|
20
24
|
currentTest.steps = []
|
|
21
25
|
if (!('retryNum' in currentTest)) currentTest.retryNum = 0
|
|
22
26
|
else currentTest.retryNum += 1
|
|
27
|
+
output.scenario.started(test)
|
|
23
28
|
})
|
|
24
29
|
|
|
25
|
-
event.dispatcher.on(event.test.after,
|
|
30
|
+
event.dispatcher.on(event.test.after, test => {
|
|
26
31
|
currentTest = null
|
|
27
32
|
})
|
|
28
33
|
|
|
29
|
-
event.dispatcher.on(event.test.finished,
|
|
34
|
+
event.dispatcher.on(event.test.finished, test => {})
|
|
30
35
|
|
|
31
|
-
event.dispatcher.on(event.hook.started,
|
|
32
|
-
currentHook =
|
|
36
|
+
event.dispatcher.on(event.hook.started, hook => {
|
|
37
|
+
currentHook = hook.ctx.test
|
|
33
38
|
currentHook.steps = []
|
|
34
39
|
|
|
35
|
-
|
|
40
|
+
output.hook.started(hook)
|
|
41
|
+
|
|
42
|
+
if (hook.ctx && hook.ctx.test) debug(`--- STARTED ${hook.ctx.test.title} ---`)
|
|
36
43
|
})
|
|
37
44
|
|
|
38
|
-
event.dispatcher.on(event.hook.passed,
|
|
45
|
+
event.dispatcher.on(event.hook.passed, hook => {
|
|
39
46
|
currentHook = null
|
|
40
|
-
|
|
47
|
+
output.hook.passed(hook)
|
|
48
|
+
if (hook.ctx && hook.ctx.test) debug(`--- ENDED ${hook.ctx.test.title} ---`)
|
|
41
49
|
})
|
|
42
50
|
|
|
43
51
|
event.dispatcher.on(event.test.failed, () => {
|
|
44
52
|
const cutSteps = function (current) {
|
|
45
|
-
const failureIndex = current.steps.findIndex(
|
|
53
|
+
const failureIndex = current.steps.findIndex(el => el.status === 'failed')
|
|
46
54
|
// To be sure that failed test will be failed in report
|
|
47
55
|
current.state = 'failed'
|
|
48
56
|
current.steps.length = failureIndex + 1
|
|
@@ -65,19 +73,25 @@ module.exports = function () {
|
|
|
65
73
|
currentTest.state = 'passed'
|
|
66
74
|
})
|
|
67
75
|
|
|
68
|
-
event.dispatcher.on(event.step.started,
|
|
69
|
-
|
|
70
|
-
step.test = currentTest
|
|
76
|
+
event.dispatcher.on(event.step.started, step => {
|
|
77
|
+
store.currentStep = step
|
|
71
78
|
if (currentHook && Array.isArray(currentHook.steps)) {
|
|
72
79
|
return currentHook.steps.push(step)
|
|
73
80
|
}
|
|
74
81
|
if (!currentTest || !currentTest.steps) return
|
|
82
|
+
|
|
83
|
+
// Check if we're in a session that should be excluded from main test steps
|
|
84
|
+
const currentSessionId = recorder.getCurrentSessionId()
|
|
85
|
+
if (currentSessionId && EXCLUDED_SESSIONS.includes(currentSessionId)) {
|
|
86
|
+
// Skip adding this step to the main test steps
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
|
|
75
90
|
currentTest.steps.push(step)
|
|
76
91
|
})
|
|
77
92
|
|
|
78
|
-
event.dispatcher.on(event.step.finished,
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
debug(`Step '${step}' finished; Duration: ${step.duration || 0}ms`)
|
|
93
|
+
event.dispatcher.on(event.step.finished, step => {
|
|
94
|
+
store.currentStep = null
|
|
95
|
+
store.stepOptions = null
|
|
82
96
|
})
|
|
83
97
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const event = require('../event')
|
|
2
|
+
const store = require('../store')
|
|
3
|
+
|
|
4
|
+
module.exports = function () {
|
|
5
|
+
event.dispatcher.on(event.suite.before, suite => {
|
|
6
|
+
store.currentSuite = suite
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
event.dispatcher.on(event.suite.after, () => {
|
|
10
|
+
store.currentSuite = null
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
event.dispatcher.on(event.test.before, test => {
|
|
14
|
+
store.currentTest = test
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
event.dispatcher.on(event.test.finished, () => {
|
|
18
|
+
store.currentTest = null
|
|
19
|
+
})
|
|
20
|
+
}
|
package/lib/locator.js
CHANGED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
const promiseRetry = require('promise-retry')
|
|
2
|
+
const event = require('../event')
|
|
3
|
+
const recorder = require('../recorder')
|
|
4
|
+
const assertThrown = require('../assert/throws')
|
|
5
|
+
const { ucfirst, isAsyncFunction } = require('../utils')
|
|
6
|
+
const { getInjectedArguments } = require('./inject')
|
|
7
|
+
const { fireHook } = require('./hooks')
|
|
8
|
+
|
|
9
|
+
const injectHook = function (inject, suite) {
|
|
10
|
+
try {
|
|
11
|
+
inject()
|
|
12
|
+
} catch (err) {
|
|
13
|
+
recorder.throw(err)
|
|
14
|
+
}
|
|
15
|
+
recorder.catch(err => {
|
|
16
|
+
suiteTestFailedHookError(suite, err)
|
|
17
|
+
throw err
|
|
18
|
+
})
|
|
19
|
+
return recorder.promise()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function suiteTestFailedHookError(suite, err, hookName) {
|
|
23
|
+
suite.eachTest(test => {
|
|
24
|
+
test.err = err
|
|
25
|
+
if (hookName) hookName = ucfirst(hookName)
|
|
26
|
+
event.emit(event.test.failed, test, err, hookName)
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function makeDoneCallableOnce(done) {
|
|
31
|
+
let called = false
|
|
32
|
+
return function (err) {
|
|
33
|
+
if (called) {
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
called = true
|
|
37
|
+
return done(err)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Wraps test function, injects support objects from container,
|
|
43
|
+
* starts promise chain with recorder, performs before/after hooks
|
|
44
|
+
* through event system.
|
|
45
|
+
*/
|
|
46
|
+
module.exports.test = test => {
|
|
47
|
+
const testFn = test.fn
|
|
48
|
+
if (!testFn) {
|
|
49
|
+
return test
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
test.timeout(0)
|
|
53
|
+
test.async = true
|
|
54
|
+
|
|
55
|
+
test.fn = function (done) {
|
|
56
|
+
const doneFn = makeDoneCallableOnce(done)
|
|
57
|
+
recorder.errHandler(err => {
|
|
58
|
+
recorder.session.start('teardown')
|
|
59
|
+
recorder.cleanAsyncErr()
|
|
60
|
+
if (test.throws) {
|
|
61
|
+
// check that test should actually fail
|
|
62
|
+
try {
|
|
63
|
+
assertThrown(err, test.throws)
|
|
64
|
+
event.emit(event.test.passed, test)
|
|
65
|
+
event.emit(event.test.finished, test)
|
|
66
|
+
recorder.add(doneFn)
|
|
67
|
+
return
|
|
68
|
+
} catch (newErr) {
|
|
69
|
+
err = newErr
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
test.err = err
|
|
73
|
+
event.emit(event.test.failed, test, err)
|
|
74
|
+
event.emit(event.test.finished, test)
|
|
75
|
+
recorder.add(() => doneFn(err))
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
if (isAsyncFunction(testFn)) {
|
|
79
|
+
event.emit(event.test.started, test)
|
|
80
|
+
testFn
|
|
81
|
+
.call(test, getInjectedArguments(testFn, test))
|
|
82
|
+
.then(() => {
|
|
83
|
+
recorder.add('fire test.passed', () => {
|
|
84
|
+
event.emit(event.test.passed, test)
|
|
85
|
+
event.emit(event.test.finished, test)
|
|
86
|
+
})
|
|
87
|
+
recorder.add('finish test', doneFn)
|
|
88
|
+
})
|
|
89
|
+
.catch(err => {
|
|
90
|
+
recorder.throw(err)
|
|
91
|
+
})
|
|
92
|
+
.finally(() => {
|
|
93
|
+
recorder.catch()
|
|
94
|
+
})
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
event.emit(event.test.started, test)
|
|
100
|
+
testFn.call(test, getInjectedArguments(testFn, test))
|
|
101
|
+
} catch (err) {
|
|
102
|
+
recorder.throw(err)
|
|
103
|
+
} finally {
|
|
104
|
+
recorder.add('fire test.passed', () => {
|
|
105
|
+
event.emit(event.test.passed, test)
|
|
106
|
+
event.emit(event.test.finished, test)
|
|
107
|
+
})
|
|
108
|
+
recorder.add('finish test', doneFn)
|
|
109
|
+
recorder.catch()
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return test
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Injects arguments to function from controller
|
|
117
|
+
*/
|
|
118
|
+
module.exports.injected = function (fn, suite, hookName) {
|
|
119
|
+
return function (done) {
|
|
120
|
+
const doneFn = makeDoneCallableOnce(done)
|
|
121
|
+
const errHandler = err => {
|
|
122
|
+
recorder.session.start('teardown')
|
|
123
|
+
recorder.cleanAsyncErr()
|
|
124
|
+
if (['before', 'beforeSuite'].includes(hookName)) {
|
|
125
|
+
suiteTestFailedHookError(suite, err, hookName)
|
|
126
|
+
}
|
|
127
|
+
if (hookName === 'after') {
|
|
128
|
+
suiteTestFailedHookError(suite, err, hookName)
|
|
129
|
+
suite.eachTest(test => {
|
|
130
|
+
event.emit(event.test.after, test)
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
if (hookName === 'afterSuite') {
|
|
134
|
+
suiteTestFailedHookError(suite, err, hookName)
|
|
135
|
+
event.emit(event.suite.after, suite)
|
|
136
|
+
}
|
|
137
|
+
recorder.add(() => doneFn(err))
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
recorder.errHandler(err => {
|
|
141
|
+
errHandler(err)
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
if (!fn) throw new Error('fn is not defined')
|
|
145
|
+
|
|
146
|
+
fireHook(event.hook.started, suite)
|
|
147
|
+
|
|
148
|
+
this.test.body = fn.toString()
|
|
149
|
+
|
|
150
|
+
if (!recorder.isRunning()) {
|
|
151
|
+
recorder.errHandler(err => {
|
|
152
|
+
errHandler(err)
|
|
153
|
+
})
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const opts = suite.opts || {}
|
|
157
|
+
const retries = opts[`retry${ucfirst(hookName)}`] || 0
|
|
158
|
+
|
|
159
|
+
const currentTest = hookName === 'before' || hookName === 'after' ? suite?.ctx?.currentTest : null
|
|
160
|
+
|
|
161
|
+
promiseRetry(
|
|
162
|
+
async (retry, number) => {
|
|
163
|
+
try {
|
|
164
|
+
recorder.startUnlessRunning()
|
|
165
|
+
await fn.call(this, { ...getInjectedArguments(fn), suite, test: currentTest })
|
|
166
|
+
await recorder.promise().catch(err => retry(err))
|
|
167
|
+
} catch (err) {
|
|
168
|
+
retry(err)
|
|
169
|
+
} finally {
|
|
170
|
+
if (number < retries) {
|
|
171
|
+
recorder.stop()
|
|
172
|
+
recorder.start()
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
{ retries },
|
|
177
|
+
)
|
|
178
|
+
.then(() => {
|
|
179
|
+
recorder.add('fire hook.passed', () => fireHook(event.hook.passed, suite))
|
|
180
|
+
recorder.add('fire hook.finished', () => fireHook(event.hook.finished, suite))
|
|
181
|
+
recorder.add(`finish ${hookName} hook`, doneFn)
|
|
182
|
+
recorder.catch()
|
|
183
|
+
})
|
|
184
|
+
.catch(e => {
|
|
185
|
+
recorder.throw(e)
|
|
186
|
+
recorder.catch(e => {
|
|
187
|
+
const err = recorder.getAsyncErr() === null ? e : recorder.getAsyncErr()
|
|
188
|
+
errHandler(err)
|
|
189
|
+
})
|
|
190
|
+
recorder.add('fire hook.failed', () => fireHook(event.hook.failed, suite, e))
|
|
191
|
+
recorder.add('fire hook.finished', () => fireHook(event.hook.finished, suite))
|
|
192
|
+
})
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Starts promise chain, so helpers could enqueue their hooks
|
|
198
|
+
*/
|
|
199
|
+
module.exports.setup = function (suite) {
|
|
200
|
+
const { enhanceMochaTest } = require('./test')
|
|
201
|
+
return injectHook(() => {
|
|
202
|
+
recorder.startUnlessRunning()
|
|
203
|
+
event.emit(event.test.before, enhanceMochaTest(suite?.ctx?.currentTest))
|
|
204
|
+
}, suite)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
module.exports.teardown = function (suite) {
|
|
208
|
+
const { enhanceMochaTest } = require('./test')
|
|
209
|
+
return injectHook(() => {
|
|
210
|
+
recorder.startUnlessRunning()
|
|
211
|
+
event.emit(event.test.after, enhanceMochaTest(suite?.ctx?.currentTest))
|
|
212
|
+
}, suite)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
module.exports.suiteSetup = function (suite) {
|
|
216
|
+
const { enhanceMochaSuite } = require('./suite')
|
|
217
|
+
return injectHook(() => {
|
|
218
|
+
recorder.startUnlessRunning()
|
|
219
|
+
event.emit(event.suite.before, enhanceMochaSuite(suite))
|
|
220
|
+
}, suite)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
module.exports.suiteTeardown = function (suite) {
|
|
224
|
+
const { enhanceMochaSuite } = require('./suite')
|
|
225
|
+
return injectHook(() => {
|
|
226
|
+
recorder.startUnlessRunning()
|
|
227
|
+
event.emit(event.suite.after, enhanceMochaSuite(suite))
|
|
228
|
+
}, suite)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
module.exports.getInjectedArguments = getInjectedArguments
|
|
@@ -27,7 +27,7 @@ const addStep = (step, fn) => {
|
|
|
27
27
|
|
|
28
28
|
const parameterTypeRegistry = new ParameterTypeRegistry()
|
|
29
29
|
|
|
30
|
-
const matchStep =
|
|
30
|
+
const matchStep = step => {
|
|
31
31
|
for (const stepName in steps) {
|
|
32
32
|
if (stepName.indexOf('/') === 0) {
|
|
33
33
|
const regExpArr = stepName.match(/^\/(.*?)\/([gimy]*)$/) || []
|
|
@@ -43,7 +43,7 @@ const matchStep = (step) => {
|
|
|
43
43
|
const res = expression.match(step)
|
|
44
44
|
if (res) {
|
|
45
45
|
const fn = steps[stepName]
|
|
46
|
-
fn.params = res.map(
|
|
46
|
+
fn.params = res.map(arg => arg.getValue())
|
|
47
47
|
return fn
|
|
48
48
|
}
|
|
49
49
|
}
|
|
@@ -58,7 +58,7 @@ const getSteps = () => {
|
|
|
58
58
|
return steps
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
const defineParameterType =
|
|
61
|
+
const defineParameterType = options => {
|
|
62
62
|
const parameterType = buildParameterType(options)
|
|
63
63
|
parameterTypeRegistry.defineParameterType(parameterType)
|
|
64
64
|
}
|