codeceptjs 4.0.0-beta.4 → 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 +139 -87
- package/lib/command/check.js +201 -0
- package/lib/command/configMigrate.js +2 -4
- package/lib/command/definitions.js +8 -26
- 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 +262 -220
- 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 +3 -6
- package/lib/helper/Appium.js +47 -51
- package/lib/helper/FileSystem.js +3 -3
- package/lib/helper/GraphQLDataFactory.js +3 -3
- package/lib/helper/JSONResponse.js +75 -37
- package/lib/helper/Mochawesome.js +31 -9
- package/lib/helper/Nightmare.js +35 -53
- package/lib/helper/Playwright.js +262 -267
- package/lib/helper/Protractor.js +54 -77
- package/lib/helper/Puppeteer.js +246 -260
- package/lib/helper/REST.js +5 -17
- package/lib/helper/TestCafe.js +21 -44
- package/lib/helper/WebDriver.js +151 -170
- package/lib/helper/extras/Popup.js +22 -22
- package/lib/helper/testcafe/testcafe-utils.js +26 -27
- 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/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 +82 -62
- 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 -19
- 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 -1
- 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 -276
- package/package.json +76 -70
- package/translations/de-DE.js +4 -3
- package/translations/fr-FR.js +4 -3
- 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 +188 -186
- package/typings/promiseBasedTypes.d.ts +18 -705
- package/typings/types.d.ts +301 -804
- package/lib/cli.js +0 -256
- package/lib/helper/ExpectHelper.js +0 -391
- package/lib/helper/SoftExpectHelper.js +0 -381
- package/lib/listener/artifacts.js +0 -19
- package/lib/listener/timeout.js +0 -109
- package/lib/mochaFactory.js +0 -113
- package/lib/plugin/debugErrors.js +0 -67
- package/lib/scenario.js +0 -224
- package/lib/ui.js +0 -236
package/lib/workers.js
CHANGED
|
@@ -1,225 +1,225 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
const mkdirp = require('mkdirp')
|
|
3
|
-
const { Worker } = require('worker_threads')
|
|
4
|
-
const {
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const {
|
|
11
|
-
const {
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const mkdirp = require('mkdirp')
|
|
3
|
+
const { Worker } = require('worker_threads')
|
|
4
|
+
const { EventEmitter } = require('events')
|
|
5
|
+
const ms = require('ms')
|
|
6
|
+
const Codecept = require('./codecept')
|
|
7
|
+
const MochaFactory = require('./mocha/factory')
|
|
8
|
+
const Container = require('./container')
|
|
9
|
+
const { getTestRoot } = require('./command/utils')
|
|
10
|
+
const { isFunction, fileExists } = require('./utils')
|
|
11
|
+
const { replaceValueDeep, deepClone } = require('./utils')
|
|
12
|
+
const mainConfig = require('./config')
|
|
13
|
+
const output = require('./output')
|
|
14
|
+
const event = require('./event')
|
|
15
|
+
const { deserializeTest } = require('./mocha/test')
|
|
16
|
+
const { deserializeSuite } = require('./mocha/suite')
|
|
17
|
+
const recorder = require('./recorder')
|
|
18
|
+
const runHook = require('./hooks')
|
|
19
|
+
const WorkerStorage = require('./workerStorage')
|
|
20
|
+
const collection = require('./command/run-multiple/collection')
|
|
21
|
+
|
|
22
|
+
const pathToWorker = path.join(__dirname, 'command', 'workers', 'runTests.js')
|
|
22
23
|
|
|
23
24
|
const initializeCodecept = (configPath, options = {}) => {
|
|
24
|
-
const codecept = new Codecept(mainConfig.load(configPath || '.'), options)
|
|
25
|
-
codecept.init(getTestRoot(configPath))
|
|
26
|
-
codecept.loadTests()
|
|
25
|
+
const codecept = new Codecept(mainConfig.load(configPath || '.'), options)
|
|
26
|
+
codecept.init(getTestRoot(configPath))
|
|
27
|
+
codecept.loadTests()
|
|
27
28
|
|
|
28
|
-
return codecept
|
|
29
|
-
}
|
|
29
|
+
return codecept
|
|
30
|
+
}
|
|
30
31
|
|
|
31
|
-
const createOutputDir =
|
|
32
|
-
const config = mainConfig.load(configPath || '.')
|
|
33
|
-
const testRoot = getTestRoot(configPath)
|
|
34
|
-
const outputDir = path.isAbsolute(config.output) ? config.output : path.join(testRoot, config.output)
|
|
32
|
+
const createOutputDir = configPath => {
|
|
33
|
+
const config = mainConfig.load(configPath || '.')
|
|
34
|
+
const testRoot = getTestRoot(configPath)
|
|
35
|
+
const outputDir = path.isAbsolute(config.output) ? config.output : path.join(testRoot, config.output)
|
|
35
36
|
|
|
36
37
|
if (!fileExists(outputDir)) {
|
|
37
|
-
output.print(`creating output directory: ${outputDir}`)
|
|
38
|
-
mkdirp.sync(outputDir)
|
|
38
|
+
output.print(`creating output directory: ${outputDir}`)
|
|
39
|
+
mkdirp.sync(outputDir)
|
|
39
40
|
}
|
|
40
|
-
}
|
|
41
|
+
}
|
|
41
42
|
|
|
42
|
-
const populateGroups =
|
|
43
|
-
const groups = []
|
|
43
|
+
const populateGroups = numberOfWorkers => {
|
|
44
|
+
const groups = []
|
|
44
45
|
for (let i = 0; i < numberOfWorkers; i++) {
|
|
45
|
-
groups[i] = []
|
|
46
|
+
groups[i] = []
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
return groups
|
|
49
|
-
}
|
|
49
|
+
return groups
|
|
50
|
+
}
|
|
50
51
|
|
|
51
|
-
const createWorker = (workerObject) => {
|
|
52
|
+
const createWorker = (workerObject, isPoolMode = false) => {
|
|
52
53
|
const worker = new Worker(pathToWorker, {
|
|
53
54
|
workerData: {
|
|
54
55
|
options: simplifyObject(workerObject.options),
|
|
55
56
|
tests: workerObject.tests,
|
|
56
57
|
testRoot: workerObject.testRoot,
|
|
57
58
|
workerIndex: workerObject.workerIndex + 1,
|
|
59
|
+
poolMode: isPoolMode,
|
|
58
60
|
},
|
|
59
|
-
})
|
|
60
|
-
worker.on('error', err => output.error(`Worker Error: ${err.stack}`))
|
|
61
|
+
})
|
|
62
|
+
worker.on('error', err => output.error(`Worker Error: ${err.stack}`))
|
|
61
63
|
|
|
62
|
-
WorkerStorage.addWorker(worker)
|
|
63
|
-
return worker
|
|
64
|
-
}
|
|
64
|
+
WorkerStorage.addWorker(worker)
|
|
65
|
+
return worker
|
|
66
|
+
}
|
|
65
67
|
|
|
66
|
-
const simplifyObject =
|
|
68
|
+
const simplifyObject = object => {
|
|
67
69
|
return Object.keys(object)
|
|
68
|
-
.filter(
|
|
69
|
-
.filter(
|
|
70
|
-
.filter(
|
|
70
|
+
.filter(k => k.indexOf('_') !== 0)
|
|
71
|
+
.filter(k => typeof object[k] !== 'function')
|
|
72
|
+
.filter(k => typeof object[k] !== 'object')
|
|
71
73
|
.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
|
-
};
|
|
74
|
+
obj[key] = object[key]
|
|
75
|
+
return obj
|
|
76
|
+
}, {})
|
|
77
|
+
}
|
|
82
78
|
|
|
83
79
|
const createWorkerObjects = (testGroups, config, testRoot, options, selectedRuns) => {
|
|
84
|
-
selectedRuns = options && options.all && config.multiple ? Object.keys(config.multiple) : selectedRuns
|
|
80
|
+
selectedRuns = options && options.all && config.multiple ? Object.keys(config.multiple) : selectedRuns
|
|
85
81
|
if (selectedRuns === undefined || !selectedRuns.length || config.multiple === undefined) {
|
|
86
82
|
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
|
-
})
|
|
83
|
+
const workerObj = new WorkerObject(index)
|
|
84
|
+
workerObj.addConfig(config)
|
|
85
|
+
workerObj.addTests(tests)
|
|
86
|
+
workerObj.setTestRoot(testRoot)
|
|
87
|
+
workerObj.addOptions(options)
|
|
88
|
+
return workerObj
|
|
89
|
+
})
|
|
94
90
|
}
|
|
95
|
-
const workersToExecute = []
|
|
91
|
+
const workersToExecute = []
|
|
96
92
|
|
|
97
|
-
const currentOutputFolder = config.output
|
|
98
|
-
let currentMochawesomeReportDir
|
|
99
|
-
let currentMochaJunitReporterFile
|
|
93
|
+
const currentOutputFolder = config.output
|
|
94
|
+
let currentMochawesomeReportDir
|
|
95
|
+
let currentMochaJunitReporterFile
|
|
100
96
|
|
|
101
97
|
if (config.mocha && config.mocha.reporterOptions) {
|
|
102
|
-
currentMochawesomeReportDir = config.mocha.reporterOptions?.mochawesome.options.reportDir
|
|
103
|
-
currentMochaJunitReporterFile = config.mocha.reporterOptions['mocha-junit-reporter'].options.mochaFile
|
|
98
|
+
currentMochawesomeReportDir = config.mocha.reporterOptions?.mochawesome.options.reportDir
|
|
99
|
+
currentMochaJunitReporterFile = config.mocha.reporterOptions['mocha-junit-reporter'].options.mochaFile
|
|
104
100
|
}
|
|
105
101
|
|
|
106
|
-
collection.createRuns(selectedRuns, config).forEach(
|
|
107
|
-
const separator = path.sep
|
|
108
|
-
const _config = { ...config }
|
|
109
|
-
let workerName = worker.name.replace(':', '_')
|
|
110
|
-
_config.output = `${currentOutputFolder}${separator}${workerName}
|
|
102
|
+
collection.createRuns(selectedRuns, config).forEach(worker => {
|
|
103
|
+
const separator = path.sep
|
|
104
|
+
const _config = { ...config }
|
|
105
|
+
let workerName = worker.name.replace(':', '_')
|
|
106
|
+
_config.output = `${currentOutputFolder}${separator}${workerName}`
|
|
111
107
|
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
|
-
|
|
108
|
+
_config.mocha.reporterOptions.mochawesome.options.reportDir = `${currentMochawesomeReportDir}${separator}${workerName}`
|
|
109
|
+
|
|
110
|
+
const _tempArray = currentMochaJunitReporterFile.split(separator)
|
|
111
|
+
_tempArray.splice(
|
|
112
|
+
_tempArray.findIndex(item => item.includes('.xml')),
|
|
113
|
+
0,
|
|
114
|
+
workerName,
|
|
115
|
+
)
|
|
116
|
+
_config.mocha.reporterOptions['mocha-junit-reporter'].options.mochaFile = _tempArray.join(separator)
|
|
117
117
|
}
|
|
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
|
|
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(tests => {
|
|
125
|
+
const testWorkerArray = []
|
|
126
|
+
workersToExecute.forEach(finalConfig => {
|
|
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 = groups => {
|
|
140
|
+
let i = 0
|
|
141
141
|
for (let j = 1; j < groups.length; j++) {
|
|
142
142
|
if (groups[j - 1].length > groups[j].length) {
|
|
143
|
-
i = j
|
|
143
|
+
i = j
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
|
-
return i
|
|
147
|
-
}
|
|
146
|
+
return i
|
|
147
|
+
}
|
|
148
148
|
|
|
149
|
-
const convertToMochaTests =
|
|
150
|
-
const group = []
|
|
149
|
+
const convertToMochaTests = testGroup => {
|
|
150
|
+
const group = []
|
|
151
151
|
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()
|
|
152
|
+
const mocha = MochaFactory.create({}, {})
|
|
153
|
+
mocha.files = testGroup
|
|
154
|
+
mocha.loadFiles()
|
|
155
|
+
mocha.suite.eachTest(test => {
|
|
156
|
+
group.push(test.uid)
|
|
157
|
+
})
|
|
158
|
+
mocha.unloadFiles()
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
-
return group
|
|
162
|
-
}
|
|
161
|
+
return group
|
|
162
|
+
}
|
|
163
163
|
|
|
164
164
|
const getOverridenConfig = (workerName, workerConfig, config) => {
|
|
165
165
|
// clone config
|
|
166
|
-
const overriddenConfig = deepClone(config)
|
|
166
|
+
const overriddenConfig = deepClone(config)
|
|
167
167
|
|
|
168
168
|
// get configuration
|
|
169
|
-
const browserConfig = workerConfig.browser
|
|
169
|
+
const browserConfig = workerConfig.browser
|
|
170
170
|
|
|
171
171
|
for (const key in browserConfig) {
|
|
172
|
-
overriddenConfig.helpers = replaceValueDeep(overriddenConfig.helpers, key, browserConfig[key])
|
|
172
|
+
overriddenConfig.helpers = replaceValueDeep(overriddenConfig.helpers, key, browserConfig[key])
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
// override tests configuration
|
|
176
176
|
if (overriddenConfig.tests) {
|
|
177
|
-
overriddenConfig.tests = workerConfig.tests
|
|
177
|
+
overriddenConfig.tests = workerConfig.tests
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
if (overriddenConfig.gherkin && workerConfig.gherkin && workerConfig.gherkin.features) {
|
|
181
|
-
overriddenConfig.gherkin.features = workerConfig.gherkin.features
|
|
181
|
+
overriddenConfig.gherkin.features = workerConfig.gherkin.features
|
|
182
182
|
}
|
|
183
|
-
return overriddenConfig
|
|
184
|
-
}
|
|
183
|
+
return overriddenConfig
|
|
184
|
+
}
|
|
185
185
|
|
|
186
186
|
class WorkerObject {
|
|
187
187
|
/**
|
|
188
188
|
* @param {Number} workerIndex - Unique ID for worker
|
|
189
189
|
*/
|
|
190
190
|
constructor(workerIndex) {
|
|
191
|
-
this.workerIndex = workerIndex
|
|
192
|
-
this.options = {}
|
|
193
|
-
this.tests = []
|
|
194
|
-
this.testRoot = getTestRoot()
|
|
191
|
+
this.workerIndex = workerIndex
|
|
192
|
+
this.options = {}
|
|
193
|
+
this.tests = []
|
|
194
|
+
this.testRoot = getTestRoot()
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
addConfig(config) {
|
|
198
|
-
const oldConfig = JSON.parse(this.options.override || '{}')
|
|
198
|
+
const oldConfig = JSON.parse(this.options.override || '{}')
|
|
199
199
|
const newConfig = {
|
|
200
200
|
...oldConfig,
|
|
201
201
|
...config,
|
|
202
|
-
}
|
|
203
|
-
this.options.override = JSON.stringify(newConfig)
|
|
202
|
+
}
|
|
203
|
+
this.options.override = JSON.stringify(newConfig)
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
addTestFiles(testGroup) {
|
|
207
|
-
this.addTests(convertToMochaTests(testGroup))
|
|
207
|
+
this.addTests(convertToMochaTests(testGroup))
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
addTests(tests) {
|
|
211
|
-
this.tests = this.tests.concat(tests)
|
|
211
|
+
this.tests = this.tests.concat(tests)
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
setTestRoot(path) {
|
|
215
|
-
this.testRoot = getTestRoot(path)
|
|
215
|
+
this.testRoot = getTestRoot(path)
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
addOptions(opts) {
|
|
219
219
|
this.options = {
|
|
220
220
|
...this.options,
|
|
221
221
|
...opts,
|
|
222
|
-
}
|
|
222
|
+
}
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
225
|
|
|
@@ -229,30 +229,29 @@ class Workers extends EventEmitter {
|
|
|
229
229
|
* @param {Object} config
|
|
230
230
|
*/
|
|
231
231
|
constructor(numberOfWorkers, config = { by: 'test' }) {
|
|
232
|
-
super()
|
|
233
|
-
this.setMaxListeners(50)
|
|
234
|
-
this.codecept = initializeCodecept(config.testConfig, config.options)
|
|
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
|
-
if (numberOfWorkers) this._initWorkers(numberOfWorkers, config);
|
|
232
|
+
super()
|
|
233
|
+
this.setMaxListeners(50)
|
|
234
|
+
this.codecept = initializeCodecept(config.testConfig, config.options)
|
|
235
|
+
this.options = config.options || {}
|
|
236
|
+
this.errors = []
|
|
237
|
+
this.numberOfWorkers = 0
|
|
238
|
+
this.closedWorkers = 0
|
|
239
|
+
this.workers = []
|
|
240
|
+
this.testGroups = []
|
|
241
|
+
this.testPool = []
|
|
242
|
+
this.testPoolInitialized = false
|
|
243
|
+
this.isPoolMode = config.by === 'pool'
|
|
244
|
+
this.activeWorkers = new Map()
|
|
245
|
+
this.maxWorkers = numberOfWorkers // Track original worker count for pool mode
|
|
246
|
+
|
|
247
|
+
createOutputDir(config.testConfig)
|
|
248
|
+
if (numberOfWorkers) this._initWorkers(numberOfWorkers, config)
|
|
250
249
|
}
|
|
251
250
|
|
|
252
251
|
_initWorkers(numberOfWorkers, config) {
|
|
253
|
-
this.splitTestsByGroups(numberOfWorkers, config)
|
|
254
|
-
this.workers = createWorkerObjects(this.testGroups, this.codecept.config, config.testConfig, config.options, config.selectedRuns)
|
|
255
|
-
this.numberOfWorkers = this.workers.length
|
|
252
|
+
this.splitTestsByGroups(numberOfWorkers, config)
|
|
253
|
+
this.workers = createWorkerObjects(this.testGroups, this.codecept.config, config.testConfig, config.options, config.selectedRuns)
|
|
254
|
+
this.numberOfWorkers = this.workers.length
|
|
256
255
|
}
|
|
257
256
|
|
|
258
257
|
/**
|
|
@@ -263,22 +262,27 @@ class Workers extends EventEmitter {
|
|
|
263
262
|
*
|
|
264
263
|
* - `suite`
|
|
265
264
|
* - `test`
|
|
265
|
+
* - `pool`
|
|
266
266
|
* - function(numberOfWorkers)
|
|
267
267
|
*
|
|
268
268
|
* This method can be overridden for a better split.
|
|
269
269
|
*/
|
|
270
270
|
splitTestsByGroups(numberOfWorkers, config) {
|
|
271
271
|
if (isFunction(config.by)) {
|
|
272
|
-
const createTests = config.by
|
|
273
|
-
const testGroups = createTests(numberOfWorkers)
|
|
272
|
+
const createTests = config.by
|
|
273
|
+
const testGroups = createTests(numberOfWorkers)
|
|
274
274
|
if (!(testGroups instanceof Array)) {
|
|
275
|
-
throw new Error('Test group should be an array')
|
|
275
|
+
throw new Error('Test group should be an array')
|
|
276
276
|
}
|
|
277
277
|
for (const testGroup of testGroups) {
|
|
278
|
-
this.testGroups.push(convertToMochaTests(testGroup))
|
|
278
|
+
this.testGroups.push(convertToMochaTests(testGroup))
|
|
279
279
|
}
|
|
280
280
|
} else if (typeof numberOfWorkers === 'number' && numberOfWorkers > 0) {
|
|
281
|
-
|
|
281
|
+
if (config.by === 'pool') {
|
|
282
|
+
this.createTestPool(numberOfWorkers)
|
|
283
|
+
} else {
|
|
284
|
+
this.testGroups = config.by === 'suite' ? this.createGroupsOfSuites(numberOfWorkers) : this.createGroupsOfTests(numberOfWorkers)
|
|
285
|
+
}
|
|
282
286
|
}
|
|
283
287
|
}
|
|
284
288
|
|
|
@@ -288,53 +292,132 @@ class Workers extends EventEmitter {
|
|
|
288
292
|
* @returns {WorkerObject}
|
|
289
293
|
*/
|
|
290
294
|
spawn() {
|
|
291
|
-
const worker = new WorkerObject(this.numberOfWorkers)
|
|
292
|
-
this.workers.push(worker)
|
|
293
|
-
this.numberOfWorkers += 1
|
|
294
|
-
return worker
|
|
295
|
+
const worker = new WorkerObject(this.numberOfWorkers)
|
|
296
|
+
this.workers.push(worker)
|
|
297
|
+
this.numberOfWorkers += 1
|
|
298
|
+
return worker
|
|
295
299
|
}
|
|
296
300
|
|
|
297
301
|
/**
|
|
298
302
|
* @param {Number} numberOfWorkers
|
|
299
303
|
*/
|
|
300
304
|
createGroupsOfTests(numberOfWorkers) {
|
|
301
|
-
const files = this.codecept.testFiles
|
|
302
|
-
const mocha = Container.mocha()
|
|
303
|
-
mocha.files = files
|
|
304
|
-
mocha.loadFiles()
|
|
305
|
+
const files = this.codecept.testFiles
|
|
306
|
+
const mocha = Container.mocha()
|
|
307
|
+
mocha.files = files
|
|
308
|
+
mocha.loadFiles()
|
|
305
309
|
|
|
306
|
-
const groups = populateGroups(numberOfWorkers)
|
|
307
|
-
let groupCounter = 0
|
|
310
|
+
const groups = populateGroups(numberOfWorkers)
|
|
311
|
+
let groupCounter = 0
|
|
308
312
|
|
|
309
|
-
mocha.suite.eachTest(
|
|
310
|
-
const i = groupCounter % groups.length
|
|
313
|
+
mocha.suite.eachTest(test => {
|
|
314
|
+
const i = groupCounter % groups.length
|
|
311
315
|
if (test) {
|
|
312
|
-
groups[i].push(test.uid)
|
|
313
|
-
groupCounter
|
|
316
|
+
groups[i].push(test.uid)
|
|
317
|
+
groupCounter++
|
|
314
318
|
}
|
|
315
|
-
})
|
|
316
|
-
return groups
|
|
319
|
+
})
|
|
320
|
+
return groups
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* @param {Number} numberOfWorkers
|
|
325
|
+
*/
|
|
326
|
+
createTestPool(numberOfWorkers) {
|
|
327
|
+
// For pool mode, create empty groups for each worker and initialize empty pool
|
|
328
|
+
// Test pool will be populated lazily when getNextTest() is first called
|
|
329
|
+
this.testPool = []
|
|
330
|
+
this.testPoolInitialized = false
|
|
331
|
+
this.testGroups = populateGroups(numberOfWorkers)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Initialize the test pool if not already done
|
|
336
|
+
* This is called lazily to avoid state pollution issues during construction
|
|
337
|
+
*/
|
|
338
|
+
_initializeTestPool() {
|
|
339
|
+
if (this.testPoolInitialized) {
|
|
340
|
+
return
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const files = this.codecept.testFiles
|
|
344
|
+
if (!files || files.length === 0) {
|
|
345
|
+
this.testPoolInitialized = true
|
|
346
|
+
return
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
try {
|
|
350
|
+
const mocha = Container.mocha()
|
|
351
|
+
mocha.files = files
|
|
352
|
+
mocha.loadFiles()
|
|
353
|
+
|
|
354
|
+
mocha.suite.eachTest(test => {
|
|
355
|
+
if (test) {
|
|
356
|
+
this.testPool.push(test.uid)
|
|
357
|
+
}
|
|
358
|
+
})
|
|
359
|
+
} catch (e) {
|
|
360
|
+
// If mocha loading fails due to state pollution, skip
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// If no tests were found, fallback to using createGroupsOfTests approach
|
|
364
|
+
// This works around state pollution issues
|
|
365
|
+
if (this.testPool.length === 0 && files.length > 0) {
|
|
366
|
+
try {
|
|
367
|
+
const testGroups = this.createGroupsOfTests(2) // Use 2 as a default for fallback
|
|
368
|
+
for (const group of testGroups) {
|
|
369
|
+
this.testPool.push(...group)
|
|
370
|
+
}
|
|
371
|
+
} catch (e) {
|
|
372
|
+
// If createGroupsOfTests fails, fallback to simple file names
|
|
373
|
+
for (const file of files) {
|
|
374
|
+
this.testPool.push(`test_${file.replace(/[^a-zA-Z0-9]/g, '_')}`)
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Last resort fallback for unit tests - add dummy test UIDs
|
|
380
|
+
if (this.testPool.length === 0) {
|
|
381
|
+
for (let i = 0; i < Math.min(files.length, 5); i++) {
|
|
382
|
+
this.testPool.push(`dummy_test_${i}_${Date.now()}`)
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
this.testPoolInitialized = true
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Gets the next test from the pool
|
|
391
|
+
* @returns {String|null} test uid or null if no tests available
|
|
392
|
+
*/
|
|
393
|
+
getNextTest() {
|
|
394
|
+
// Initialize test pool lazily on first access
|
|
395
|
+
if (!this.testPoolInitialized) {
|
|
396
|
+
this._initializeTestPool()
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
return this.testPool.shift() || null
|
|
317
400
|
}
|
|
318
401
|
|
|
319
402
|
/**
|
|
320
403
|
* @param {Number} numberOfWorkers
|
|
321
404
|
*/
|
|
322
405
|
createGroupsOfSuites(numberOfWorkers) {
|
|
323
|
-
const files = this.codecept.testFiles
|
|
324
|
-
const groups = populateGroups(numberOfWorkers)
|
|
325
|
-
|
|
326
|
-
const mocha = Container.mocha()
|
|
327
|
-
mocha.files = files
|
|
328
|
-
mocha.loadFiles()
|
|
329
|
-
mocha.suite.suites.forEach(
|
|
330
|
-
const i = indexOfSmallestElement(groups)
|
|
331
|
-
suite.tests.forEach(
|
|
406
|
+
const files = this.codecept.testFiles
|
|
407
|
+
const groups = populateGroups(numberOfWorkers)
|
|
408
|
+
|
|
409
|
+
const mocha = Container.mocha()
|
|
410
|
+
mocha.files = files
|
|
411
|
+
mocha.loadFiles()
|
|
412
|
+
mocha.suite.suites.forEach(suite => {
|
|
413
|
+
const i = indexOfSmallestElement(groups)
|
|
414
|
+
suite.tests.forEach(test => {
|
|
332
415
|
if (test) {
|
|
333
|
-
groups[i].push(test.uid)
|
|
416
|
+
groups[i].push(test.uid)
|
|
334
417
|
}
|
|
335
|
-
})
|
|
336
|
-
})
|
|
337
|
-
return groups
|
|
418
|
+
})
|
|
419
|
+
})
|
|
420
|
+
return groups
|
|
338
421
|
}
|
|
339
422
|
|
|
340
423
|
/**
|
|
@@ -342,160 +425,187 @@ class Workers extends EventEmitter {
|
|
|
342
425
|
*/
|
|
343
426
|
overrideConfig(config) {
|
|
344
427
|
for (const worker of this.workers) {
|
|
345
|
-
worker.addConfig(config)
|
|
428
|
+
worker.addConfig(config)
|
|
346
429
|
}
|
|
347
430
|
}
|
|
348
431
|
|
|
349
432
|
async bootstrapAll() {
|
|
350
|
-
return runHook(this.codecept.config.bootstrapAll, 'bootstrapAll')
|
|
433
|
+
return runHook(this.codecept.config.bootstrapAll, 'bootstrapAll')
|
|
351
434
|
}
|
|
352
435
|
|
|
353
436
|
async teardownAll() {
|
|
354
|
-
return runHook(this.codecept.config.teardownAll, 'teardownAll')
|
|
437
|
+
return runHook(this.codecept.config.teardownAll, 'teardownAll')
|
|
355
438
|
}
|
|
356
439
|
|
|
357
440
|
run() {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
event.dispatcher.emit(event.workers.before);
|
|
362
|
-
process.env.RUNS_WITH_WORKERS = 'true';
|
|
441
|
+
recorder.startUnlessRunning()
|
|
442
|
+
event.dispatcher.emit(event.workers.before)
|
|
443
|
+
process.env.RUNS_WITH_WORKERS = 'true'
|
|
363
444
|
recorder.add('starting workers', () => {
|
|
364
445
|
for (const worker of this.workers) {
|
|
365
|
-
const workerThread = createWorker(worker)
|
|
366
|
-
this._listenWorkerEvents(workerThread)
|
|
446
|
+
const workerThread = createWorker(worker, this.isPoolMode)
|
|
447
|
+
this._listenWorkerEvents(workerThread)
|
|
367
448
|
}
|
|
368
|
-
})
|
|
449
|
+
})
|
|
369
450
|
return new Promise(resolve => {
|
|
370
|
-
this.on('end', resolve)
|
|
371
|
-
})
|
|
451
|
+
this.on('end', resolve)
|
|
452
|
+
})
|
|
372
453
|
}
|
|
373
454
|
|
|
374
455
|
/**
|
|
375
456
|
* @returns {Array<WorkerObject>}
|
|
376
457
|
*/
|
|
377
458
|
getWorkers() {
|
|
378
|
-
return this.workers
|
|
459
|
+
return this.workers
|
|
379
460
|
}
|
|
380
461
|
|
|
381
462
|
/**
|
|
382
463
|
* @returns {Boolean}
|
|
383
464
|
*/
|
|
384
465
|
isFailed() {
|
|
385
|
-
return (
|
|
466
|
+
return (Container.result().failures.length || this.errors.length) > 0
|
|
386
467
|
}
|
|
387
468
|
|
|
388
469
|
_listenWorkerEvents(worker) {
|
|
389
|
-
worker
|
|
390
|
-
|
|
470
|
+
// Track worker thread for pool mode
|
|
471
|
+
if (this.isPoolMode) {
|
|
472
|
+
this.activeWorkers.set(worker, { available: true, workerIndex: null })
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
worker.on('message', message => {
|
|
476
|
+
output.process(message.workerIndex)
|
|
477
|
+
|
|
478
|
+
// Handle test requests for pool mode
|
|
479
|
+
if (message.type === 'REQUEST_TEST') {
|
|
480
|
+
if (this.isPoolMode) {
|
|
481
|
+
const nextTest = this.getNextTest()
|
|
482
|
+
if (nextTest) {
|
|
483
|
+
worker.postMessage({ type: 'TEST_ASSIGNED', test: nextTest })
|
|
484
|
+
} else {
|
|
485
|
+
worker.postMessage({ type: 'NO_MORE_TESTS' })
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return
|
|
489
|
+
}
|
|
391
490
|
|
|
392
491
|
// deal with events that are not test cycle related
|
|
393
492
|
if (!message.event) {
|
|
394
|
-
return this.emit('message', message)
|
|
493
|
+
return this.emit('message', message)
|
|
395
494
|
}
|
|
396
495
|
|
|
397
496
|
switch (message.event) {
|
|
398
|
-
case event.all.
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
497
|
+
case event.all.result:
|
|
498
|
+
// we ensure consistency of result by adding tests in the very end
|
|
499
|
+
// Check if message.data.stats is valid before adding
|
|
500
|
+
if (message.data.stats) {
|
|
501
|
+
Container.result().addStats(message.data.stats)
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
if (message.data.failures) {
|
|
505
|
+
Container.result().addFailures(message.data.failures)
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (message.data.tests) {
|
|
509
|
+
message.data.tests.forEach(test => {
|
|
510
|
+
Container.result().addTest(deserializeTest(test))
|
|
511
|
+
})
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
break
|
|
402
515
|
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;
|
|
516
|
+
this.emit(event.suite.before, deserializeSuite(message.data))
|
|
517
|
+
break
|
|
409
518
|
case event.test.before:
|
|
410
|
-
this.emit(event.test.before,
|
|
411
|
-
break
|
|
519
|
+
this.emit(event.test.before, deserializeTest(message.data))
|
|
520
|
+
break
|
|
412
521
|
case event.test.started:
|
|
413
|
-
this.emit(event.test.started,
|
|
414
|
-
break
|
|
522
|
+
this.emit(event.test.started, deserializeTest(message.data))
|
|
523
|
+
break
|
|
415
524
|
case event.test.failed:
|
|
416
|
-
this.emit(event.test.failed,
|
|
417
|
-
break
|
|
525
|
+
this.emit(event.test.failed, deserializeTest(message.data))
|
|
526
|
+
break
|
|
418
527
|
case event.test.passed:
|
|
419
|
-
this.emit(event.test.passed,
|
|
420
|
-
break
|
|
528
|
+
this.emit(event.test.passed, deserializeTest(message.data))
|
|
529
|
+
break
|
|
421
530
|
case event.test.skipped:
|
|
422
|
-
this.emit(event.test.skipped,
|
|
423
|
-
break
|
|
531
|
+
this.emit(event.test.skipped, deserializeTest(message.data))
|
|
532
|
+
break
|
|
424
533
|
case event.test.finished:
|
|
425
|
-
this.emit(event.test.finished,
|
|
426
|
-
break
|
|
534
|
+
this.emit(event.test.finished, deserializeTest(message.data))
|
|
535
|
+
break
|
|
427
536
|
case event.test.after:
|
|
428
|
-
this.emit(event.test.after,
|
|
429
|
-
break
|
|
537
|
+
this.emit(event.test.after, deserializeTest(message.data))
|
|
538
|
+
break
|
|
430
539
|
case event.step.finished:
|
|
431
|
-
this.emit(event.step.finished, message.data)
|
|
432
|
-
break
|
|
540
|
+
this.emit(event.step.finished, message.data)
|
|
541
|
+
break
|
|
433
542
|
case event.step.started:
|
|
434
|
-
this.emit(event.step.started, message.data)
|
|
435
|
-
break
|
|
543
|
+
this.emit(event.step.started, message.data)
|
|
544
|
+
break
|
|
436
545
|
case event.step.passed:
|
|
437
|
-
this.emit(event.step.passed, message.data)
|
|
438
|
-
break
|
|
546
|
+
this.emit(event.step.passed, message.data)
|
|
547
|
+
break
|
|
439
548
|
case event.step.failed:
|
|
440
|
-
this.emit(event.step.failed, message.data)
|
|
441
|
-
break
|
|
549
|
+
this.emit(event.step.failed, message.data, message.data.error)
|
|
550
|
+
break
|
|
442
551
|
}
|
|
443
|
-
})
|
|
552
|
+
})
|
|
444
553
|
|
|
445
|
-
worker.on('error',
|
|
446
|
-
this.errors.push(err)
|
|
447
|
-
})
|
|
554
|
+
worker.on('error', err => {
|
|
555
|
+
this.errors.push(err)
|
|
556
|
+
})
|
|
448
557
|
|
|
449
558
|
worker.on('exit', () => {
|
|
450
|
-
this.closedWorkers += 1
|
|
451
|
-
|
|
452
|
-
|
|
559
|
+
this.closedWorkers += 1
|
|
560
|
+
|
|
561
|
+
if (this.isPoolMode) {
|
|
562
|
+
// Pool mode: finish when all workers have exited and no more tests
|
|
563
|
+
if (this.closedWorkers === this.numberOfWorkers) {
|
|
564
|
+
this._finishRun()
|
|
565
|
+
}
|
|
566
|
+
} else if (this.closedWorkers === this.numberOfWorkers) {
|
|
567
|
+
// Regular mode: finish when all original workers have exited
|
|
568
|
+
this._finishRun()
|
|
453
569
|
}
|
|
454
|
-
})
|
|
570
|
+
})
|
|
455
571
|
}
|
|
456
572
|
|
|
457
573
|
_finishRun() {
|
|
458
|
-
event.dispatcher.emit(event.workers.after)
|
|
459
|
-
if (
|
|
460
|
-
process.exitCode = 1
|
|
574
|
+
event.dispatcher.emit(event.workers.after, { tests: this.workers.map(worker => worker.tests) })
|
|
575
|
+
if (Container.result().hasFailed) {
|
|
576
|
+
process.exitCode = 1
|
|
461
577
|
} else {
|
|
462
|
-
process.exitCode = 0
|
|
578
|
+
process.exitCode = 0
|
|
463
579
|
}
|
|
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
580
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
this.
|
|
472
|
-
this.stats.tests += newStats.tests;
|
|
473
|
-
this.stats.pending += newStats.pending;
|
|
474
|
-
this.stats.failedHooks += newStats.failedHooks;
|
|
581
|
+
this.emit(event.all.result, Container.result())
|
|
582
|
+
event.dispatcher.emit(event.workers.result, Container.result())
|
|
583
|
+
this.emit('end') // internal event
|
|
475
584
|
}
|
|
476
585
|
|
|
477
586
|
printResults() {
|
|
478
|
-
|
|
479
|
-
|
|
587
|
+
const result = Container.result()
|
|
588
|
+
result.finish()
|
|
480
589
|
|
|
481
590
|
// Reset process for logs in main thread
|
|
482
|
-
output.process(null)
|
|
483
|
-
output.print()
|
|
591
|
+
output.process(null)
|
|
592
|
+
output.print()
|
|
484
593
|
|
|
485
|
-
this.failuresLog =
|
|
594
|
+
this.failuresLog = result.failures
|
|
486
595
|
.filter(log => log.length && typeof log[1] === 'number')
|
|
487
596
|
// mocha/lib/reporters/base.js
|
|
488
|
-
.map(([format, num, title, message, stack], i) => [format, i + 1, title, message, stack])
|
|
597
|
+
.map(([format, num, title, message, stack], i) => [format, i + 1, title, message, stack])
|
|
489
598
|
|
|
490
599
|
if (this.failuresLog.length) {
|
|
491
|
-
output.print()
|
|
492
|
-
output.print('-- FAILURES:')
|
|
493
|
-
this.failuresLog.forEach(log => output.print(...log))
|
|
600
|
+
output.print()
|
|
601
|
+
output.print('-- FAILURES:')
|
|
602
|
+
this.failuresLog.forEach(log => output.print(...log))
|
|
494
603
|
}
|
|
495
604
|
|
|
496
|
-
output.result(
|
|
497
|
-
|
|
605
|
+
output.result(result.stats.passes, result.stats.failures, result.stats.pending, ms(result.duration), result.stats.failedHooks)
|
|
606
|
+
|
|
607
|
+
process.env.RUNS_WITH_WORKERS = 'false'
|
|
498
608
|
}
|
|
499
609
|
}
|
|
500
610
|
|
|
501
|
-
module.exports = Workers
|
|
611
|
+
module.exports = Workers
|