codeceptjs 3.7.0-beta.1 → 3.7.0-beta.11
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 +9 -10
- package/bin/codecept.js +7 -0
- package/lib/actor.js +46 -92
- package/lib/ai.js +130 -121
- package/lib/codecept.js +2 -2
- package/lib/command/check.js +186 -0
- package/lib/command/definitions.js +3 -1
- package/lib/command/interactive.js +1 -1
- package/lib/command/run-workers.js +2 -54
- package/lib/command/workers/runTests.js +64 -225
- package/lib/container.js +32 -0
- package/lib/effects.js +218 -0
- package/lib/els.js +87 -106
- package/lib/event.js +18 -17
- package/lib/heal.js +10 -0
- package/lib/helper/AI.js +2 -1
- package/lib/helper/Appium.js +31 -22
- package/lib/helper/Playwright.js +22 -1
- package/lib/helper/Puppeteer.js +5 -0
- package/lib/helper/WebDriver.js +29 -8
- package/lib/listener/emptyRun.js +2 -5
- package/lib/listener/exit.js +5 -8
- package/lib/listener/globalTimeout.js +66 -10
- package/lib/listener/result.js +12 -0
- package/lib/listener/steps.js +3 -6
- package/lib/listener/store.js +9 -1
- package/lib/mocha/asyncWrapper.js +15 -3
- package/lib/mocha/cli.js +79 -28
- package/lib/mocha/featureConfig.js +13 -0
- package/lib/mocha/hooks.js +32 -3
- package/lib/mocha/inject.js +5 -0
- package/lib/mocha/scenarioConfig.js +11 -0
- package/lib/mocha/suite.js +27 -1
- package/lib/mocha/test.js +102 -3
- package/lib/mocha/types.d.ts +11 -0
- package/lib/output.js +75 -73
- package/lib/pause.js +3 -10
- package/lib/plugin/analyze.js +349 -0
- package/lib/plugin/autoDelay.js +2 -2
- package/lib/plugin/commentStep.js +5 -0
- package/lib/plugin/customReporter.js +52 -0
- package/lib/plugin/heal.js +30 -0
- package/lib/plugin/pageInfo.js +140 -0
- package/lib/plugin/retryTo.js +18 -118
- package/lib/plugin/screenshotOnFail.js +12 -17
- package/lib/plugin/standardActingHelpers.js +4 -1
- package/lib/plugin/stepByStepReport.js +6 -5
- package/lib/plugin/stepTimeout.js +1 -1
- package/lib/plugin/tryTo.js +17 -107
- package/lib/recorder.js +5 -5
- package/lib/rerun.js +43 -42
- package/lib/result.js +161 -0
- package/lib/step/base.js +228 -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 +20 -347
- package/lib/steps.js +50 -0
- package/lib/store.js +4 -0
- package/lib/timeout.js +66 -0
- package/lib/utils.js +93 -0
- package/lib/within.js +2 -2
- package/lib/workers.js +29 -49
- package/package.json +23 -20
- package/typings/index.d.ts +5 -4
- package/typings/promiseBasedTypes.d.ts +507 -49
- package/typings/types.d.ts +623 -73
- package/lib/listener/artifacts.js +0 -19
- package/lib/plugin/debugErrors.js +0 -67
package/lib/codecept.js
CHANGED
|
@@ -105,8 +105,8 @@ class Codecept {
|
|
|
105
105
|
// default hooks
|
|
106
106
|
runHook(require('./listener/store'))
|
|
107
107
|
runHook(require('./listener/steps'))
|
|
108
|
-
runHook(require('./listener/artifacts'))
|
|
109
108
|
runHook(require('./listener/config'))
|
|
109
|
+
runHook(require('./listener/result'))
|
|
110
110
|
runHook(require('./listener/helpers'))
|
|
111
111
|
runHook(require('./listener/globalTimeout'))
|
|
112
112
|
runHook(require('./listener/globalRetry'))
|
|
@@ -199,7 +199,7 @@ class Codecept {
|
|
|
199
199
|
mocha.files = mocha.files.filter(t => fsPath.basename(t, '.js') === test || t === test)
|
|
200
200
|
}
|
|
201
201
|
const done = () => {
|
|
202
|
-
event.emit(event.all.result,
|
|
202
|
+
event.emit(event.all.result, container.result())
|
|
203
203
|
event.emit(event.all.after, this)
|
|
204
204
|
resolve()
|
|
205
205
|
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
const { getConfig, getTestRoot } = require('./utils')
|
|
2
|
+
const Codecept = require('../codecept')
|
|
3
|
+
const output = require('../output')
|
|
4
|
+
const store = require('../store')
|
|
5
|
+
const container = require('../container')
|
|
6
|
+
const figures = require('figures')
|
|
7
|
+
const chalk = require('chalk')
|
|
8
|
+
const { createTest } = require('../mocha/test')
|
|
9
|
+
const { getMachineInfo } = require('./info')
|
|
10
|
+
const definitions = require('./definitions')
|
|
11
|
+
|
|
12
|
+
module.exports = async function (options) {
|
|
13
|
+
const configFile = options.config
|
|
14
|
+
|
|
15
|
+
setTimeout(() => {
|
|
16
|
+
output.error("Something went wrong. Checks didn't pass and timed out. Please check your config and helpers.")
|
|
17
|
+
process.exit(1)
|
|
18
|
+
}, options.timeout || 50000)
|
|
19
|
+
|
|
20
|
+
const checks = {
|
|
21
|
+
config: false,
|
|
22
|
+
container: false,
|
|
23
|
+
pageObjects: false,
|
|
24
|
+
plugins: false,
|
|
25
|
+
ai: true, // we don't need to check AI
|
|
26
|
+
helpers: false,
|
|
27
|
+
setup: false,
|
|
28
|
+
tests: false,
|
|
29
|
+
def: false,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const testRoot = getTestRoot(configFile)
|
|
33
|
+
let config = getConfig(configFile)
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
config = getConfig(configFile)
|
|
37
|
+
checks['config'] = true
|
|
38
|
+
} catch (err) {
|
|
39
|
+
checks['config'] = err
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
printCheck('config', checks['config'], config.name)
|
|
43
|
+
|
|
44
|
+
let codecept
|
|
45
|
+
try {
|
|
46
|
+
codecept = new Codecept(config, options)
|
|
47
|
+
codecept.init(testRoot)
|
|
48
|
+
await container.started()
|
|
49
|
+
checks.container = true
|
|
50
|
+
} catch (err) {
|
|
51
|
+
checks.container = err
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const standardActingHelpers = container.STANDARD_ACTING_HELPERS
|
|
55
|
+
|
|
56
|
+
printCheck('container', checks['container'])
|
|
57
|
+
|
|
58
|
+
if (codecept) {
|
|
59
|
+
try {
|
|
60
|
+
if (options.bootstrap) await codecept.bootstrap()
|
|
61
|
+
checks.bootstrap = true
|
|
62
|
+
} catch (err) {
|
|
63
|
+
checks.bootstrap = err
|
|
64
|
+
}
|
|
65
|
+
printCheck('bootstrap', checks['bootstrap'], options.bootstrap ? 'Bootstrap was executed' : 'No bootstrap command')
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let numTests = 0
|
|
69
|
+
if (codecept) {
|
|
70
|
+
try {
|
|
71
|
+
codecept.loadTests()
|
|
72
|
+
const mocha = container.mocha()
|
|
73
|
+
mocha.files = codecept.testFiles
|
|
74
|
+
mocha.loadFiles()
|
|
75
|
+
mocha.suite.suites.forEach(suite => {
|
|
76
|
+
numTests += suite.tests.length
|
|
77
|
+
})
|
|
78
|
+
if (numTests > 0) {
|
|
79
|
+
checks.tests = true
|
|
80
|
+
} else {
|
|
81
|
+
throw new Error('No tests found')
|
|
82
|
+
}
|
|
83
|
+
} catch (err) {
|
|
84
|
+
checks.tests = err
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (config?.ai?.request) {
|
|
89
|
+
checks.ai = true
|
|
90
|
+
printCheck('ai', checks['ai'], 'AI configuration is enabled, request function is set')
|
|
91
|
+
} else {
|
|
92
|
+
printCheck('ai', checks['ai'], 'AI is disabled')
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
printCheck('tests', checks['tests'], `Total: ${numTests} tests`)
|
|
96
|
+
|
|
97
|
+
store.dryRun = true
|
|
98
|
+
|
|
99
|
+
const helpers = container.helpers()
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
if (!Object.keys(helpers).length) throw new Error('No helpers found')
|
|
103
|
+
// load helpers
|
|
104
|
+
for (const helper of Object.values(helpers)) {
|
|
105
|
+
if (helper._init) helper._init()
|
|
106
|
+
}
|
|
107
|
+
checks.helpers = true
|
|
108
|
+
} catch (err) {
|
|
109
|
+
checks.helpers = err
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
printCheck('helpers', checks['helpers'], `${Object.keys(helpers).join(', ')}`)
|
|
113
|
+
|
|
114
|
+
const pageObjects = container.support()
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
if (Object.keys(pageObjects).length) {
|
|
118
|
+
for (const pageObject of Object.values(pageObjects)) {
|
|
119
|
+
pageObject.name
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
checks.pageObjects = true
|
|
123
|
+
} catch (err) {
|
|
124
|
+
checks.pageObjects = err
|
|
125
|
+
}
|
|
126
|
+
printCheck('page objects', checks['pageObjects'], `Total: ${Object.keys(pageObjects).length} support objects`)
|
|
127
|
+
|
|
128
|
+
checks.plugins = true // how to check plugins?
|
|
129
|
+
printCheck('plugins', checks['plugins'], Object.keys(container.plugins()).join(', '))
|
|
130
|
+
|
|
131
|
+
if (Object.keys(helpers).length) {
|
|
132
|
+
const suite = container.mocha().suite
|
|
133
|
+
const test = createTest('test', () => {})
|
|
134
|
+
try {
|
|
135
|
+
for (const helper of Object.values(helpers)) {
|
|
136
|
+
if (helper._beforeSuite) await helper._beforeSuite(suite)
|
|
137
|
+
if (helper._before) await helper._before(test)
|
|
138
|
+
if (helper._passed) await helper._passed(test)
|
|
139
|
+
if (helper._after) await helper._after(test)
|
|
140
|
+
if (helper._finishTest) await helper._finishTest(suite)
|
|
141
|
+
if (helper._afterSuite) await helper._afterSuite(suite)
|
|
142
|
+
}
|
|
143
|
+
checks.setup = true
|
|
144
|
+
} catch (err) {
|
|
145
|
+
checks.setup = err
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
printCheck('Helpers Before/After', checks['setup'], standardActingHelpers.some(h => Object.keys(helpers).includes(h)) ? 'Initializing and closing browser' : '')
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
definitions(configFile, { dryRun: true })
|
|
153
|
+
checks.def = true
|
|
154
|
+
} catch (err) {
|
|
155
|
+
checks.def = err
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
printCheck('TypeScript Definitions', checks['def'])
|
|
159
|
+
|
|
160
|
+
output.print('')
|
|
161
|
+
|
|
162
|
+
if (!Object.values(checks).every(check => check === true)) {
|
|
163
|
+
output.error("Something went wrong. Checks didn't pass.")
|
|
164
|
+
output.print()
|
|
165
|
+
await getMachineInfo()
|
|
166
|
+
process.exit(1)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
output.print(output.styles.success('All checks passed'.toUpperCase()), 'Ready to run your tests 🚀')
|
|
170
|
+
process.exit(0)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function printCheck(name, value, comment = '') {
|
|
174
|
+
let status = ''
|
|
175
|
+
if (value == true) {
|
|
176
|
+
status += chalk.bold.green(figures.tick)
|
|
177
|
+
} else {
|
|
178
|
+
status += chalk.bold.red(figures.cross)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (value instanceof Error) {
|
|
182
|
+
comment = `${comment} ${chalk.red(value.message)}`.trim()
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
output.print(status, name.toUpperCase(), chalk.dim(comment))
|
|
186
|
+
}
|
|
@@ -5,7 +5,7 @@ const { getConfig, getTestRoot } = require('./utils')
|
|
|
5
5
|
const Codecept = require('../codecept')
|
|
6
6
|
const container = require('../container')
|
|
7
7
|
const output = require('../output')
|
|
8
|
-
const actingHelpers = [...
|
|
8
|
+
const actingHelpers = [...container.STANDARD_ACTING_HELPERS, 'REST']
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Prepare data and generate content of definitions file
|
|
@@ -185,6 +185,8 @@ module.exports = function (genPath, options) {
|
|
|
185
185
|
definitionsFileContent += `\n${translationAliases.join('\n')}`
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
if (options.dryRun) return
|
|
189
|
+
|
|
188
190
|
fs.writeFileSync(path.join(targetFolderPath, 'steps.d.ts'), definitionsFileContent)
|
|
189
191
|
output.print('TypeScript Definitions provide autocompletion in Visual Studio Code and other IDEs')
|
|
190
192
|
output.print('Definitions were generated in steps.d.ts')
|
|
@@ -4,7 +4,7 @@ const Codecept = require('../codecept')
|
|
|
4
4
|
const Container = require('../container')
|
|
5
5
|
const event = require('../event')
|
|
6
6
|
const output = require('../output')
|
|
7
|
-
const webHelpers =
|
|
7
|
+
const webHelpers = Container.STANDARD_ACTING_HELPERS
|
|
8
8
|
|
|
9
9
|
module.exports = async function (path, options) {
|
|
10
10
|
// Backward compatibility for --profile
|
|
@@ -8,12 +8,6 @@ const Workers = require('../workers')
|
|
|
8
8
|
module.exports = async function (workerCount, selectedRuns, options) {
|
|
9
9
|
process.env.profile = options.profile
|
|
10
10
|
|
|
11
|
-
const suiteArr = []
|
|
12
|
-
const passedTestArr = []
|
|
13
|
-
const failedTestArr = []
|
|
14
|
-
const skippedTestArr = []
|
|
15
|
-
const stepArr = []
|
|
16
|
-
|
|
17
11
|
const { config: testConfig, override = '' } = options
|
|
18
12
|
const overrideConfigs = tryOrDefault(() => JSON.parse(override), {})
|
|
19
13
|
const by = options.suites ? 'suite' : 'test'
|
|
@@ -30,69 +24,24 @@ module.exports = async function (workerCount, selectedRuns, options) {
|
|
|
30
24
|
output.print(`CodeceptJS v${require('../codecept').version()} ${output.standWithUkraine()}`)
|
|
31
25
|
output.print(`Running tests in ${output.styles.bold(numberOfWorkers)} workers...`)
|
|
32
26
|
output.print()
|
|
27
|
+
store.hasWorkers = true
|
|
33
28
|
|
|
34
29
|
const workers = new Workers(numberOfWorkers, config)
|
|
35
30
|
workers.overrideConfig(overrideConfigs)
|
|
36
31
|
|
|
37
|
-
workers.on(event.suite.before, suite => {
|
|
38
|
-
suiteArr.push(suite)
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
workers.on(event.step.passed, step => {
|
|
42
|
-
stepArr.push(step)
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
workers.on(event.step.failed, step => {
|
|
46
|
-
stepArr.push(step)
|
|
47
|
-
})
|
|
48
|
-
|
|
49
32
|
workers.on(event.test.failed, test => {
|
|
50
|
-
failedTestArr.push(test)
|
|
51
33
|
output.test.failed(test)
|
|
52
34
|
})
|
|
53
35
|
|
|
54
36
|
workers.on(event.test.passed, test => {
|
|
55
|
-
passedTestArr.push(test)
|
|
56
37
|
output.test.passed(test)
|
|
57
38
|
})
|
|
58
39
|
|
|
59
40
|
workers.on(event.test.skipped, test => {
|
|
60
|
-
skippedTestArr.push(test)
|
|
61
41
|
output.test.skipped(test)
|
|
62
42
|
})
|
|
63
43
|
|
|
64
|
-
workers.on(event.all.result,
|
|
65
|
-
// expose test stats after all workers finished their execution
|
|
66
|
-
function addStepsToTest(test, stepArr) {
|
|
67
|
-
stepArr.test.steps.forEach(step => {
|
|
68
|
-
if (test.steps.length === 0) {
|
|
69
|
-
test.steps.push(step)
|
|
70
|
-
}
|
|
71
|
-
})
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
stepArr.forEach(step => {
|
|
75
|
-
passedTestArr.forEach(test => {
|
|
76
|
-
if (step.test.title === test.title) {
|
|
77
|
-
addStepsToTest(test, step)
|
|
78
|
-
}
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
failedTestArr.forEach(test => {
|
|
82
|
-
if (step.test.title === test.title) {
|
|
83
|
-
addStepsToTest(test, step)
|
|
84
|
-
}
|
|
85
|
-
})
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
event.dispatcher.emit(event.workers.result, {
|
|
89
|
-
suites: suiteArr,
|
|
90
|
-
tests: {
|
|
91
|
-
passed: passedTestArr,
|
|
92
|
-
failed: failedTestArr,
|
|
93
|
-
skipped: skippedTestArr,
|
|
94
|
-
},
|
|
95
|
-
})
|
|
44
|
+
workers.on(event.all.result, result => {
|
|
96
45
|
workers.printResults()
|
|
97
46
|
})
|
|
98
47
|
|
|
@@ -100,7 +49,6 @@ module.exports = async function (workerCount, selectedRuns, options) {
|
|
|
100
49
|
if (options.verbose || options.debug) store.debugMode = true
|
|
101
50
|
|
|
102
51
|
if (options.verbose) {
|
|
103
|
-
global.debugMode = true
|
|
104
52
|
const { getMachineInfo } = require('./info')
|
|
105
53
|
await getMachineInfo()
|
|
106
54
|
}
|
|
@@ -1,288 +1,127 @@
|
|
|
1
|
-
const tty = require('tty')
|
|
1
|
+
const tty = require('tty')
|
|
2
2
|
|
|
3
3
|
if (!tty.getWindowSize) {
|
|
4
4
|
// this is really old method, long removed from Node, but Mocha
|
|
5
5
|
// reporters fall back on it if they cannot use `process.stdout.getWindowSize`
|
|
6
6
|
// we need to polyfill it.
|
|
7
|
-
tty.getWindowSize = () => [40, 80]
|
|
7
|
+
tty.getWindowSize = () => [40, 80]
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
const { parentPort, workerData } = require('worker_threads')
|
|
11
|
-
const event = require('../../event')
|
|
12
|
-
const container = require('../../container')
|
|
13
|
-
const { getConfig } = require('../utils')
|
|
14
|
-
const { tryOrDefault, deepMerge } = require('../../utils')
|
|
10
|
+
const { parentPort, workerData } = require('worker_threads')
|
|
11
|
+
const event = require('../../event')
|
|
12
|
+
const container = require('../../container')
|
|
13
|
+
const { getConfig } = require('../utils')
|
|
14
|
+
const { tryOrDefault, deepMerge } = require('../../utils')
|
|
15
15
|
|
|
16
|
-
let stdout = ''
|
|
16
|
+
let stdout = ''
|
|
17
17
|
|
|
18
|
-
const stderr = ''
|
|
18
|
+
const stderr = ''
|
|
19
19
|
|
|
20
20
|
// Requiring of Codecept need to be after tty.getWindowSize is available.
|
|
21
|
-
const Codecept = require(process.env.CODECEPT_CLASS_PATH || '../../codecept')
|
|
21
|
+
const Codecept = require(process.env.CODECEPT_CLASS_PATH || '../../codecept')
|
|
22
22
|
|
|
23
|
-
const { options, tests, testRoot, workerIndex } = workerData
|
|
23
|
+
const { options, tests, testRoot, workerIndex } = workerData
|
|
24
24
|
|
|
25
25
|
// hide worker output
|
|
26
26
|
if (!options.debug && !options.verbose)
|
|
27
27
|
process.stdout.write = string => {
|
|
28
|
-
stdout += string
|
|
29
|
-
return true
|
|
30
|
-
}
|
|
28
|
+
stdout += string
|
|
29
|
+
return true
|
|
30
|
+
}
|
|
31
31
|
|
|
32
|
-
const overrideConfigs = tryOrDefault(() => JSON.parse(options.override), {})
|
|
32
|
+
const overrideConfigs = tryOrDefault(() => JSON.parse(options.override), {})
|
|
33
33
|
|
|
34
34
|
// important deep merge so dynamic things e.g. functions on config are not overridden
|
|
35
|
-
const config = deepMerge(getConfig(options.config || testRoot), overrideConfigs)
|
|
35
|
+
const config = deepMerge(getConfig(options.config || testRoot), overrideConfigs)
|
|
36
36
|
|
|
37
37
|
// Load test and run
|
|
38
|
-
const codecept = new Codecept(config, options)
|
|
39
|
-
codecept.init(testRoot)
|
|
40
|
-
codecept.loadTests()
|
|
41
|
-
const mocha = container.mocha()
|
|
42
|
-
filterTests()
|
|
38
|
+
const codecept = new Codecept(config, options)
|
|
39
|
+
codecept.init(testRoot)
|
|
40
|
+
codecept.loadTests()
|
|
41
|
+
const mocha = container.mocha()
|
|
42
|
+
filterTests()
|
|
43
43
|
|
|
44
44
|
// run tests
|
|
45
|
-
(async function () {
|
|
45
|
+
;(async function () {
|
|
46
46
|
if (mocha.suite.total()) {
|
|
47
|
-
await runTests()
|
|
47
|
+
await runTests()
|
|
48
48
|
}
|
|
49
|
-
})()
|
|
49
|
+
})()
|
|
50
50
|
|
|
51
51
|
async function runTests() {
|
|
52
52
|
try {
|
|
53
|
-
await codecept.bootstrap()
|
|
53
|
+
await codecept.bootstrap()
|
|
54
54
|
} catch (err) {
|
|
55
|
-
throw new Error(`Error while running bootstrap file :${err}`)
|
|
55
|
+
throw new Error(`Error while running bootstrap file :${err}`)
|
|
56
56
|
}
|
|
57
|
-
listenToParentThread()
|
|
58
|
-
initializeListeners()
|
|
59
|
-
disablePause()
|
|
57
|
+
listenToParentThread()
|
|
58
|
+
initializeListeners()
|
|
59
|
+
disablePause()
|
|
60
60
|
try {
|
|
61
|
-
await codecept.run()
|
|
61
|
+
await codecept.run()
|
|
62
62
|
} finally {
|
|
63
|
-
await codecept.teardown()
|
|
63
|
+
await codecept.teardown()
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
function filterTests() {
|
|
68
|
-
const files = codecept.testFiles
|
|
69
|
-
mocha.files = files
|
|
70
|
-
mocha.loadFiles()
|
|
68
|
+
const files = codecept.testFiles
|
|
69
|
+
mocha.files = files
|
|
70
|
+
mocha.loadFiles()
|
|
71
71
|
|
|
72
72
|
for (const suite of mocha.suite.suites) {
|
|
73
|
-
suite.tests = suite.tests.filter(test => tests.indexOf(test.uid) >= 0)
|
|
73
|
+
suite.tests = suite.tests.filter(test => tests.indexOf(test.uid) >= 0)
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
function initializeListeners() {
|
|
78
|
-
function simplifyError(error) {
|
|
79
|
-
if (error) {
|
|
80
|
-
const { stack, uncaught, message, actual, expected } = error;
|
|
81
|
-
|
|
82
|
-
return {
|
|
83
|
-
stack,
|
|
84
|
-
uncaught,
|
|
85
|
-
message,
|
|
86
|
-
actual,
|
|
87
|
-
expected,
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
function simplifyTest(test, err = null) {
|
|
94
|
-
test = { ...test };
|
|
95
|
-
|
|
96
|
-
if (test.start && !test.duration) {
|
|
97
|
-
const end = new Date();
|
|
98
|
-
test.duration = end - test.start;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (test.err) {
|
|
102
|
-
err = simplifyError(test.err);
|
|
103
|
-
test.status = 'failed';
|
|
104
|
-
} else if (err) {
|
|
105
|
-
err = simplifyError(err);
|
|
106
|
-
test.status = 'failed';
|
|
107
|
-
}
|
|
108
|
-
const parent = {};
|
|
109
|
-
if (test.parent) {
|
|
110
|
-
parent.title = test.parent.title;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (test.opts) {
|
|
114
|
-
Object.keys(test.opts).forEach(k => {
|
|
115
|
-
if (typeof test.opts[k] === 'object') delete test.opts[k];
|
|
116
|
-
if (typeof test.opts[k] === 'function') delete test.opts[k];
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return {
|
|
121
|
-
opts: test.opts || {},
|
|
122
|
-
tags: test.tags || [],
|
|
123
|
-
uid: test.uid,
|
|
124
|
-
workerIndex,
|
|
125
|
-
retries: test._retries,
|
|
126
|
-
title: test.title,
|
|
127
|
-
status: test.status,
|
|
128
|
-
duration: test.duration || 0,
|
|
129
|
-
err,
|
|
130
|
-
parent,
|
|
131
|
-
steps: test.steps && test.steps.length > 0 ? simplifyStepsInTestObject(test.steps, err) : [],
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function simplifyStepsInTestObject(steps, err) {
|
|
136
|
-
steps = [...steps];
|
|
137
|
-
const _steps = [];
|
|
138
|
-
|
|
139
|
-
for (step of steps) {
|
|
140
|
-
const _args = [];
|
|
141
|
-
|
|
142
|
-
if (step.args) {
|
|
143
|
-
for (const arg of step.args) {
|
|
144
|
-
// check if arg is a JOI object
|
|
145
|
-
if (arg && arg.$_root) {
|
|
146
|
-
_args.push(JSON.stringify(arg).slice(0, 300));
|
|
147
|
-
// check if arg is a function
|
|
148
|
-
} else if (arg && typeof arg === 'function') {
|
|
149
|
-
_args.push(arg.name);
|
|
150
|
-
} else {
|
|
151
|
-
_args.push(arg);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
_steps.push({
|
|
157
|
-
actor: step.actor,
|
|
158
|
-
name: step.name,
|
|
159
|
-
status: step.status,
|
|
160
|
-
args: JSON.stringify(_args),
|
|
161
|
-
startedAt: step.startedAt,
|
|
162
|
-
startTime: step.startTime,
|
|
163
|
-
endTime: step.endTime,
|
|
164
|
-
finishedAt: step.finishedAt,
|
|
165
|
-
duration: step.duration,
|
|
166
|
-
err,
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return _steps;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function simplifyStep(step, err = null) {
|
|
174
|
-
step = { ...step };
|
|
175
|
-
|
|
176
|
-
if (step.startTime && !step.duration) {
|
|
177
|
-
const end = new Date();
|
|
178
|
-
step.duration = end - step.startTime;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (step.err) {
|
|
182
|
-
err = simplifyError(step.err);
|
|
183
|
-
step.status = 'failed';
|
|
184
|
-
} else if (err) {
|
|
185
|
-
err = simplifyError(err);
|
|
186
|
-
step.status = 'failed';
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const parent = {};
|
|
190
|
-
if (step.metaStep) {
|
|
191
|
-
parent.title = step.metaStep.actor;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (step.opts) {
|
|
195
|
-
Object.keys(step.opts).forEach(k => {
|
|
196
|
-
if (typeof step.opts[k] === 'object') delete step.opts[k];
|
|
197
|
-
if (typeof step.opts[k] === 'function') delete step.opts[k];
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
return {
|
|
202
|
-
opts: step.opts || {},
|
|
203
|
-
workerIndex,
|
|
204
|
-
title: step.name,
|
|
205
|
-
status: step.status,
|
|
206
|
-
duration: step.duration || 0,
|
|
207
|
-
err,
|
|
208
|
-
parent,
|
|
209
|
-
test: simplifyTest(step.test),
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
collectStats();
|
|
214
78
|
// suite
|
|
215
|
-
event.dispatcher.on(event.suite.before, suite => sendToParentThread({ event: event.suite.before, workerIndex, data:
|
|
216
|
-
event.dispatcher.on(event.suite.after, suite => sendToParentThread({ event: event.suite.after, workerIndex, data:
|
|
79
|
+
event.dispatcher.on(event.suite.before, suite => sendToParentThread({ event: event.suite.before, workerIndex, data: suite.simplify() }))
|
|
80
|
+
event.dispatcher.on(event.suite.after, suite => sendToParentThread({ event: event.suite.after, workerIndex, data: suite.simplify() }))
|
|
217
81
|
|
|
218
82
|
// calculate duration
|
|
219
|
-
event.dispatcher.on(event.test.started, test => (test.start = new Date()))
|
|
83
|
+
event.dispatcher.on(event.test.started, test => (test.start = new Date()))
|
|
220
84
|
|
|
221
85
|
// tests
|
|
222
|
-
event.dispatcher.on(event.test.before, test => sendToParentThread({ event: event.test.before, workerIndex, data:
|
|
223
|
-
event.dispatcher.on(event.test.after, test => sendToParentThread({ event: event.test.after, workerIndex, data:
|
|
86
|
+
event.dispatcher.on(event.test.before, test => sendToParentThread({ event: event.test.before, workerIndex, data: test.simplify() }))
|
|
87
|
+
event.dispatcher.on(event.test.after, test => sendToParentThread({ event: event.test.after, workerIndex, data: test.simplify() }))
|
|
224
88
|
// we should force-send correct errors to prevent race condition
|
|
225
|
-
event.dispatcher.on(event.test.finished, (test, err) => sendToParentThread({ event: event.test.finished, workerIndex, data:
|
|
226
|
-
event.dispatcher.on(event.test.failed, (test, err) => sendToParentThread({ event: event.test.failed, workerIndex, data:
|
|
227
|
-
event.dispatcher.on(event.test.passed, (test, err) => sendToParentThread({ event: event.test.passed, workerIndex, data:
|
|
228
|
-
event.dispatcher.on(event.test.started, test => sendToParentThread({ event: event.test.started, workerIndex, data:
|
|
229
|
-
event.dispatcher.on(event.test.skipped, test => sendToParentThread({ event: event.test.skipped, workerIndex, data:
|
|
89
|
+
event.dispatcher.on(event.test.finished, (test, err) => sendToParentThread({ event: event.test.finished, workerIndex, data: { ...test.simplify(), err } }))
|
|
90
|
+
event.dispatcher.on(event.test.failed, (test, err) => sendToParentThread({ event: event.test.failed, workerIndex, data: { ...test.simplify(), err } }))
|
|
91
|
+
event.dispatcher.on(event.test.passed, (test, err) => sendToParentThread({ event: event.test.passed, workerIndex, data: { ...test.simplify(), err } }))
|
|
92
|
+
event.dispatcher.on(event.test.started, test => sendToParentThread({ event: event.test.started, workerIndex, data: test.simplify() }))
|
|
93
|
+
event.dispatcher.on(event.test.skipped, test => sendToParentThread({ event: event.test.skipped, workerIndex, data: test.simplify() }))
|
|
230
94
|
|
|
231
95
|
// steps
|
|
232
|
-
event.dispatcher.on(event.step.finished, step => sendToParentThread({ event: event.step.finished, workerIndex, data:
|
|
233
|
-
event.dispatcher.on(event.step.started, step => sendToParentThread({ event: event.step.started, workerIndex, data:
|
|
234
|
-
event.dispatcher.on(event.step.passed, step => sendToParentThread({ event: event.step.passed, workerIndex, data:
|
|
235
|
-
event.dispatcher.on(event.step.failed, step => sendToParentThread({ event: event.step.failed, workerIndex, data:
|
|
96
|
+
event.dispatcher.on(event.step.finished, step => sendToParentThread({ event: event.step.finished, workerIndex, data: step.simplify() }))
|
|
97
|
+
event.dispatcher.on(event.step.started, step => sendToParentThread({ event: event.step.started, workerIndex, data: step.simplify() }))
|
|
98
|
+
event.dispatcher.on(event.step.passed, step => sendToParentThread({ event: event.step.passed, workerIndex, data: step.simplify() }))
|
|
99
|
+
event.dispatcher.on(event.step.failed, step => sendToParentThread({ event: event.step.failed, workerIndex, data: step.simplify() }))
|
|
236
100
|
|
|
237
|
-
event.dispatcher.on(event.hook.failed, (
|
|
238
|
-
event.dispatcher.on(event.hook.passed,
|
|
239
|
-
event.dispatcher.on(event.
|
|
101
|
+
event.dispatcher.on(event.hook.failed, (hook, err) => sendToParentThread({ event: event.hook.failed, workerIndex, data: { ...hook.simplify(), err } }))
|
|
102
|
+
event.dispatcher.on(event.hook.passed, hook => sendToParentThread({ event: event.hook.passed, workerIndex, data: hook.simplify() }))
|
|
103
|
+
event.dispatcher.on(event.hook.finished, hook => sendToParentThread({ event: event.hook.finished, workerIndex, data: hook.simplify() }))
|
|
240
104
|
|
|
105
|
+
event.dispatcher.once(event.all.after, () => {
|
|
106
|
+
sendToParentThread({ event: event.all.after, workerIndex, data: container.result().simplify() })
|
|
107
|
+
})
|
|
241
108
|
// all
|
|
242
|
-
event.dispatcher.once(event.all.result, () =>
|
|
109
|
+
event.dispatcher.once(event.all.result, () => {
|
|
110
|
+
sendToParentThread({ event: event.all.result, workerIndex, data: container.result().simplify() })
|
|
111
|
+
parentPort?.close()
|
|
112
|
+
})
|
|
243
113
|
}
|
|
244
114
|
|
|
245
115
|
function disablePause() {
|
|
246
|
-
global.pause = () => {}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
function collectStats() {
|
|
250
|
-
const stats = {
|
|
251
|
-
passes: 0,
|
|
252
|
-
failures: 0,
|
|
253
|
-
skipped: 0,
|
|
254
|
-
tests: 0,
|
|
255
|
-
pending: 0,
|
|
256
|
-
};
|
|
257
|
-
event.dispatcher.on(event.test.skipped, () => {
|
|
258
|
-
stats.skipped++;
|
|
259
|
-
});
|
|
260
|
-
event.dispatcher.on(event.test.passed, () => {
|
|
261
|
-
stats.passes++;
|
|
262
|
-
});
|
|
263
|
-
event.dispatcher.on(event.test.failed, test => {
|
|
264
|
-
if (test.ctx._runnable.title.includes('hook: AfterSuite')) {
|
|
265
|
-
stats.failedHooks += 1;
|
|
266
|
-
}
|
|
267
|
-
stats.failures++;
|
|
268
|
-
});
|
|
269
|
-
event.dispatcher.on(event.test.skipped, () => {
|
|
270
|
-
stats.pending++;
|
|
271
|
-
});
|
|
272
|
-
event.dispatcher.on(event.test.finished, () => {
|
|
273
|
-
stats.tests++;
|
|
274
|
-
});
|
|
275
|
-
event.dispatcher.once(event.all.after, () => {
|
|
276
|
-
sendToParentThread({ event: event.all.after, data: stats });
|
|
277
|
-
});
|
|
116
|
+
global.pause = () => {}
|
|
278
117
|
}
|
|
279
118
|
|
|
280
119
|
function sendToParentThread(data) {
|
|
281
|
-
parentPort
|
|
120
|
+
parentPort?.postMessage(data)
|
|
282
121
|
}
|
|
283
122
|
|
|
284
123
|
function listenToParentThread() {
|
|
285
|
-
parentPort
|
|
286
|
-
container.append({ support: eventData.data })
|
|
287
|
-
})
|
|
124
|
+
parentPort?.on('message', eventData => {
|
|
125
|
+
container.append({ support: eventData.data })
|
|
126
|
+
})
|
|
288
127
|
}
|