codeceptjs 4.0.0-beta.4 → 4.0.0-beta.6.esm-aria
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 +89 -119
- package/bin/codecept.js +53 -54
- package/docs/webapi/clearCookie.mustache +1 -1
- package/lib/actor.js +70 -102
- package/lib/ai.js +131 -121
- package/lib/assert/empty.js +11 -12
- package/lib/assert/equal.js +16 -21
- package/lib/assert/error.js +2 -2
- package/lib/assert/include.js +11 -15
- package/lib/assert/throws.js +3 -5
- package/lib/assert/truth.js +10 -7
- package/lib/assert.js +18 -18
- package/lib/codecept.js +112 -101
- package/lib/colorUtils.js +48 -50
- package/lib/command/check.js +206 -0
- package/lib/command/configMigrate.js +13 -14
- package/lib/command/definitions.js +24 -36
- package/lib/command/dryRun.js +16 -16
- package/lib/command/generate.js +38 -39
- package/lib/command/gherkin/init.js +36 -38
- package/lib/command/gherkin/snippets.js +76 -74
- package/lib/command/gherkin/steps.js +21 -18
- package/lib/command/info.js +49 -15
- package/lib/command/init.js +41 -37
- package/lib/command/interactive.js +22 -13
- package/lib/command/list.js +11 -10
- package/lib/command/run-multiple/chunk.js +50 -47
- package/lib/command/run-multiple/collection.js +5 -5
- package/lib/command/run-multiple/run.js +3 -3
- package/lib/command/run-multiple.js +27 -47
- package/lib/command/run-rerun.js +6 -7
- package/lib/command/run-workers.js +15 -66
- package/lib/command/run.js +8 -8
- package/lib/command/utils.js +22 -21
- package/lib/command/workers/runTests.js +131 -241
- package/lib/config.js +111 -49
- package/lib/container.js +589 -244
- package/lib/data/context.js +16 -18
- package/lib/data/dataScenarioConfig.js +9 -9
- package/lib/data/dataTableArgument.js +7 -7
- package/lib/data/table.js +6 -12
- package/lib/effects.js +307 -0
- package/lib/els.js +160 -0
- package/lib/event.js +24 -19
- package/lib/globals.js +141 -0
- package/lib/heal.js +89 -81
- package/lib/helper/AI.js +3 -2
- package/lib/helper/ApiDataFactory.js +19 -19
- package/lib/helper/Appium.js +47 -51
- package/lib/helper/FileSystem.js +35 -15
- package/lib/helper/GraphQL.js +1 -1
- package/lib/helper/GraphQLDataFactory.js +4 -4
- package/lib/helper/JSONResponse.js +72 -45
- package/lib/helper/Mochawesome.js +14 -11
- package/lib/helper/Playwright.js +832 -434
- package/lib/helper/Puppeteer.js +393 -292
- package/lib/helper/REST.js +32 -27
- package/lib/helper/WebDriver.js +320 -219
- package/lib/helper/errors/ConnectionRefused.js +6 -6
- package/lib/helper/errors/ElementAssertion.js +11 -16
- package/lib/helper/errors/ElementNotFound.js +5 -9
- package/lib/helper/errors/RemoteBrowserConnectionRefused.js +5 -5
- package/lib/helper/extras/Console.js +11 -11
- package/lib/helper/extras/PlaywrightLocator.js +110 -0
- package/lib/helper/extras/PlaywrightPropEngine.js +18 -18
- package/lib/helper/extras/PlaywrightRestartOpts.js +23 -23
- package/lib/helper/extras/Popup.js +22 -22
- package/lib/helper/extras/React.js +29 -30
- package/lib/helper/network/actions.js +33 -48
- package/lib/helper/network/utils.js +76 -83
- package/lib/helper/scripts/blurElement.js +6 -6
- package/lib/helper/scripts/focusElement.js +6 -6
- package/lib/helper/scripts/highlightElement.js +9 -9
- package/lib/helper/scripts/isElementClickable.js +34 -34
- package/lib/helper.js +2 -1
- package/lib/history.js +23 -20
- package/lib/hooks.js +10 -10
- package/lib/html.js +90 -100
- package/lib/index.js +48 -21
- package/lib/listener/config.js +8 -9
- package/lib/listener/emptyRun.js +54 -0
- package/lib/listener/exit.js +10 -12
- package/lib/listener/{retry.js → globalRetry.js} +10 -10
- package/lib/listener/globalTimeout.js +166 -0
- package/lib/listener/helpers.js +43 -24
- package/lib/listener/mocha.js +4 -5
- package/lib/listener/result.js +11 -0
- package/lib/listener/steps.js +26 -23
- package/lib/listener/store.js +20 -0
- package/lib/locator.js +213 -192
- package/lib/mocha/asyncWrapper.js +264 -0
- package/lib/mocha/bdd.js +167 -0
- package/lib/mocha/cli.js +341 -0
- package/lib/mocha/factory.js +160 -0
- package/lib/{interfaces → mocha}/featureConfig.js +33 -13
- package/lib/{interfaces → mocha}/gherkin.js +75 -45
- package/lib/mocha/hooks.js +121 -0
- package/lib/mocha/index.js +21 -0
- package/lib/mocha/inject.js +46 -0
- package/lib/{interfaces → mocha}/scenarioConfig.js +32 -8
- package/lib/mocha/suite.js +89 -0
- package/lib/mocha/test.js +178 -0
- package/lib/mocha/types.d.ts +42 -0
- package/lib/mocha/ui.js +229 -0
- package/lib/output.js +86 -64
- package/lib/parser.js +44 -44
- package/lib/pause.js +160 -139
- package/lib/plugin/analyze.js +403 -0
- package/lib/plugin/{autoLogin.js → auth.js} +137 -43
- package/lib/plugin/autoDelay.js +19 -15
- package/lib/plugin/coverage.js +22 -27
- package/lib/plugin/customLocator.js +5 -5
- package/lib/plugin/customReporter.js +53 -0
- package/lib/plugin/heal.js +49 -17
- package/lib/plugin/pageInfo.js +140 -0
- package/lib/plugin/pauseOnFail.js +4 -3
- package/lib/plugin/retryFailedStep.js +60 -19
- package/lib/plugin/screenshotOnFail.js +80 -83
- package/lib/plugin/stepByStepReport.js +70 -31
- package/lib/plugin/stepTimeout.js +7 -13
- package/lib/plugin/subtitles.js +10 -9
- package/lib/recorder.js +167 -126
- package/lib/rerun.js +94 -50
- package/lib/result.js +161 -0
- package/lib/secret.js +18 -17
- package/lib/session.js +95 -89
- 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 +18 -332
- package/lib/steps.js +54 -0
- package/lib/store.js +37 -5
- package/lib/template/heal.js +2 -11
- package/lib/timeout.js +60 -0
- package/lib/transform.js +8 -8
- package/lib/translation.js +32 -18
- package/lib/utils.js +354 -250
- package/lib/workerStorage.js +16 -16
- package/lib/workers.js +366 -282
- package/package.json +107 -95
- package/translations/de-DE.js +5 -4
- package/translations/fr-FR.js +5 -4
- package/translations/index.js +23 -9
- package/translations/it-IT.js +5 -4
- package/translations/ja-JP.js +5 -4
- package/translations/nl-NL.js +76 -0
- package/translations/pl-PL.js +5 -4
- package/translations/pt-BR.js +5 -4
- package/translations/ru-RU.js +5 -4
- package/translations/utils.js +18 -0
- package/translations/zh-CN.js +5 -4
- package/translations/zh-TW.js +5 -4
- package/typings/index.d.ts +177 -186
- package/typings/promiseBasedTypes.d.ts +3573 -5941
- package/typings/types.d.ts +4042 -6370
- package/lib/cli.js +0 -256
- package/lib/helper/ExpectHelper.js +0 -391
- package/lib/helper/Nightmare.js +0 -1504
- package/lib/helper/Protractor.js +0 -1863
- package/lib/helper/SoftExpectHelper.js +0 -381
- package/lib/helper/TestCafe.js +0 -1414
- package/lib/helper/clientscripts/nightmare.js +0 -213
- package/lib/helper/extras/PlaywrightReactVueLocator.js +0 -43
- package/lib/helper/testcafe/testControllerHolder.js +0 -42
- package/lib/helper/testcafe/testcafe-utils.js +0 -62
- package/lib/interfaces/bdd.js +0 -81
- package/lib/listener/artifacts.js +0 -19
- package/lib/listener/timeout.js +0 -109
- package/lib/mochaFactory.js +0 -113
- package/lib/plugin/allure.js +0 -15
- package/lib/plugin/commentStep.js +0 -136
- package/lib/plugin/debugErrors.js +0 -67
- package/lib/plugin/eachElement.js +0 -127
- package/lib/plugin/fakerTransform.js +0 -49
- package/lib/plugin/retryTo.js +0 -127
- package/lib/plugin/selenoid.js +0 -384
- package/lib/plugin/standardActingHelpers.js +0 -3
- package/lib/plugin/tryTo.js +0 -115
- package/lib/plugin/wdio.js +0 -249
- package/lib/scenario.js +0 -224
- package/lib/ui.js +0 -236
- package/lib/within.js +0 -70
package/lib/workers.js
CHANGED
|
@@ -1,54 +1,60 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import { fileURLToPath } from 'url'
|
|
3
|
+
import { dirname } from 'path'
|
|
4
|
+
import { mkdirp } from 'mkdirp'
|
|
5
|
+
import { Worker } from 'worker_threads'
|
|
6
|
+
import { EventEmitter } from 'events'
|
|
7
|
+
import ms from 'ms'
|
|
8
|
+
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
10
|
+
const __dirname = dirname(__filename)
|
|
11
|
+
import Codecept from './codecept.js'
|
|
12
|
+
import MochaFactory from './mocha/factory.js'
|
|
13
|
+
import Container from './container.js'
|
|
14
|
+
import { getTestRoot } from './command/utils.js'
|
|
15
|
+
import { isFunction, fileExists, replaceValueDeep, deepClone } from './utils.js'
|
|
16
|
+
import mainConfig from './config.js'
|
|
17
|
+
import output from './output.js'
|
|
18
|
+
import event from './event.js'
|
|
19
|
+
import { deserializeTest } from './mocha/test.js'
|
|
20
|
+
import { deserializeSuite } from './mocha/suite.js'
|
|
21
|
+
import recorder from './recorder.js'
|
|
22
|
+
import runHook from './hooks.js'
|
|
23
|
+
import WorkerStorage from './workerStorage.js'
|
|
24
|
+
import { createRuns } from './command/run-multiple/collection.js'
|
|
25
|
+
|
|
26
|
+
const pathToWorker = path.join(__dirname, 'command', 'workers', 'runTests.js')
|
|
27
|
+
|
|
28
|
+
const initializeCodecept = async (configPath, options = {}) => {
|
|
29
|
+
const config = await mainConfig.load(configPath || '.')
|
|
30
|
+
const codecept = new Codecept(config, options)
|
|
31
|
+
await codecept.init(getTestRoot(configPath))
|
|
32
|
+
codecept.loadTests()
|
|
33
|
+
|
|
34
|
+
return codecept
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const createOutputDir = async configPath => {
|
|
38
|
+
const config = await mainConfig.load(configPath || '.')
|
|
39
|
+
const testRoot = getTestRoot(configPath)
|
|
40
|
+
const outputDir = path.isAbsolute(config.output) ? config.output : path.join(testRoot, config.output)
|
|
35
41
|
|
|
36
42
|
if (!fileExists(outputDir)) {
|
|
37
|
-
output.print(`creating output directory: ${outputDir}`)
|
|
38
|
-
mkdirp.sync(outputDir)
|
|
43
|
+
output.print(`creating output directory: ${outputDir}`)
|
|
44
|
+
mkdirp.sync(outputDir)
|
|
39
45
|
}
|
|
40
|
-
}
|
|
46
|
+
}
|
|
41
47
|
|
|
42
|
-
const populateGroups =
|
|
43
|
-
const groups = []
|
|
48
|
+
const populateGroups = numberOfWorkers => {
|
|
49
|
+
const groups = []
|
|
44
50
|
for (let i = 0; i < numberOfWorkers; i++) {
|
|
45
|
-
groups[i] = []
|
|
51
|
+
groups[i] = []
|
|
46
52
|
}
|
|
47
53
|
|
|
48
|
-
return groups
|
|
49
|
-
}
|
|
54
|
+
return groups
|
|
55
|
+
}
|
|
50
56
|
|
|
51
|
-
const createWorker =
|
|
57
|
+
const createWorker = workerObject => {
|
|
52
58
|
const worker = new Worker(pathToWorker, {
|
|
53
59
|
workerData: {
|
|
54
60
|
options: simplifyObject(workerObject.options),
|
|
@@ -56,170 +62,168 @@ const createWorker = (workerObject) => {
|
|
|
56
62
|
testRoot: workerObject.testRoot,
|
|
57
63
|
workerIndex: workerObject.workerIndex + 1,
|
|
58
64
|
},
|
|
59
|
-
})
|
|
60
|
-
worker.on('error', err => output.error(`Worker Error: ${err.stack}`))
|
|
65
|
+
})
|
|
66
|
+
worker.on('error', err => output.error(`Worker Error: ${err.stack}`))
|
|
61
67
|
|
|
62
|
-
WorkerStorage.addWorker(worker)
|
|
63
|
-
return worker
|
|
64
|
-
}
|
|
68
|
+
WorkerStorage.addWorker(worker)
|
|
69
|
+
return worker
|
|
70
|
+
}
|
|
65
71
|
|
|
66
|
-
const simplifyObject =
|
|
72
|
+
const simplifyObject = object => {
|
|
67
73
|
return Object.keys(object)
|
|
68
|
-
.filter(
|
|
69
|
-
.filter(
|
|
70
|
-
.filter(
|
|
74
|
+
.filter(k => k.indexOf('_') !== 0)
|
|
75
|
+
.filter(k => typeof object[k] !== 'function')
|
|
76
|
+
.filter(k => typeof object[k] !== 'object')
|
|
71
77
|
.reduce((obj, key) => {
|
|
72
|
-
obj[key] = object[key]
|
|
73
|
-
return obj
|
|
74
|
-
}, {})
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const repackTest = (test) => {
|
|
78
|
-
test = Object.assign(new Test(test.title || '', () => { }), test);
|
|
79
|
-
test.parent = Object.assign(new Suite(test.parent.title), test.parent);
|
|
80
|
-
return test;
|
|
81
|
-
};
|
|
78
|
+
obj[key] = object[key]
|
|
79
|
+
return obj
|
|
80
|
+
}, {})
|
|
81
|
+
}
|
|
82
82
|
|
|
83
83
|
const createWorkerObjects = (testGroups, config, testRoot, options, selectedRuns) => {
|
|
84
|
-
selectedRuns = options && options.all && config.multiple ? Object.keys(config.multiple) : selectedRuns
|
|
84
|
+
selectedRuns = options && options.all && config.multiple ? Object.keys(config.multiple) : selectedRuns
|
|
85
85
|
if (selectedRuns === undefined || !selectedRuns.length || config.multiple === undefined) {
|
|
86
86
|
return testGroups.map((tests, index) => {
|
|
87
|
-
const workerObj = new WorkerObject(index)
|
|
88
|
-
workerObj.addConfig(config)
|
|
89
|
-
workerObj.addTests(tests)
|
|
90
|
-
workerObj.setTestRoot(testRoot)
|
|
91
|
-
workerObj.addOptions(options)
|
|
92
|
-
return workerObj
|
|
93
|
-
})
|
|
87
|
+
const workerObj = new WorkerObject(index)
|
|
88
|
+
workerObj.addConfig(config)
|
|
89
|
+
workerObj.addTests(tests)
|
|
90
|
+
workerObj.setTestRoot(testRoot)
|
|
91
|
+
workerObj.addOptions(options)
|
|
92
|
+
return workerObj
|
|
93
|
+
})
|
|
94
94
|
}
|
|
95
|
-
const workersToExecute = []
|
|
95
|
+
const workersToExecute = []
|
|
96
96
|
|
|
97
|
-
const currentOutputFolder = config.output
|
|
98
|
-
let currentMochawesomeReportDir
|
|
99
|
-
let currentMochaJunitReporterFile
|
|
97
|
+
const currentOutputFolder = config.output
|
|
98
|
+
let currentMochawesomeReportDir
|
|
99
|
+
let currentMochaJunitReporterFile
|
|
100
100
|
|
|
101
101
|
if (config.mocha && config.mocha.reporterOptions) {
|
|
102
|
-
currentMochawesomeReportDir = config.mocha.reporterOptions?.mochawesome.options.reportDir
|
|
103
|
-
currentMochaJunitReporterFile = config.mocha.reporterOptions['mocha-junit-reporter'].options.mochaFile
|
|
102
|
+
currentMochawesomeReportDir = config.mocha.reporterOptions?.mochawesome.options.reportDir
|
|
103
|
+
currentMochaJunitReporterFile = config.mocha.reporterOptions['mocha-junit-reporter'].options.mochaFile
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
const separator = path.sep
|
|
108
|
-
const _config = { ...config }
|
|
109
|
-
let workerName = worker.name.replace(':', '_')
|
|
110
|
-
_config.output = `${currentOutputFolder}${separator}${workerName}
|
|
106
|
+
createRuns(selectedRuns, config).forEach(worker => {
|
|
107
|
+
const separator = path.sep
|
|
108
|
+
const _config = { ...config }
|
|
109
|
+
let workerName = worker.name.replace(':', '_')
|
|
110
|
+
_config.output = `${currentOutputFolder}${separator}${workerName}`
|
|
111
111
|
if (config.mocha && config.mocha.reporterOptions) {
|
|
112
|
-
_config.mocha.reporterOptions.mochawesome.options.reportDir = `${currentMochawesomeReportDir}${separator}${workerName}
|
|
113
|
-
|
|
114
|
-
const _tempArray = currentMochaJunitReporterFile.split(separator)
|
|
115
|
-
_tempArray.splice(
|
|
116
|
-
|
|
112
|
+
_config.mocha.reporterOptions.mochawesome.options.reportDir = `${currentMochawesomeReportDir}${separator}${workerName}`
|
|
113
|
+
|
|
114
|
+
const _tempArray = currentMochaJunitReporterFile.split(separator)
|
|
115
|
+
_tempArray.splice(
|
|
116
|
+
_tempArray.findIndex(item => item.includes('.xml')),
|
|
117
|
+
0,
|
|
118
|
+
workerName,
|
|
119
|
+
)
|
|
120
|
+
_config.mocha.reporterOptions['mocha-junit-reporter'].options.mochaFile = _tempArray.join(separator)
|
|
117
121
|
}
|
|
118
|
-
workerName = worker.getOriginalName() || worker.getName()
|
|
119
|
-
const workerConfig = worker.getConfig()
|
|
120
|
-
workersToExecute.push(getOverridenConfig(workerName, workerConfig, _config))
|
|
121
|
-
})
|
|
122
|
-
const workers = []
|
|
123
|
-
let index = 0
|
|
124
|
-
testGroups.forEach(
|
|
125
|
-
const testWorkerArray = []
|
|
126
|
-
workersToExecute.forEach(
|
|
127
|
-
const workerObj = new WorkerObject(index++)
|
|
128
|
-
workerObj.addConfig(finalConfig)
|
|
129
|
-
workerObj.addTests(tests)
|
|
130
|
-
workerObj.setTestRoot(testRoot)
|
|
131
|
-
workerObj.addOptions(options)
|
|
132
|
-
testWorkerArray.push(workerObj)
|
|
133
|
-
})
|
|
134
|
-
workers.push(...testWorkerArray)
|
|
135
|
-
})
|
|
136
|
-
return workers
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const indexOfSmallestElement =
|
|
140
|
-
let i = 0
|
|
122
|
+
workerName = worker.getOriginalName() || worker.getName()
|
|
123
|
+
const workerConfig = worker.getConfig()
|
|
124
|
+
workersToExecute.push(getOverridenConfig(workerName, workerConfig, _config))
|
|
125
|
+
})
|
|
126
|
+
const workers = []
|
|
127
|
+
let index = 0
|
|
128
|
+
testGroups.forEach(tests => {
|
|
129
|
+
const testWorkerArray = []
|
|
130
|
+
workersToExecute.forEach(finalConfig => {
|
|
131
|
+
const workerObj = new WorkerObject(index++)
|
|
132
|
+
workerObj.addConfig(finalConfig)
|
|
133
|
+
workerObj.addTests(tests)
|
|
134
|
+
workerObj.setTestRoot(testRoot)
|
|
135
|
+
workerObj.addOptions(options)
|
|
136
|
+
testWorkerArray.push(workerObj)
|
|
137
|
+
})
|
|
138
|
+
workers.push(...testWorkerArray)
|
|
139
|
+
})
|
|
140
|
+
return workers
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const indexOfSmallestElement = groups => {
|
|
144
|
+
let i = 0
|
|
141
145
|
for (let j = 1; j < groups.length; j++) {
|
|
142
146
|
if (groups[j - 1].length > groups[j].length) {
|
|
143
|
-
i = j
|
|
147
|
+
i = j
|
|
144
148
|
}
|
|
145
149
|
}
|
|
146
|
-
return i
|
|
147
|
-
}
|
|
150
|
+
return i
|
|
151
|
+
}
|
|
148
152
|
|
|
149
|
-
const convertToMochaTests =
|
|
150
|
-
const group = []
|
|
153
|
+
const convertToMochaTests = testGroup => {
|
|
154
|
+
const group = []
|
|
151
155
|
if (testGroup instanceof Array) {
|
|
152
|
-
const mocha = MochaFactory.create({}, {})
|
|
153
|
-
mocha.files = testGroup
|
|
154
|
-
mocha.loadFiles()
|
|
155
|
-
mocha.suite.eachTest(
|
|
156
|
-
group.push(test.uid)
|
|
157
|
-
})
|
|
158
|
-
mocha.unloadFiles()
|
|
156
|
+
const mocha = MochaFactory.create({}, {})
|
|
157
|
+
mocha.files = testGroup
|
|
158
|
+
mocha.loadFiles()
|
|
159
|
+
mocha.suite.eachTest(test => {
|
|
160
|
+
group.push(test.uid)
|
|
161
|
+
})
|
|
162
|
+
mocha.unloadFiles()
|
|
159
163
|
}
|
|
160
164
|
|
|
161
|
-
return group
|
|
162
|
-
}
|
|
165
|
+
return group
|
|
166
|
+
}
|
|
163
167
|
|
|
164
168
|
const getOverridenConfig = (workerName, workerConfig, config) => {
|
|
165
169
|
// clone config
|
|
166
|
-
const overriddenConfig = deepClone(config)
|
|
170
|
+
const overriddenConfig = deepClone(config)
|
|
167
171
|
|
|
168
172
|
// get configuration
|
|
169
|
-
const browserConfig = workerConfig.browser
|
|
173
|
+
const browserConfig = workerConfig.browser
|
|
170
174
|
|
|
171
175
|
for (const key in browserConfig) {
|
|
172
|
-
overriddenConfig.helpers = replaceValueDeep(overriddenConfig.helpers, key, browserConfig[key])
|
|
176
|
+
overriddenConfig.helpers = replaceValueDeep(overriddenConfig.helpers, key, browserConfig[key])
|
|
173
177
|
}
|
|
174
178
|
|
|
175
179
|
// override tests configuration
|
|
176
180
|
if (overriddenConfig.tests) {
|
|
177
|
-
overriddenConfig.tests = workerConfig.tests
|
|
181
|
+
overriddenConfig.tests = workerConfig.tests
|
|
178
182
|
}
|
|
179
183
|
|
|
180
184
|
if (overriddenConfig.gherkin && workerConfig.gherkin && workerConfig.gherkin.features) {
|
|
181
|
-
overriddenConfig.gherkin.features = workerConfig.gherkin.features
|
|
185
|
+
overriddenConfig.gherkin.features = workerConfig.gherkin.features
|
|
182
186
|
}
|
|
183
|
-
return overriddenConfig
|
|
184
|
-
}
|
|
187
|
+
return overriddenConfig
|
|
188
|
+
}
|
|
185
189
|
|
|
186
190
|
class WorkerObject {
|
|
187
191
|
/**
|
|
188
192
|
* @param {Number} workerIndex - Unique ID for worker
|
|
189
193
|
*/
|
|
190
194
|
constructor(workerIndex) {
|
|
191
|
-
this.workerIndex = workerIndex
|
|
192
|
-
this.options = {}
|
|
193
|
-
this.tests = []
|
|
194
|
-
this.testRoot = getTestRoot()
|
|
195
|
+
this.workerIndex = workerIndex
|
|
196
|
+
this.options = {}
|
|
197
|
+
this.tests = []
|
|
198
|
+
this.testRoot = getTestRoot()
|
|
195
199
|
}
|
|
196
200
|
|
|
197
201
|
addConfig(config) {
|
|
198
|
-
const oldConfig = JSON.parse(this.options.override || '{}')
|
|
202
|
+
const oldConfig = JSON.parse(this.options.override || '{}')
|
|
199
203
|
const newConfig = {
|
|
200
204
|
...oldConfig,
|
|
201
205
|
...config,
|
|
202
|
-
}
|
|
203
|
-
this.options.override = JSON.stringify(newConfig)
|
|
206
|
+
}
|
|
207
|
+
this.options.override = JSON.stringify(newConfig)
|
|
204
208
|
}
|
|
205
209
|
|
|
206
210
|
addTestFiles(testGroup) {
|
|
207
|
-
this.addTests(convertToMochaTests(testGroup))
|
|
211
|
+
this.addTests(convertToMochaTests(testGroup))
|
|
208
212
|
}
|
|
209
213
|
|
|
210
214
|
addTests(tests) {
|
|
211
|
-
this.tests = this.tests.concat(tests)
|
|
215
|
+
this.tests = this.tests.concat(tests)
|
|
212
216
|
}
|
|
213
217
|
|
|
214
218
|
setTestRoot(path) {
|
|
215
|
-
this.testRoot = getTestRoot(path)
|
|
219
|
+
this.testRoot = getTestRoot(path)
|
|
216
220
|
}
|
|
217
221
|
|
|
218
222
|
addOptions(opts) {
|
|
219
223
|
this.options = {
|
|
220
224
|
...this.options,
|
|
221
225
|
...opts,
|
|
222
|
-
}
|
|
226
|
+
}
|
|
223
227
|
}
|
|
224
228
|
}
|
|
225
229
|
|
|
@@ -229,30 +233,47 @@ class Workers extends EventEmitter {
|
|
|
229
233
|
* @param {Object} config
|
|
230
234
|
*/
|
|
231
235
|
constructor(numberOfWorkers, config = { by: 'test' }) {
|
|
232
|
-
super()
|
|
233
|
-
this.setMaxListeners(50)
|
|
234
|
-
this.
|
|
235
|
-
this.
|
|
236
|
-
this.errors = []
|
|
237
|
-
this.numberOfWorkers = 0
|
|
238
|
-
this.closedWorkers = 0
|
|
239
|
-
this.workers = []
|
|
240
|
-
this.
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
236
|
+
super()
|
|
237
|
+
this.setMaxListeners(50)
|
|
238
|
+
this.codeceptPromise = initializeCodecept(config.testConfig, config.options)
|
|
239
|
+
this.codecept = null
|
|
240
|
+
this.errors = []
|
|
241
|
+
this.numberOfWorkers = 0
|
|
242
|
+
this.closedWorkers = 0
|
|
243
|
+
this.workers = []
|
|
244
|
+
this.testGroups = []
|
|
245
|
+
this.config = config
|
|
246
|
+
this.numberOfWorkersRequested = numberOfWorkers
|
|
247
|
+
// Track emitted pass events to avoid double-counting duplicates from retries/race conditions
|
|
248
|
+
this._passedUids = new Set()
|
|
249
|
+
|
|
250
|
+
createOutputDir(config.testConfig)
|
|
251
|
+
// Defer worker initialization until codecept is ready
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async _ensureInitialized() {
|
|
255
|
+
if (!this.codecept) {
|
|
256
|
+
this.codecept = await this.codeceptPromise
|
|
257
|
+
// Initialize workers in these cases:
|
|
258
|
+
// 1. Positive number requested AND no manual workers pre-spawned
|
|
259
|
+
// 2. Function-based grouping (indicated by negative number) AND no manual workers pre-spawned
|
|
260
|
+
const shouldAutoInit = this.workers.length === 0 && (
|
|
261
|
+
(Number.isInteger(this.numberOfWorkersRequested) && this.numberOfWorkersRequested > 0) ||
|
|
262
|
+
(this.numberOfWorkersRequested < 0 && isFunction(this.config.by))
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
if (shouldAutoInit) {
|
|
266
|
+
this._initWorkers(this.numberOfWorkersRequested, this.config)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
250
269
|
}
|
|
251
270
|
|
|
252
271
|
_initWorkers(numberOfWorkers, config) {
|
|
253
|
-
this.splitTestsByGroups(numberOfWorkers, config)
|
|
254
|
-
|
|
255
|
-
|
|
272
|
+
this.splitTestsByGroups(numberOfWorkers, config)
|
|
273
|
+
// For function-based grouping, use the actual number of test groups created
|
|
274
|
+
const actualNumberOfWorkers = isFunction(config.by) ? this.testGroups.length : numberOfWorkers
|
|
275
|
+
this.workers = createWorkerObjects(this.testGroups, this.codecept.config, config.testConfig, config.options, config.selectedRuns)
|
|
276
|
+
this.numberOfWorkers = this.workers.length
|
|
256
277
|
}
|
|
257
278
|
|
|
258
279
|
/**
|
|
@@ -269,16 +290,16 @@ class Workers extends EventEmitter {
|
|
|
269
290
|
*/
|
|
270
291
|
splitTestsByGroups(numberOfWorkers, config) {
|
|
271
292
|
if (isFunction(config.by)) {
|
|
272
|
-
const createTests = config.by
|
|
273
|
-
const testGroups = createTests(numberOfWorkers)
|
|
293
|
+
const createTests = config.by
|
|
294
|
+
const testGroups = createTests(numberOfWorkers)
|
|
274
295
|
if (!(testGroups instanceof Array)) {
|
|
275
|
-
throw new Error('Test group should be an array')
|
|
296
|
+
throw new Error('Test group should be an array')
|
|
276
297
|
}
|
|
277
298
|
for (const testGroup of testGroups) {
|
|
278
|
-
this.testGroups.push(convertToMochaTests(testGroup))
|
|
299
|
+
this.testGroups.push(convertToMochaTests(testGroup))
|
|
279
300
|
}
|
|
280
301
|
} else if (typeof numberOfWorkers === 'number' && numberOfWorkers > 0) {
|
|
281
|
-
this.testGroups = config.by === 'suite' ? this.createGroupsOfSuites(numberOfWorkers) : this.createGroupsOfTests(numberOfWorkers)
|
|
302
|
+
this.testGroups = config.by === 'suite' ? this.createGroupsOfSuites(numberOfWorkers) : this.createGroupsOfTests(numberOfWorkers)
|
|
282
303
|
}
|
|
283
304
|
}
|
|
284
305
|
|
|
@@ -288,53 +309,57 @@ class Workers extends EventEmitter {
|
|
|
288
309
|
* @returns {WorkerObject}
|
|
289
310
|
*/
|
|
290
311
|
spawn() {
|
|
291
|
-
const worker = new WorkerObject(this.numberOfWorkers)
|
|
292
|
-
this.workers.push(worker)
|
|
293
|
-
this.numberOfWorkers += 1
|
|
294
|
-
return worker
|
|
312
|
+
const worker = new WorkerObject(this.numberOfWorkers)
|
|
313
|
+
this.workers.push(worker)
|
|
314
|
+
this.numberOfWorkers += 1
|
|
315
|
+
return worker
|
|
295
316
|
}
|
|
296
317
|
|
|
297
318
|
/**
|
|
298
319
|
* @param {Number} numberOfWorkers
|
|
299
320
|
*/
|
|
300
321
|
createGroupsOfTests(numberOfWorkers) {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
mocha.
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
322
|
+
// If Codecept isn't initialized yet, return empty groups as a safe fallback
|
|
323
|
+
if (!this.codecept) return populateGroups(numberOfWorkers)
|
|
324
|
+
const files = this.codecept.testFiles
|
|
325
|
+
const mocha = Container.mocha()
|
|
326
|
+
mocha.files = files
|
|
327
|
+
mocha.loadFiles()
|
|
328
|
+
|
|
329
|
+
const groups = populateGroups(numberOfWorkers)
|
|
330
|
+
let groupCounter = 0
|
|
331
|
+
|
|
332
|
+
mocha.suite.eachTest(test => {
|
|
333
|
+
const i = groupCounter % groups.length
|
|
311
334
|
if (test) {
|
|
312
|
-
groups[i].push(test.uid)
|
|
313
|
-
groupCounter
|
|
335
|
+
groups[i].push(test.uid)
|
|
336
|
+
groupCounter++
|
|
314
337
|
}
|
|
315
|
-
})
|
|
316
|
-
return groups
|
|
338
|
+
})
|
|
339
|
+
return groups
|
|
317
340
|
}
|
|
318
341
|
|
|
319
342
|
/**
|
|
320
343
|
* @param {Number} numberOfWorkers
|
|
321
344
|
*/
|
|
322
345
|
createGroupsOfSuites(numberOfWorkers) {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
mocha.
|
|
329
|
-
mocha.
|
|
330
|
-
|
|
331
|
-
|
|
346
|
+
// If Codecept isn't initialized yet, return empty groups as a safe fallback
|
|
347
|
+
if (!this.codecept) return populateGroups(numberOfWorkers)
|
|
348
|
+
const files = this.codecept.testFiles
|
|
349
|
+
const groups = populateGroups(numberOfWorkers)
|
|
350
|
+
|
|
351
|
+
const mocha = Container.mocha()
|
|
352
|
+
mocha.files = files
|
|
353
|
+
mocha.loadFiles()
|
|
354
|
+
mocha.suite.suites.forEach(suite => {
|
|
355
|
+
const i = indexOfSmallestElement(groups)
|
|
356
|
+
suite.tests.forEach(test => {
|
|
332
357
|
if (test) {
|
|
333
|
-
groups[i].push(test.uid)
|
|
358
|
+
groups[i].push(test.uid)
|
|
334
359
|
}
|
|
335
|
-
})
|
|
336
|
-
})
|
|
337
|
-
return groups
|
|
360
|
+
})
|
|
361
|
+
})
|
|
362
|
+
return groups
|
|
338
363
|
}
|
|
339
364
|
|
|
340
365
|
/**
|
|
@@ -342,160 +367,219 @@ class Workers extends EventEmitter {
|
|
|
342
367
|
*/
|
|
343
368
|
overrideConfig(config) {
|
|
344
369
|
for (const worker of this.workers) {
|
|
345
|
-
worker.addConfig(config)
|
|
370
|
+
worker.addConfig(config)
|
|
346
371
|
}
|
|
347
372
|
}
|
|
348
373
|
|
|
349
374
|
async bootstrapAll() {
|
|
350
|
-
|
|
375
|
+
await this._ensureInitialized()
|
|
376
|
+
return runHook(this.codecept.config.bootstrapAll, 'bootstrapAll')
|
|
351
377
|
}
|
|
352
378
|
|
|
353
379
|
async teardownAll() {
|
|
354
|
-
|
|
380
|
+
await this._ensureInitialized()
|
|
381
|
+
return runHook(this.codecept.config.teardownAll, 'teardownAll')
|
|
355
382
|
}
|
|
356
383
|
|
|
357
|
-
run() {
|
|
358
|
-
this.
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
process.env.RUNS_WITH_WORKERS = 'true';
|
|
384
|
+
async run() {
|
|
385
|
+
await this._ensureInitialized()
|
|
386
|
+
recorder.startUnlessRunning()
|
|
387
|
+
event.dispatcher.emit(event.workers.before)
|
|
388
|
+
process.env.RUNS_WITH_WORKERS = 'true'
|
|
363
389
|
recorder.add('starting workers', () => {
|
|
364
390
|
for (const worker of this.workers) {
|
|
365
|
-
const workerThread = createWorker(worker)
|
|
366
|
-
this._listenWorkerEvents(workerThread)
|
|
391
|
+
const workerThread = createWorker(worker)
|
|
392
|
+
this._listenWorkerEvents(workerThread)
|
|
367
393
|
}
|
|
368
|
-
})
|
|
394
|
+
})
|
|
369
395
|
return new Promise(resolve => {
|
|
370
|
-
this.on('end', resolve)
|
|
371
|
-
})
|
|
396
|
+
this.on('end', resolve)
|
|
397
|
+
})
|
|
372
398
|
}
|
|
373
399
|
|
|
374
400
|
/**
|
|
375
401
|
* @returns {Array<WorkerObject>}
|
|
376
402
|
*/
|
|
377
403
|
getWorkers() {
|
|
378
|
-
return this.workers
|
|
404
|
+
return this.workers
|
|
379
405
|
}
|
|
380
406
|
|
|
381
407
|
/**
|
|
382
408
|
* @returns {Boolean}
|
|
383
409
|
*/
|
|
384
410
|
isFailed() {
|
|
385
|
-
return (
|
|
411
|
+
return (Container.result().failures.length || this.errors.length) > 0
|
|
386
412
|
}
|
|
387
413
|
|
|
388
414
|
_listenWorkerEvents(worker) {
|
|
389
|
-
worker.on('message',
|
|
390
|
-
output.process(message.workerIndex)
|
|
415
|
+
worker.on('message', message => {
|
|
416
|
+
output.process(message.workerIndex)
|
|
391
417
|
|
|
392
418
|
// deal with events that are not test cycle related
|
|
393
419
|
if (!message.event) {
|
|
394
|
-
return this.emit('message', message)
|
|
420
|
+
return this.emit('message', message)
|
|
395
421
|
}
|
|
396
422
|
|
|
397
423
|
switch (message.event) {
|
|
398
|
-
case event.all.
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
424
|
+
case event.all.result:
|
|
425
|
+
// we ensure consistency of result by adding tests in the very end
|
|
426
|
+
Container.result().addFailures(message.data.failures)
|
|
427
|
+
Container.result().addStats(message.data.stats)
|
|
428
|
+
message.data.tests.forEach(test => {
|
|
429
|
+
Container.result().addTest(deserializeTest(test))
|
|
430
|
+
})
|
|
431
|
+
break
|
|
402
432
|
case event.suite.before:
|
|
403
|
-
this.emit(event.suite.before,
|
|
404
|
-
break
|
|
405
|
-
case event.hook.failed:
|
|
406
|
-
this.emit(event.hook.failed, repackTest(message.data));
|
|
407
|
-
this.errors.push(message.data.err);
|
|
408
|
-
break;
|
|
433
|
+
this.emit(event.suite.before, deserializeSuite(message.data))
|
|
434
|
+
break
|
|
409
435
|
case event.test.before:
|
|
410
|
-
this.emit(event.test.before,
|
|
411
|
-
break
|
|
436
|
+
this.emit(event.test.before, deserializeTest(message.data))
|
|
437
|
+
break
|
|
412
438
|
case event.test.started:
|
|
413
|
-
this.emit(event.test.started,
|
|
414
|
-
break
|
|
439
|
+
this.emit(event.test.started, deserializeTest(message.data))
|
|
440
|
+
break
|
|
415
441
|
case event.test.failed:
|
|
416
|
-
|
|
417
|
-
break
|
|
442
|
+
// Skip individual failed events - we'll emit based on finished state
|
|
443
|
+
break
|
|
418
444
|
case event.test.passed:
|
|
419
|
-
|
|
420
|
-
break
|
|
445
|
+
// Skip individual passed events - we'll emit based on finished state
|
|
446
|
+
break
|
|
421
447
|
case event.test.skipped:
|
|
422
|
-
this.emit(event.test.skipped,
|
|
423
|
-
break
|
|
448
|
+
this.emit(event.test.skipped, deserializeTest(message.data))
|
|
449
|
+
break
|
|
424
450
|
case event.test.finished:
|
|
425
|
-
|
|
426
|
-
|
|
451
|
+
// Handle different types of test completion properly
|
|
452
|
+
{
|
|
453
|
+
const data = message.data
|
|
454
|
+
const uid = data?.uid
|
|
455
|
+
const isFailed = !!data?.err || data?.state === 'failed'
|
|
456
|
+
|
|
457
|
+
if (uid) {
|
|
458
|
+
// Track states for each test UID
|
|
459
|
+
if (!this._testStates) this._testStates = new Map()
|
|
460
|
+
|
|
461
|
+
if (!this._testStates.has(uid)) {
|
|
462
|
+
this._testStates.set(uid, { states: [], lastData: data })
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const testState = this._testStates.get(uid)
|
|
466
|
+
testState.states.push({ isFailed, data })
|
|
467
|
+
testState.lastData = data
|
|
468
|
+
} else {
|
|
469
|
+
// For tests without UID, emit immediately
|
|
470
|
+
if (isFailed) {
|
|
471
|
+
this.emit(event.test.failed, deserializeTest(data))
|
|
472
|
+
} else {
|
|
473
|
+
this.emit(event.test.passed, deserializeTest(data))
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
this.emit(event.test.finished, deserializeTest(data))
|
|
478
|
+
}
|
|
479
|
+
break
|
|
427
480
|
case event.test.after:
|
|
428
|
-
this.emit(event.test.after,
|
|
429
|
-
break
|
|
481
|
+
this.emit(event.test.after, deserializeTest(message.data))
|
|
482
|
+
break
|
|
430
483
|
case event.step.finished:
|
|
431
|
-
this.emit(event.step.finished, message.data)
|
|
432
|
-
break
|
|
484
|
+
this.emit(event.step.finished, message.data)
|
|
485
|
+
break
|
|
433
486
|
case event.step.started:
|
|
434
|
-
this.emit(event.step.started, message.data)
|
|
435
|
-
break
|
|
487
|
+
this.emit(event.step.started, message.data)
|
|
488
|
+
break
|
|
436
489
|
case event.step.passed:
|
|
437
|
-
this.emit(event.step.passed, message.data)
|
|
438
|
-
break
|
|
490
|
+
this.emit(event.step.passed, message.data)
|
|
491
|
+
break
|
|
439
492
|
case event.step.failed:
|
|
440
|
-
this.emit(event.step.failed, message.data)
|
|
441
|
-
break
|
|
493
|
+
this.emit(event.step.failed, message.data, message.data.error)
|
|
494
|
+
break
|
|
495
|
+
case event.hook.failed:
|
|
496
|
+
// Count hook failures as test failures for event counting
|
|
497
|
+
this.emit(event.test.failed, { title: `Hook failure: ${message.data.hookName || 'unknown'}`, err: message.data.error })
|
|
498
|
+
this.emit(event.hook.failed, message.data)
|
|
499
|
+
break
|
|
442
500
|
}
|
|
443
|
-
})
|
|
501
|
+
})
|
|
444
502
|
|
|
445
|
-
worker.on('error',
|
|
446
|
-
this.errors.push(err)
|
|
447
|
-
})
|
|
503
|
+
worker.on('error', err => {
|
|
504
|
+
this.errors.push(err)
|
|
505
|
+
})
|
|
448
506
|
|
|
449
507
|
worker.on('exit', () => {
|
|
450
|
-
this.closedWorkers += 1
|
|
508
|
+
this.closedWorkers += 1
|
|
451
509
|
if (this.closedWorkers === this.numberOfWorkers) {
|
|
452
|
-
this._finishRun()
|
|
510
|
+
this._finishRun()
|
|
453
511
|
}
|
|
454
|
-
})
|
|
512
|
+
})
|
|
455
513
|
}
|
|
456
514
|
|
|
457
515
|
_finishRun() {
|
|
458
|
-
event.dispatcher.emit(event.workers.after)
|
|
459
|
-
if (
|
|
460
|
-
process.exitCode = 1
|
|
516
|
+
event.dispatcher.emit(event.workers.after, { tests: this.workers.map(worker => worker.tests) })
|
|
517
|
+
if (Container.result().hasFailed) {
|
|
518
|
+
process.exitCode = 1
|
|
461
519
|
} else {
|
|
462
|
-
process.exitCode = 0
|
|
520
|
+
process.exitCode = 0
|
|
463
521
|
}
|
|
464
|
-
// removed this.finishedTests because in all /lib only first argument (!this.isFailed()) is used)
|
|
465
|
-
this.emit(event.all.result, !this.isFailed());
|
|
466
|
-
this.emit('end'); // internal event
|
|
467
|
-
}
|
|
468
522
|
|
|
469
|
-
|
|
470
|
-
this.
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
523
|
+
// Emit states for all tracked tests before emitting results
|
|
524
|
+
if (this._testStates) {
|
|
525
|
+
for (const [uid, { states, lastData }] of this._testStates) {
|
|
526
|
+
// For tests with retries configured, emit all failures + final success
|
|
527
|
+
// For tests without retries, emit only final state
|
|
528
|
+
const lastState = states[states.length - 1]
|
|
529
|
+
|
|
530
|
+
// Check if this test had retries by looking for failure followed by success
|
|
531
|
+
const hasRetryPattern = states.length > 1 &&
|
|
532
|
+
states.some((s, i) => s.isFailed && i < states.length - 1 && !states[i + 1].isFailed)
|
|
533
|
+
|
|
534
|
+
if (hasRetryPattern) {
|
|
535
|
+
// Emit all intermediate failures and final success for retries
|
|
536
|
+
for (const state of states) {
|
|
537
|
+
if (state.isFailed) {
|
|
538
|
+
this.emit(event.test.failed, deserializeTest(state.data))
|
|
539
|
+
} else {
|
|
540
|
+
this.emit(event.test.passed, deserializeTest(state.data))
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
} else {
|
|
544
|
+
// For non-retries (like step failures), emit only the final state
|
|
545
|
+
if (lastState.isFailed) {
|
|
546
|
+
this.emit(event.test.failed, deserializeTest(lastState.data))
|
|
547
|
+
} else {
|
|
548
|
+
this.emit(event.test.passed, deserializeTest(lastState.data))
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
this._testStates.clear()
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
this.emit(event.all.result, Container.result())
|
|
556
|
+
event.dispatcher.emit(event.workers.result, Container.result())
|
|
557
|
+
this.emit('end') // internal event
|
|
475
558
|
}
|
|
476
559
|
|
|
477
560
|
printResults() {
|
|
478
|
-
|
|
479
|
-
|
|
561
|
+
const result = Container.result()
|
|
562
|
+
result.finish()
|
|
480
563
|
|
|
481
564
|
// Reset process for logs in main thread
|
|
482
|
-
output.process(null)
|
|
483
|
-
output.print()
|
|
565
|
+
output.process(null)
|
|
566
|
+
output.print()
|
|
484
567
|
|
|
485
|
-
this.failuresLog =
|
|
568
|
+
this.failuresLog = result.failures
|
|
486
569
|
.filter(log => log.length && typeof log[1] === 'number')
|
|
487
570
|
// mocha/lib/reporters/base.js
|
|
488
|
-
.map(([format, num, title, message, stack], i) => [format, i + 1, title, message, stack])
|
|
571
|
+
.map(([format, num, title, message, stack], i) => [format, i + 1, title, message, stack])
|
|
489
572
|
|
|
490
573
|
if (this.failuresLog.length) {
|
|
491
|
-
output.print()
|
|
492
|
-
output.print('-- FAILURES:')
|
|
493
|
-
this.failuresLog.forEach(log => output.print(...log))
|
|
574
|
+
output.print()
|
|
575
|
+
output.print('-- FAILURES:')
|
|
576
|
+
this.failuresLog.forEach(log => output.print(...log))
|
|
494
577
|
}
|
|
495
578
|
|
|
496
|
-
output.result(
|
|
497
|
-
|
|
579
|
+
output.result(result.stats?.passes || 0, result.stats?.failures || 0, result.stats?.pending || 0, ms(result.duration), result.stats?.failedHooks || 0)
|
|
580
|
+
|
|
581
|
+
process.env.RUNS_WITH_WORKERS = 'false'
|
|
498
582
|
}
|
|
499
583
|
}
|
|
500
584
|
|
|
501
|
-
|
|
585
|
+
export default Workers
|