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
|
@@ -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
|
|
@@ -23,15 +23,23 @@ module.exports = async function (path, options) {
|
|
|
23
23
|
|
|
24
24
|
if (options.verbose) output.level(3)
|
|
25
25
|
|
|
26
|
+
let addGlobalRetries
|
|
27
|
+
|
|
28
|
+
if (config.retry) {
|
|
29
|
+
addGlobalRetries = function retries() {}
|
|
30
|
+
}
|
|
31
|
+
|
|
26
32
|
output.print('Starting interactive shell for current suite...')
|
|
27
33
|
recorder.start()
|
|
28
34
|
event.emit(event.suite.before, {
|
|
29
35
|
fullTitle: () => 'Interactive Shell',
|
|
30
36
|
tests: [],
|
|
37
|
+
retries: addGlobalRetries,
|
|
31
38
|
})
|
|
32
39
|
event.emit(event.test.before, {
|
|
33
40
|
title: '',
|
|
34
41
|
artifacts: {},
|
|
42
|
+
retries: addGlobalRetries,
|
|
35
43
|
})
|
|
36
44
|
|
|
37
45
|
const enabledHelpers = Container.helpers()
|
|
@@ -39,7 +47,7 @@ module.exports = async function (path, options) {
|
|
|
39
47
|
if (webHelpers.includes(helperName)) {
|
|
40
48
|
const I = enabledHelpers[helperName]
|
|
41
49
|
recorder.add(() => I.amOnPage('/'))
|
|
42
|
-
recorder.catchWithoutStop(
|
|
50
|
+
recorder.catchWithoutStop(e => output.print(`Error while loading home page: ${e.message}}`))
|
|
43
51
|
break
|
|
44
52
|
}
|
|
45
53
|
}
|
package/lib/command/list.js
CHANGED
|
@@ -17,7 +17,7 @@ module.exports = function (path) {
|
|
|
17
17
|
const actions = []
|
|
18
18
|
for (const name in helpers) {
|
|
19
19
|
const helper = helpers[name]
|
|
20
|
-
methodsOfObject(helper).forEach(
|
|
20
|
+
methodsOfObject(helper).forEach(action => {
|
|
21
21
|
const params = getParamsToString(helper[action])
|
|
22
22
|
actions[action] = 1
|
|
23
23
|
output.print(` ${output.colors.grey(name)} I.${output.colors.bold(action)}(${params})`)
|
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
const
|
|
2
|
-
const path = require('path')
|
|
3
|
-
const fs = require('fs')
|
|
1
|
+
const { globSync } = require('glob')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const fs = require('fs')
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Splits a list to (n) parts, defined via the size argument.
|
|
7
7
|
*/
|
|
8
8
|
const splitFiles = (list, size) => {
|
|
9
|
-
const sets = []
|
|
10
|
-
const chunks = list.length / size
|
|
11
|
-
let i = 0
|
|
9
|
+
const sets = []
|
|
10
|
+
const chunks = list.length / size
|
|
11
|
+
let i = 0
|
|
12
12
|
|
|
13
13
|
while (i < chunks) {
|
|
14
|
-
sets[i] = list.splice(0, size)
|
|
15
|
-
i
|
|
14
|
+
sets[i] = list.splice(0, size)
|
|
15
|
+
i++
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
return sets
|
|
19
|
-
}
|
|
18
|
+
return sets
|
|
19
|
+
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Executes a glob pattern and pushes the results to a list.
|
|
23
23
|
*/
|
|
24
|
-
const findFiles =
|
|
25
|
-
const files = []
|
|
24
|
+
const findFiles = pattern => {
|
|
25
|
+
const files = []
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
files.push(path.resolve(file))
|
|
29
|
-
})
|
|
27
|
+
globSync(pattern).forEach(file => {
|
|
28
|
+
files.push(path.resolve(file))
|
|
29
|
+
})
|
|
30
30
|
|
|
31
|
-
return files
|
|
32
|
-
}
|
|
31
|
+
return files
|
|
32
|
+
}
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* Joins a list of files to a valid glob pattern
|
|
36
36
|
*/
|
|
37
|
-
const flattenFiles =
|
|
38
|
-
const pattern = list.join(',')
|
|
39
|
-
return pattern.indexOf(',') > -1 ? `{${pattern}}` : pattern
|
|
40
|
-
}
|
|
37
|
+
const flattenFiles = list => {
|
|
38
|
+
const pattern = list.join(',')
|
|
39
|
+
return pattern.indexOf(',') > -1 ? `{${pattern}}` : pattern
|
|
40
|
+
}
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* Greps a file by its content, checks if Scenario or Feature text'
|
|
44
44
|
* matches the grep text.
|
|
45
45
|
*/
|
|
46
46
|
const grepFile = (file, grep) => {
|
|
47
|
-
const contents = fs.readFileSync(file, 'utf8')
|
|
48
|
-
const pattern = new RegExp(`((Scenario|Feature)\(.*${grep}.*\))`, 'g')
|
|
49
|
-
return !!pattern.exec(contents)
|
|
50
|
-
}
|
|
47
|
+
const contents = fs.readFileSync(file, 'utf8')
|
|
48
|
+
const pattern = new RegExp(`((Scenario|Feature)\(.*${grep}.*\))`, 'g') // <- How future proof/solid is this?
|
|
49
|
+
return !!pattern.exec(contents)
|
|
50
|
+
}
|
|
51
51
|
|
|
52
|
-
const mapFileFormats =
|
|
52
|
+
const mapFileFormats = files => {
|
|
53
53
|
return {
|
|
54
54
|
gherkin: files.filter(file => file.match(/\.feature$/)),
|
|
55
55
|
js: files.filter(file => file.match(/\.t|js$/)),
|
|
56
|
-
}
|
|
57
|
-
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
60
|
* Creates a list of chunks incl. configuration by either dividing a list of scenario
|
|
@@ -62,30 +62,33 @@ const mapFileFormats = (files) => {
|
|
|
62
62
|
* the splitting.
|
|
63
63
|
*/
|
|
64
64
|
const createChunks = (config, patterns = []) => {
|
|
65
|
-
const files = patterns
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
const files = patterns
|
|
66
|
+
.filter(pattern => !!pattern)
|
|
67
|
+
.map(pattern => {
|
|
68
|
+
return findFiles(pattern).filter(file => {
|
|
69
|
+
return config.grep ? grepFile(file, config.grep) : true
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
.reduce((acc, val) => acc.concat(val), [])
|
|
70
73
|
|
|
71
|
-
let chunks = []
|
|
74
|
+
let chunks = []
|
|
72
75
|
if (typeof config.chunks === 'function') {
|
|
73
|
-
chunks = config.chunks.call(this, files)
|
|
76
|
+
chunks = config.chunks.call(this, files)
|
|
74
77
|
} else if (typeof config.chunks === 'number' || typeof config.chunks === 'string') {
|
|
75
|
-
chunks = splitFiles(files, Math.ceil(files.length / config.chunks))
|
|
78
|
+
chunks = splitFiles(files, Math.ceil(files.length / config.chunks))
|
|
76
79
|
} else {
|
|
77
|
-
throw new Error('chunks is neither a finite number or a valid function')
|
|
80
|
+
throw new Error('chunks is neither a finite number or a valid function')
|
|
78
81
|
}
|
|
79
82
|
|
|
80
|
-
const chunkConfig = { ...config }
|
|
81
|
-
delete chunkConfig.chunks
|
|
83
|
+
const chunkConfig = { ...config }
|
|
84
|
+
delete chunkConfig.chunks
|
|
82
85
|
|
|
83
|
-
return chunks.map(
|
|
84
|
-
const { js, gherkin } = mapFileFormats(chunkFiles)
|
|
85
|
-
return { ...chunkConfig, tests: flattenFiles(js), gherkin: { features: flattenFiles(gherkin) } }
|
|
86
|
-
})
|
|
87
|
-
}
|
|
86
|
+
return chunks.map(chunkFiles => {
|
|
87
|
+
const { js, gherkin } = mapFileFormats(chunkFiles)
|
|
88
|
+
return { ...chunkConfig, tests: flattenFiles(js), gherkin: { features: flattenFiles(gherkin) } }
|
|
89
|
+
})
|
|
90
|
+
}
|
|
88
91
|
|
|
89
92
|
module.exports = {
|
|
90
93
|
createChunks,
|
|
91
|
-
}
|
|
94
|
+
}
|
|
@@ -11,20 +11,7 @@ const { getConfig, getTestRoot, fail } = require('./utils')
|
|
|
11
11
|
const runner = path.join(__dirname, '/../../bin/codecept')
|
|
12
12
|
let config
|
|
13
13
|
const childOpts = {}
|
|
14
|
-
const copyOptions = [
|
|
15
|
-
'override',
|
|
16
|
-
'steps',
|
|
17
|
-
'reporter',
|
|
18
|
-
'verbose',
|
|
19
|
-
'config',
|
|
20
|
-
'reporter-options',
|
|
21
|
-
'grep',
|
|
22
|
-
'fgrep',
|
|
23
|
-
'invert',
|
|
24
|
-
'debug',
|
|
25
|
-
'plugins',
|
|
26
|
-
'colors',
|
|
27
|
-
]
|
|
14
|
+
const copyOptions = ['override', 'steps', 'reporter', 'verbose', 'config', 'reporter-options', 'grep', 'fgrep', 'invert', 'debug', 'plugins', 'colors']
|
|
28
15
|
let overrides = {}
|
|
29
16
|
|
|
30
17
|
// codeceptjs run-multiple smoke:chrome regression:firefox - will launch smoke run in chrome and regression in firefox
|
|
@@ -49,8 +36,8 @@ module.exports = async function (selectedRuns, options) {
|
|
|
49
36
|
|
|
50
37
|
// copy opts to run
|
|
51
38
|
Object.keys(options)
|
|
52
|
-
.filter(
|
|
53
|
-
.forEach(
|
|
39
|
+
.filter(key => copyOptions.indexOf(key) > -1)
|
|
40
|
+
.forEach(key => {
|
|
54
41
|
childOpts[key] = options[key]
|
|
55
42
|
})
|
|
56
43
|
|
|
@@ -96,12 +83,12 @@ module.exports = async function (selectedRuns, options) {
|
|
|
96
83
|
config.gherkin.features = ''
|
|
97
84
|
}
|
|
98
85
|
|
|
99
|
-
const childProcessesPromise = new Promise(
|
|
86
|
+
const childProcessesPromise = new Promise(resolve => {
|
|
100
87
|
processesDone = resolve
|
|
101
88
|
})
|
|
102
89
|
|
|
103
90
|
const runsToExecute = []
|
|
104
|
-
collection.createRuns(selectedRuns, config).forEach(
|
|
91
|
+
collection.createRuns(selectedRuns, config).forEach(run => {
|
|
105
92
|
const runName = run.getOriginalName() || run.getName()
|
|
106
93
|
const runConfig = run.getConfig()
|
|
107
94
|
runsToExecute.push(executeRun(runName, runConfig))
|
|
@@ -113,7 +100,7 @@ module.exports = async function (selectedRuns, options) {
|
|
|
113
100
|
|
|
114
101
|
// Execute all forks
|
|
115
102
|
totalSubprocessCount = runsToExecute.length
|
|
116
|
-
runsToExecute.forEach(
|
|
103
|
+
runsToExecute.forEach(runToExecute => runToExecute.call(this))
|
|
117
104
|
|
|
118
105
|
return childProcessesPromise.then(async () => {
|
|
119
106
|
// fire hook
|
|
@@ -149,11 +136,7 @@ function executeRun(runName, runConfig) {
|
|
|
149
136
|
// tweaking default output directories and for mochawesome
|
|
150
137
|
overriddenConfig = replaceValueDeep(overriddenConfig, 'output', path.join(config.output, outputDir))
|
|
151
138
|
overriddenConfig = replaceValueDeep(overriddenConfig, 'reportDir', path.join(config.output, outputDir))
|
|
152
|
-
overriddenConfig = replaceValueDeep(
|
|
153
|
-
overriddenConfig,
|
|
154
|
-
'mochaFile',
|
|
155
|
-
path.join(config.output, outputDir, `${browserName}_report.xml`),
|
|
156
|
-
)
|
|
139
|
+
overriddenConfig = replaceValueDeep(overriddenConfig, 'mochaFile', path.join(config.output, outputDir, `${browserName}_report.xml`))
|
|
157
140
|
|
|
158
141
|
// override tests configuration
|
|
159
142
|
if (overriddenConfig.tests) {
|
|
@@ -165,15 +148,9 @@ function executeRun(runName, runConfig) {
|
|
|
165
148
|
}
|
|
166
149
|
|
|
167
150
|
// override grep param and collect all params
|
|
168
|
-
const params = [
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
`${runId++}.${runName}:${browserName}`,
|
|
172
|
-
'--override',
|
|
173
|
-
JSON.stringify(overriddenConfig),
|
|
174
|
-
]
|
|
175
|
-
|
|
176
|
-
Object.keys(childOpts).forEach((key) => {
|
|
151
|
+
const params = ['run', '--child', `${runId++}.${runName}:${browserName}`, '--override', JSON.stringify(overriddenConfig)]
|
|
152
|
+
|
|
153
|
+
Object.keys(childOpts).forEach(key => {
|
|
177
154
|
params.push(`--${key}`)
|
|
178
155
|
if (childOpts[key] !== true) params.push(childOpts[key])
|
|
179
156
|
})
|
|
@@ -183,7 +160,7 @@ function executeRun(runName, runConfig) {
|
|
|
183
160
|
params.push(runConfig.grep)
|
|
184
161
|
}
|
|
185
162
|
|
|
186
|
-
const onProcessEnd =
|
|
163
|
+
const onProcessEnd = errorCode => {
|
|
187
164
|
if (errorCode !== 0) {
|
|
188
165
|
process.exitCode = errorCode
|
|
189
166
|
}
|
|
@@ -197,7 +174,7 @@ function executeRun(runName, runConfig) {
|
|
|
197
174
|
// Return function of fork for later execution
|
|
198
175
|
return () =>
|
|
199
176
|
fork(runner, params, { stdio: [0, 1, 2, 'ipc'] })
|
|
200
|
-
.on('exit',
|
|
177
|
+
.on('exit', code => {
|
|
201
178
|
return onProcessEnd(code)
|
|
202
179
|
})
|
|
203
180
|
.on('error', () => {
|
|
@@ -8,15 +8,24 @@ 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
|
+
|
|
14
|
+
// Determine test split strategy
|
|
15
|
+
let by = 'test' // default
|
|
16
|
+
if (options.by) {
|
|
17
|
+
// Explicit --by option takes precedence
|
|
18
|
+
by = options.by
|
|
19
|
+
} else if (options.suites) {
|
|
20
|
+
// Legacy --suites option
|
|
21
|
+
by = 'suite'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Validate the by option
|
|
25
|
+
const validStrategies = ['test', 'suite', 'pool']
|
|
26
|
+
if (!validStrategies.includes(by)) {
|
|
27
|
+
throw new Error(`Invalid --by strategy: ${by}. Valid options are: ${validStrategies.join(', ')}`)
|
|
28
|
+
}
|
|
20
29
|
delete options.parent
|
|
21
30
|
const config = {
|
|
22
31
|
by,
|
|
@@ -30,69 +39,24 @@ module.exports = async function (workerCount, selectedRuns, options) {
|
|
|
30
39
|
output.print(`CodeceptJS v${require('../codecept').version()} ${output.standWithUkraine()}`)
|
|
31
40
|
output.print(`Running tests in ${output.styles.bold(numberOfWorkers)} workers...`)
|
|
32
41
|
output.print()
|
|
42
|
+
store.hasWorkers = true
|
|
33
43
|
|
|
34
44
|
const workers = new Workers(numberOfWorkers, config)
|
|
35
45
|
workers.overrideConfig(overrideConfigs)
|
|
36
46
|
|
|
37
|
-
workers.on(event.
|
|
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
|
-
workers.on(event.test.failed, (test) => {
|
|
50
|
-
failedTestArr.push(test)
|
|
47
|
+
workers.on(event.test.failed, test => {
|
|
51
48
|
output.test.failed(test)
|
|
52
49
|
})
|
|
53
50
|
|
|
54
|
-
workers.on(event.test.passed,
|
|
55
|
-
passedTestArr.push(test)
|
|
51
|
+
workers.on(event.test.passed, test => {
|
|
56
52
|
output.test.passed(test)
|
|
57
53
|
})
|
|
58
54
|
|
|
59
|
-
workers.on(event.test.skipped,
|
|
60
|
-
skippedTestArr.push(test)
|
|
55
|
+
workers.on(event.test.skipped, test => {
|
|
61
56
|
output.test.skipped(test)
|
|
62
57
|
})
|
|
63
58
|
|
|
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
|
-
})
|
|
59
|
+
workers.on(event.all.result, result => {
|
|
96
60
|
workers.printResults()
|
|
97
61
|
})
|
|
98
62
|
|
|
@@ -100,7 +64,6 @@ module.exports = async function (workerCount, selectedRuns, options) {
|
|
|
100
64
|
if (options.verbose || options.debug) store.debugMode = true
|
|
101
65
|
|
|
102
66
|
if (options.verbose) {
|
|
103
|
-
global.debugMode = true
|
|
104
67
|
const { getMachineInfo } = require('./info')
|
|
105
68
|
await getMachineInfo()
|
|
106
69
|
}
|
package/lib/command/utils.js
CHANGED
|
@@ -29,8 +29,7 @@ module.exports.readConfig = function (configFile) {
|
|
|
29
29
|
function getTestRoot(currentPath) {
|
|
30
30
|
if (!currentPath) currentPath = '.'
|
|
31
31
|
if (!path.isAbsolute(currentPath)) currentPath = path.join(process.cwd(), currentPath)
|
|
32
|
-
currentPath =
|
|
33
|
-
fs.lstatSync(currentPath).isDirectory() || !path.extname(currentPath) ? currentPath : path.dirname(currentPath)
|
|
32
|
+
currentPath = fs.lstatSync(currentPath).isDirectory() || !path.extname(currentPath) ? currentPath : path.dirname(currentPath)
|
|
34
33
|
return currentPath
|
|
35
34
|
}
|
|
36
35
|
module.exports.getTestRoot = getTestRoot
|
|
@@ -71,7 +70,7 @@ function safeFileWrite(file, contents) {
|
|
|
71
70
|
|
|
72
71
|
module.exports.safeFileWrite = safeFileWrite
|
|
73
72
|
|
|
74
|
-
module.exports.captureStream =
|
|
73
|
+
module.exports.captureStream = stream => {
|
|
75
74
|
let oldStream
|
|
76
75
|
let buffer = ''
|
|
77
76
|
|
|
@@ -79,7 +78,7 @@ module.exports.captureStream = (stream) => {
|
|
|
79
78
|
startCapture() {
|
|
80
79
|
buffer = ''
|
|
81
80
|
oldStream = stream.write.bind(stream)
|
|
82
|
-
stream.write =
|
|
81
|
+
stream.write = chunk => (buffer += chunk)
|
|
83
82
|
},
|
|
84
83
|
stopCapture() {
|
|
85
84
|
if (oldStream !== undefined) stream.write = oldStream
|
|
@@ -88,7 +87,7 @@ module.exports.captureStream = (stream) => {
|
|
|
88
87
|
}
|
|
89
88
|
}
|
|
90
89
|
|
|
91
|
-
module.exports.printError =
|
|
90
|
+
module.exports.printError = err => {
|
|
92
91
|
output.print('')
|
|
93
92
|
output.error(err.message)
|
|
94
93
|
output.print('')
|
|
@@ -106,7 +105,7 @@ module.exports.createOutputDir = (config, testRoot) => {
|
|
|
106
105
|
}
|
|
107
106
|
}
|
|
108
107
|
|
|
109
|
-
module.exports.findConfigFile =
|
|
108
|
+
module.exports.findConfigFile = testsPath => {
|
|
110
109
|
const extensions = ['js', 'ts']
|
|
111
110
|
for (const ext of extensions) {
|
|
112
111
|
const configFile = path.join(testsPath, `codecept.conf.${ext}`)
|