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
package/lib/listener/timeout.js
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
const event = require('../event')
|
|
2
|
-
const output = require('../output')
|
|
3
|
-
const recorder = require('../recorder')
|
|
4
|
-
const Config = require('../config')
|
|
5
|
-
const { timeouts } = require('../store')
|
|
6
|
-
const TIMEOUT_ORDER = require('../step').TIMEOUT_ORDER
|
|
7
|
-
|
|
8
|
-
module.exports = function () {
|
|
9
|
-
let timeout
|
|
10
|
-
let suiteTimeout = []
|
|
11
|
-
let currentTest
|
|
12
|
-
let currentTimeout
|
|
13
|
-
|
|
14
|
-
if (!timeouts) {
|
|
15
|
-
console.log('Timeouts were disabled')
|
|
16
|
-
return
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
event.dispatcher.on(event.suite.before, (suite) => {
|
|
20
|
-
suiteTimeout = []
|
|
21
|
-
let timeoutConfig = Config.get('timeout')
|
|
22
|
-
|
|
23
|
-
if (timeoutConfig) {
|
|
24
|
-
if (!Number.isNaN(+timeoutConfig)) {
|
|
25
|
-
checkForSeconds(timeoutConfig)
|
|
26
|
-
suiteTimeout.push(timeoutConfig)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (!Array.isArray(timeoutConfig)) {
|
|
30
|
-
timeoutConfig = [timeoutConfig]
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
for (const config of timeoutConfig.filter((c) => !!c.Feature)) {
|
|
34
|
-
if (config.grep) {
|
|
35
|
-
if (!suite.title.includes(config.grep)) continue
|
|
36
|
-
}
|
|
37
|
-
suiteTimeout.push(config.Feature)
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (suite.totalTimeout) suiteTimeout.push(suite.totalTimeout)
|
|
42
|
-
output.log(`Timeouts: ${suiteTimeout}`)
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
event.dispatcher.on(event.test.before, (test) => {
|
|
46
|
-
currentTest = test
|
|
47
|
-
let testTimeout = null
|
|
48
|
-
|
|
49
|
-
let timeoutConfig = Config.get('timeout')
|
|
50
|
-
|
|
51
|
-
if (typeof timeoutConfig === 'object' || Array.isArray(timeoutConfig)) {
|
|
52
|
-
if (!Array.isArray(timeoutConfig)) {
|
|
53
|
-
timeoutConfig = [timeoutConfig]
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
for (const config of timeoutConfig.filter((c) => !!c.Scenario)) {
|
|
57
|
-
console.log('Test Timeout', config, test.title.includes(config.grep))
|
|
58
|
-
if (config.grep) {
|
|
59
|
-
if (!test.title.includes(config.grep)) continue
|
|
60
|
-
}
|
|
61
|
-
testTimeout = config.Scenario
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
timeout = test.totalTimeout || testTimeout || suiteTimeout[suiteTimeout.length - 1]
|
|
66
|
-
if (!timeout) return
|
|
67
|
-
currentTimeout = timeout
|
|
68
|
-
output.debug(`Test Timeout: ${timeout}s`)
|
|
69
|
-
timeout *= 1000
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
event.dispatcher.on(event.test.passed, (test) => {
|
|
73
|
-
currentTest = null
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
event.dispatcher.on(event.test.failed, (test) => {
|
|
77
|
-
currentTest = null
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
event.dispatcher.on(event.step.before, (step) => {
|
|
81
|
-
if (typeof timeout !== 'number') return
|
|
82
|
-
|
|
83
|
-
if (timeout < 0) {
|
|
84
|
-
step.setTimeout(0.01, TIMEOUT_ORDER.testOrSuite)
|
|
85
|
-
} else {
|
|
86
|
-
step.setTimeout(timeout, TIMEOUT_ORDER.testOrSuite)
|
|
87
|
-
}
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
event.dispatcher.on(event.step.finished, (step) => {
|
|
91
|
-
if (typeof timeout === 'number' && !Number.isNaN(timeout)) timeout -= step.duration
|
|
92
|
-
|
|
93
|
-
if (typeof timeout === 'number' && timeout <= 0 && recorder.isRunning()) {
|
|
94
|
-
if (currentTest && currentTest.callback) {
|
|
95
|
-
recorder.reset()
|
|
96
|
-
// replace mocha timeout with custom timeout
|
|
97
|
-
currentTest.timeout(0)
|
|
98
|
-
currentTest.callback(new Error(`Timeout ${currentTimeout}s exceeded (with Before hook)`))
|
|
99
|
-
currentTest.timedOut = true
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
})
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function checkForSeconds(timeout) {
|
|
106
|
-
if (timeout >= 1000) {
|
|
107
|
-
console.log(`Warning: Timeout was set to ${timeout}secs.\nGlobal timeout should be specified in seconds.`)
|
|
108
|
-
}
|
|
109
|
-
}
|
package/lib/mochaFactory.js
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
const Mocha = require('mocha');
|
|
2
|
-
const fsPath = require('path');
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const reporter = require('./cli');
|
|
5
|
-
const gherkinParser = require('./interfaces/gherkin');
|
|
6
|
-
const output = require('./output');
|
|
7
|
-
const { genTestId } = require('./utils');
|
|
8
|
-
const ConnectionRefused = require('./helper/errors/ConnectionRefused');
|
|
9
|
-
|
|
10
|
-
const scenarioUi = fsPath.join(__dirname, './ui.js');
|
|
11
|
-
|
|
12
|
-
let mocha;
|
|
13
|
-
|
|
14
|
-
class MochaFactory {
|
|
15
|
-
static create(config, opts) {
|
|
16
|
-
mocha = new Mocha(Object.assign(config, opts));
|
|
17
|
-
output.process(opts.child);
|
|
18
|
-
mocha.ui(scenarioUi);
|
|
19
|
-
|
|
20
|
-
Mocha.Runner.prototype.uncaught = function (err) {
|
|
21
|
-
if (err) {
|
|
22
|
-
if (err.toString().indexOf('ECONNREFUSED') >= 0) {
|
|
23
|
-
err = new ConnectionRefused(err);
|
|
24
|
-
}
|
|
25
|
-
output.error(err);
|
|
26
|
-
output.print(err.stack);
|
|
27
|
-
process.exit(1);
|
|
28
|
-
}
|
|
29
|
-
output.error('Uncaught undefined exception');
|
|
30
|
-
process.exit(1);
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
mocha.loadFiles = (fn) => {
|
|
34
|
-
// load features
|
|
35
|
-
if (mocha.suite.suites.length === 0) {
|
|
36
|
-
mocha.files
|
|
37
|
-
.filter(file => file.match(/\.feature$/))
|
|
38
|
-
.forEach(file => mocha.suite.addSuite(gherkinParser(fs.readFileSync(file, 'utf8'), file)));
|
|
39
|
-
|
|
40
|
-
// remove feature files
|
|
41
|
-
mocha.files = mocha.files.filter(file => !file.match(/\.feature$/));
|
|
42
|
-
|
|
43
|
-
Mocha.prototype.loadFiles.call(mocha, fn);
|
|
44
|
-
|
|
45
|
-
// add ids for each test and check uniqueness
|
|
46
|
-
const dupes = [];
|
|
47
|
-
let missingFeatureInFile = [];
|
|
48
|
-
const seenTests = [];
|
|
49
|
-
mocha.suite.eachTest(test => {
|
|
50
|
-
test.uid = genTestId(test);
|
|
51
|
-
|
|
52
|
-
const name = test.fullTitle();
|
|
53
|
-
if (seenTests.includes(test.uid)) {
|
|
54
|
-
dupes.push(name);
|
|
55
|
-
}
|
|
56
|
-
seenTests.push(test.uid);
|
|
57
|
-
|
|
58
|
-
if (name.slice(0, name.indexOf(':')) === '') {
|
|
59
|
-
missingFeatureInFile.push(test.file);
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
if (dupes.length) {
|
|
63
|
-
// ideally this should be no-op and throw (breaking change)...
|
|
64
|
-
output.error(`Duplicate test names detected - Feature + Scenario name should be unique:\n${dupes.join('\n')}`);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (missingFeatureInFile.length) {
|
|
68
|
-
missingFeatureInFile = [...new Set(missingFeatureInFile)];
|
|
69
|
-
output.error(`Missing Feature section in:\n${missingFeatureInFile.join('\n')}`);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
const presetReporter = opts.reporter || config.reporter;
|
|
75
|
-
// use standard reporter
|
|
76
|
-
if (!presetReporter) {
|
|
77
|
-
mocha.reporter(reporter, opts);
|
|
78
|
-
return mocha;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// load custom reporter with options
|
|
82
|
-
const reporterOptions = Object.assign(config.reporterOptions || {});
|
|
83
|
-
|
|
84
|
-
if (opts.reporterOptions !== undefined) {
|
|
85
|
-
opts.reporterOptions.split(',').forEach((opt) => {
|
|
86
|
-
const L = opt.split('=');
|
|
87
|
-
if (L.length > 2 || L.length === 0) {
|
|
88
|
-
throw new Error(`invalid reporter option '${opt}'`);
|
|
89
|
-
} else if (L.length === 2) {
|
|
90
|
-
reporterOptions[L[0]] = L[1];
|
|
91
|
-
} else {
|
|
92
|
-
reporterOptions[L[0]] = true;
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const attributes = Object.getOwnPropertyDescriptor(reporterOptions, 'codeceptjs-cli-reporter');
|
|
98
|
-
if (reporterOptions['codeceptjs-cli-reporter'] && attributes) {
|
|
99
|
-
Object.defineProperty(
|
|
100
|
-
reporterOptions,
|
|
101
|
-
'codeceptjs/lib/cli',
|
|
102
|
-
attributes,
|
|
103
|
-
);
|
|
104
|
-
delete reporterOptions['codeceptjs-cli-reporter'];
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// custom reporters
|
|
108
|
-
mocha.reporter(presetReporter, reporterOptions);
|
|
109
|
-
return mocha;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
module.exports = MochaFactory;
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
const Container = require('../container')
|
|
2
|
-
const recorder = require('../recorder')
|
|
3
|
-
const event = require('../event')
|
|
4
|
-
const supportedHelpers = require('./standardActingHelpers')
|
|
5
|
-
const { scanForErrorMessages } = require('../html')
|
|
6
|
-
const { output } = require('..')
|
|
7
|
-
|
|
8
|
-
const defaultConfig = {
|
|
9
|
-
errorClasses: ['error', 'warning', 'alert', 'danger'],
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Prints errors found in HTML code after each failed test.
|
|
14
|
-
*
|
|
15
|
-
* It scans HTML and searches for elements with error classes.
|
|
16
|
-
* If an element found prints a text from it to console and adds as artifact to the test.
|
|
17
|
-
*
|
|
18
|
-
* Enable this plugin in config:
|
|
19
|
-
*
|
|
20
|
-
* ```js
|
|
21
|
-
* plugins: {
|
|
22
|
-
* debugErrors: {
|
|
23
|
-
* enabled: true,
|
|
24
|
-
* }
|
|
25
|
-
* ```
|
|
26
|
-
*
|
|
27
|
-
* Additional config options:
|
|
28
|
-
*
|
|
29
|
-
* * `errorClasses` - list of classes to search for errors (default: `['error', 'warning', 'alert', 'danger']`)
|
|
30
|
-
*
|
|
31
|
-
*/
|
|
32
|
-
module.exports = function (config = {}) {
|
|
33
|
-
const helpers = Container.helpers()
|
|
34
|
-
let helper
|
|
35
|
-
|
|
36
|
-
config = Object.assign(defaultConfig, config)
|
|
37
|
-
|
|
38
|
-
for (const helperName of supportedHelpers) {
|
|
39
|
-
if (Object.keys(helpers).indexOf(helperName) > -1) {
|
|
40
|
-
helper = helpers[helperName]
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (!helper) return // no helpers for screenshot
|
|
45
|
-
|
|
46
|
-
event.dispatcher.on(event.test.failed, (test) => {
|
|
47
|
-
recorder.add('HTML snapshot failed test', async () => {
|
|
48
|
-
try {
|
|
49
|
-
const currentOutputLevel = output.level()
|
|
50
|
-
output.level(0)
|
|
51
|
-
const html = await helper.grabHTMLFrom('body')
|
|
52
|
-
output.level(currentOutputLevel)
|
|
53
|
-
|
|
54
|
-
if (!html) return
|
|
55
|
-
|
|
56
|
-
const errors = scanForErrorMessages(html, config.errorClasses)
|
|
57
|
-
if (errors.length) {
|
|
58
|
-
output.debug('Detected errors in HTML code')
|
|
59
|
-
errors.forEach((error) => output.debug(error))
|
|
60
|
-
test.artifacts.errors = errors
|
|
61
|
-
}
|
|
62
|
-
} catch (err) {
|
|
63
|
-
// not really needed
|
|
64
|
-
}
|
|
65
|
-
})
|
|
66
|
-
})
|
|
67
|
-
}
|
package/lib/scenario.js
DELETED
|
@@ -1,224 +0,0 @@
|
|
|
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 parser = require('./parser');
|
|
7
|
-
|
|
8
|
-
const injectHook = function (inject, suite) {
|
|
9
|
-
try {
|
|
10
|
-
inject();
|
|
11
|
-
} catch (err) {
|
|
12
|
-
recorder.throw(err);
|
|
13
|
-
}
|
|
14
|
-
recorder.catch((err) => {
|
|
15
|
-
event.emit(event.test.failed, suite, err);
|
|
16
|
-
throw err;
|
|
17
|
-
});
|
|
18
|
-
return recorder.promise();
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
function makeDoneCallableOnce(done) {
|
|
22
|
-
let called = false;
|
|
23
|
-
return function (err) {
|
|
24
|
-
if (called) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
called = true;
|
|
28
|
-
return done(err);
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Wraps test function, injects support objects from container,
|
|
33
|
-
* starts promise chain with recorder, performs before/after hooks
|
|
34
|
-
* through event system.
|
|
35
|
-
*/
|
|
36
|
-
module.exports.test = (test) => {
|
|
37
|
-
const testFn = test.fn;
|
|
38
|
-
if (!testFn) {
|
|
39
|
-
return test;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
test.steps = [];
|
|
43
|
-
test.timeout(0);
|
|
44
|
-
test.async = true;
|
|
45
|
-
|
|
46
|
-
test.fn = function (done) {
|
|
47
|
-
const doneFn = makeDoneCallableOnce(done);
|
|
48
|
-
recorder.errHandler((err) => {
|
|
49
|
-
recorder.session.start('teardown');
|
|
50
|
-
recorder.cleanAsyncErr();
|
|
51
|
-
if (test.throws) {
|
|
52
|
-
// check that test should actually fail
|
|
53
|
-
try {
|
|
54
|
-
assertThrown(err, test.throws);
|
|
55
|
-
event.emit(event.test.passed, test);
|
|
56
|
-
event.emit(event.test.finished, test);
|
|
57
|
-
recorder.add(doneFn);
|
|
58
|
-
return;
|
|
59
|
-
} catch (newErr) {
|
|
60
|
-
err = newErr;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
event.emit(event.test.failed, test, err);
|
|
64
|
-
event.emit(event.test.finished, test);
|
|
65
|
-
recorder.add(() => doneFn(err));
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
if (isAsyncFunction(testFn)) {
|
|
69
|
-
event.emit(event.test.started, test);
|
|
70
|
-
testFn
|
|
71
|
-
.call(test, getInjectedArguments(testFn, test))
|
|
72
|
-
.then(() => {
|
|
73
|
-
recorder.add('fire test.passed', () => {
|
|
74
|
-
event.emit(event.test.passed, test);
|
|
75
|
-
event.emit(event.test.finished, test);
|
|
76
|
-
});
|
|
77
|
-
recorder.add('finish test', doneFn);
|
|
78
|
-
})
|
|
79
|
-
.catch((err) => {
|
|
80
|
-
recorder.throw(err);
|
|
81
|
-
})
|
|
82
|
-
.finally(() => {
|
|
83
|
-
recorder.catch();
|
|
84
|
-
});
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
try {
|
|
89
|
-
event.emit(event.test.started, test);
|
|
90
|
-
testFn.call(test, getInjectedArguments(testFn, test));
|
|
91
|
-
} catch (err) {
|
|
92
|
-
recorder.throw(err);
|
|
93
|
-
} finally {
|
|
94
|
-
recorder.add('fire test.passed', () => {
|
|
95
|
-
event.emit(event.test.passed, test);
|
|
96
|
-
event.emit(event.test.finished, test);
|
|
97
|
-
});
|
|
98
|
-
recorder.add('finish test', doneFn);
|
|
99
|
-
recorder.catch();
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
return test;
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Injects arguments to function from controller
|
|
107
|
-
*/
|
|
108
|
-
module.exports.injected = function (fn, suite, hookName) {
|
|
109
|
-
return function (done) {
|
|
110
|
-
const doneFn = makeDoneCallableOnce(done);
|
|
111
|
-
const errHandler = (err) => {
|
|
112
|
-
recorder.session.start('teardown');
|
|
113
|
-
recorder.cleanAsyncErr();
|
|
114
|
-
event.emit(event.test.failed, suite, err);
|
|
115
|
-
if (hookName === 'after') event.emit(event.test.after, suite);
|
|
116
|
-
if (hookName === 'afterSuite') event.emit(event.suite.after, suite);
|
|
117
|
-
recorder.add(() => doneFn(err));
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
recorder.errHandler((err) => {
|
|
121
|
-
errHandler(err);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
if (!fn) throw new Error('fn is not defined');
|
|
125
|
-
|
|
126
|
-
event.emit(event.hook.started, suite);
|
|
127
|
-
|
|
128
|
-
this.test.body = fn.toString();
|
|
129
|
-
|
|
130
|
-
if (!recorder.isRunning()) {
|
|
131
|
-
recorder.errHandler((err) => {
|
|
132
|
-
errHandler(err);
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const opts = suite.opts || {};
|
|
137
|
-
const retries = opts[`retry${ucfirst(hookName)}`] || 0;
|
|
138
|
-
|
|
139
|
-
promiseRetry(
|
|
140
|
-
async (retry, number) => {
|
|
141
|
-
try {
|
|
142
|
-
recorder.startUnlessRunning();
|
|
143
|
-
await fn.call(this, getInjectedArguments(fn));
|
|
144
|
-
await recorder.promise().catch((err) => retry(err));
|
|
145
|
-
} catch (err) {
|
|
146
|
-
retry(err);
|
|
147
|
-
} finally {
|
|
148
|
-
if (number < retries) {
|
|
149
|
-
recorder.stop();
|
|
150
|
-
recorder.start();
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
},
|
|
154
|
-
{ retries },
|
|
155
|
-
)
|
|
156
|
-
.then(() => {
|
|
157
|
-
recorder.add('fire hook.passed', () => event.emit(event.hook.passed, suite));
|
|
158
|
-
recorder.add(`finish ${hookName} hook`, doneFn);
|
|
159
|
-
recorder.catch();
|
|
160
|
-
})
|
|
161
|
-
.catch((e) => {
|
|
162
|
-
recorder.throw(e);
|
|
163
|
-
recorder.catch((e) => {
|
|
164
|
-
const err = recorder.getAsyncErr() === null ? e : recorder.getAsyncErr();
|
|
165
|
-
errHandler(err);
|
|
166
|
-
});
|
|
167
|
-
recorder.add('fire hook.failed', () => event.emit(event.hook.failed, suite, e));
|
|
168
|
-
});
|
|
169
|
-
};
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Starts promise chain, so helpers could enqueue their hooks
|
|
174
|
-
*/
|
|
175
|
-
module.exports.setup = function (suite) {
|
|
176
|
-
return injectHook(() => {
|
|
177
|
-
recorder.startUnlessRunning();
|
|
178
|
-
event.emit(event.test.before, suite && suite.ctx && suite.ctx.currentTest);
|
|
179
|
-
}, suite);
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
module.exports.teardown = function (suite) {
|
|
183
|
-
return injectHook(() => {
|
|
184
|
-
recorder.startUnlessRunning();
|
|
185
|
-
event.emit(event.test.after, suite && suite.ctx && suite.ctx.currentTest);
|
|
186
|
-
}, suite);
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
module.exports.suiteSetup = function (suite) {
|
|
190
|
-
return injectHook(() => {
|
|
191
|
-
recorder.startUnlessRunning();
|
|
192
|
-
event.emit(event.suite.before, suite);
|
|
193
|
-
}, suite);
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
module.exports.suiteTeardown = function (suite) {
|
|
197
|
-
return injectHook(() => {
|
|
198
|
-
recorder.startUnlessRunning();
|
|
199
|
-
event.emit(event.suite.after, suite);
|
|
200
|
-
}, suite);
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
const getInjectedArguments = (fn, test) => {
|
|
204
|
-
const container = require('./container');
|
|
205
|
-
const testArgs = {};
|
|
206
|
-
const params = parser.getParams(fn) || [];
|
|
207
|
-
const objects = container.support();
|
|
208
|
-
for (const key of params) {
|
|
209
|
-
testArgs[key] = {};
|
|
210
|
-
if (test && test.inject && test.inject[key]) {
|
|
211
|
-
// @FIX: need fix got inject
|
|
212
|
-
testArgs[key] = test.inject[key];
|
|
213
|
-
continue;
|
|
214
|
-
}
|
|
215
|
-
if (!objects[key]) {
|
|
216
|
-
throw new Error(`Object of type ${key} is not defined in container`);
|
|
217
|
-
}
|
|
218
|
-
testArgs[key] = container.support(key);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return testArgs;
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
module.exports.getInjectedArguments = getInjectedArguments;
|