codeceptjs 4.0.0-beta.3 → 4.0.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +134 -119
- package/bin/codecept.js +12 -2
- package/bin/test-server.js +53 -0
- package/docs/webapi/clearCookie.mustache +1 -1
- package/lib/actor.js +66 -102
- package/lib/ai.js +130 -121
- package/lib/assert/empty.js +3 -5
- package/lib/assert/equal.js +4 -7
- package/lib/assert/include.js +4 -6
- package/lib/assert/throws.js +2 -4
- package/lib/assert/truth.js +2 -2
- package/lib/codecept.js +141 -86
- package/lib/command/check.js +201 -0
- package/lib/command/configMigrate.js +2 -4
- package/lib/command/definitions.js +8 -26
- package/lib/command/dryRun.js +30 -35
- package/lib/command/generate.js +10 -14
- package/lib/command/gherkin/snippets.js +75 -73
- package/lib/command/gherkin/steps.js +1 -1
- package/lib/command/info.js +42 -8
- package/lib/command/init.js +13 -12
- package/lib/command/interactive.js +10 -2
- package/lib/command/list.js +1 -1
- package/lib/command/run-multiple/chunk.js +48 -45
- package/lib/command/run-multiple.js +12 -35
- package/lib/command/run-workers.js +21 -58
- package/lib/command/utils.js +5 -6
- package/lib/command/workers/runTests.js +263 -222
- package/lib/container.js +386 -238
- package/lib/data/context.js +10 -13
- package/lib/data/dataScenarioConfig.js +8 -8
- package/lib/data/dataTableArgument.js +6 -6
- package/lib/data/table.js +5 -11
- package/lib/effects.js +223 -0
- package/lib/element/WebElement.js +327 -0
- package/lib/els.js +158 -0
- package/lib/event.js +21 -17
- package/lib/heal.js +88 -80
- package/lib/helper/AI.js +2 -1
- package/lib/helper/ApiDataFactory.js +4 -7
- package/lib/helper/Appium.js +50 -57
- package/lib/helper/FileSystem.js +3 -3
- package/lib/helper/GraphQLDataFactory.js +4 -4
- package/lib/helper/JSONResponse.js +75 -37
- package/lib/helper/Mochawesome.js +31 -9
- package/lib/helper/Nightmare.js +37 -58
- package/lib/helper/Playwright.js +267 -272
- package/lib/helper/Protractor.js +56 -87
- package/lib/helper/Puppeteer.js +247 -264
- package/lib/helper/REST.js +29 -17
- package/lib/helper/TestCafe.js +22 -47
- package/lib/helper/WebDriver.js +157 -368
- package/lib/helper/extras/PlaywrightPropEngine.js +2 -2
- package/lib/helper/extras/Popup.js +22 -22
- package/lib/helper/network/utils.js +1 -1
- package/lib/helper/testcafe/testcafe-utils.js +27 -28
- package/lib/listener/emptyRun.js +55 -0
- package/lib/listener/exit.js +7 -10
- package/lib/listener/{retry.js → globalRetry.js} +5 -5
- package/lib/listener/globalTimeout.js +165 -0
- package/lib/listener/helpers.js +15 -15
- package/lib/listener/mocha.js +1 -1
- package/lib/listener/result.js +12 -0
- package/lib/listener/retryEnhancer.js +85 -0
- package/lib/listener/steps.js +32 -18
- package/lib/listener/store.js +20 -0
- package/lib/locator.js +1 -1
- package/lib/mocha/asyncWrapper.js +231 -0
- package/lib/{interfaces → mocha}/bdd.js +3 -3
- package/lib/mocha/cli.js +308 -0
- package/lib/mocha/factory.js +104 -0
- package/lib/{interfaces → mocha}/featureConfig.js +32 -12
- package/lib/{interfaces → mocha}/gherkin.js +26 -28
- package/lib/mocha/hooks.js +112 -0
- package/lib/mocha/index.js +12 -0
- package/lib/mocha/inject.js +29 -0
- package/lib/{interfaces → mocha}/scenarioConfig.js +31 -7
- package/lib/mocha/suite.js +82 -0
- package/lib/mocha/test.js +181 -0
- package/lib/mocha/types.d.ts +42 -0
- package/lib/mocha/ui.js +232 -0
- package/lib/output.js +93 -65
- package/lib/pause.js +160 -138
- package/lib/plugin/analyze.js +396 -0
- package/lib/plugin/auth.js +435 -0
- package/lib/plugin/autoDelay.js +8 -8
- package/lib/plugin/autoLogin.js +3 -338
- package/lib/plugin/commentStep.js +6 -1
- package/lib/plugin/coverage.js +10 -22
- package/lib/plugin/customLocator.js +3 -3
- package/lib/plugin/customReporter.js +52 -0
- package/lib/plugin/eachElement.js +1 -1
- package/lib/plugin/fakerTransform.js +1 -1
- package/lib/plugin/heal.js +36 -9
- package/lib/plugin/htmlReporter.js +1947 -0
- package/lib/plugin/pageInfo.js +140 -0
- package/lib/plugin/retryFailedStep.js +17 -18
- package/lib/plugin/retryTo.js +2 -113
- package/lib/plugin/screenshotOnFail.js +17 -58
- package/lib/plugin/selenoid.js +15 -35
- package/lib/plugin/standardActingHelpers.js +4 -1
- package/lib/plugin/stepByStepReport.js +56 -17
- package/lib/plugin/stepTimeout.js +5 -12
- package/lib/plugin/subtitles.js +4 -4
- package/lib/plugin/tryTo.js +3 -102
- package/lib/plugin/wdio.js +8 -10
- package/lib/recorder.js +155 -124
- package/lib/rerun.js +43 -42
- package/lib/result.js +161 -0
- package/lib/secret.js +1 -2
- package/lib/step/base.js +239 -0
- package/lib/step/comment.js +10 -0
- package/lib/step/config.js +50 -0
- package/lib/step/func.js +46 -0
- package/lib/step/helper.js +50 -0
- package/lib/step/meta.js +99 -0
- package/lib/step/record.js +74 -0
- package/lib/step/retry.js +11 -0
- package/lib/step/section.js +55 -0
- package/lib/step.js +21 -332
- package/lib/steps.js +50 -0
- package/lib/store.js +37 -5
- package/lib/template/heal.js +2 -11
- package/lib/test-server.js +323 -0
- package/lib/timeout.js +66 -0
- package/lib/utils.js +351 -218
- package/lib/within.js +75 -55
- package/lib/workerStorage.js +2 -1
- package/lib/workers.js +386 -277
- package/package.json +81 -75
- package/translations/de-DE.js +5 -3
- package/translations/fr-FR.js +5 -4
- package/translations/index.js +1 -0
- package/translations/it-IT.js +4 -3
- package/translations/ja-JP.js +4 -3
- package/translations/nl-NL.js +76 -0
- package/translations/pl-PL.js +4 -3
- package/translations/pt-BR.js +4 -3
- package/translations/ru-RU.js +4 -3
- package/translations/utils.js +9 -0
- package/translations/zh-CN.js +4 -3
- package/translations/zh-TW.js +4 -3
- package/typings/index.d.ts +197 -187
- package/typings/promiseBasedTypes.d.ts +53 -903
- package/typings/types.d.ts +372 -1042
- package/lib/cli.js +0 -257
- package/lib/helper/ExpectHelper.js +0 -391
- package/lib/helper/MockServer.js +0 -221
- package/lib/helper/SoftExpectHelper.js +0 -381
- package/lib/listener/artifacts.js +0 -19
- package/lib/listener/timeout.js +0 -109
- package/lib/mochaFactory.js +0 -113
- package/lib/plugin/debugErrors.js +0 -67
- package/lib/scenario.js +0 -224
- package/lib/ui.js +0 -236
package/lib/workers.js
CHANGED
|
@@ -1,226 +1,225 @@
|
|
|
1
|
-
|
|
2
|
-
const
|
|
3
|
-
const
|
|
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 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')
|
|
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')
|
|
23
23
|
|
|
24
24
|
const initializeCodecept = (configPath, options = {}) => {
|
|
25
|
-
const codecept = new Codecept(mainConfig.load(configPath || '.'), options)
|
|
26
|
-
codecept.init(getTestRoot(configPath))
|
|
27
|
-
codecept.loadTests()
|
|
25
|
+
const codecept = new Codecept(mainConfig.load(configPath || '.'), options)
|
|
26
|
+
codecept.init(getTestRoot(configPath))
|
|
27
|
+
codecept.loadTests()
|
|
28
28
|
|
|
29
|
-
return codecept
|
|
30
|
-
}
|
|
29
|
+
return codecept
|
|
30
|
+
}
|
|
31
31
|
|
|
32
|
-
const createOutputDir =
|
|
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)
|
|
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)
|
|
36
36
|
|
|
37
37
|
if (!fileExists(outputDir)) {
|
|
38
|
-
output.print(`creating output directory: ${outputDir}`)
|
|
39
|
-
mkdirp.sync(outputDir)
|
|
38
|
+
output.print(`creating output directory: ${outputDir}`)
|
|
39
|
+
mkdirp.sync(outputDir)
|
|
40
40
|
}
|
|
41
|
-
}
|
|
41
|
+
}
|
|
42
42
|
|
|
43
|
-
const populateGroups =
|
|
44
|
-
const groups = []
|
|
43
|
+
const populateGroups = numberOfWorkers => {
|
|
44
|
+
const groups = []
|
|
45
45
|
for (let i = 0; i < numberOfWorkers; i++) {
|
|
46
|
-
groups[i] = []
|
|
46
|
+
groups[i] = []
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
return groups
|
|
50
|
-
}
|
|
49
|
+
return groups
|
|
50
|
+
}
|
|
51
51
|
|
|
52
|
-
const createWorker = (workerObject) => {
|
|
52
|
+
const createWorker = (workerObject, isPoolMode = false) => {
|
|
53
53
|
const worker = new Worker(pathToWorker, {
|
|
54
54
|
workerData: {
|
|
55
55
|
options: simplifyObject(workerObject.options),
|
|
56
56
|
tests: workerObject.tests,
|
|
57
57
|
testRoot: workerObject.testRoot,
|
|
58
58
|
workerIndex: workerObject.workerIndex + 1,
|
|
59
|
+
poolMode: isPoolMode,
|
|
59
60
|
},
|
|
60
|
-
})
|
|
61
|
-
worker.on('error', err => output.error(`Worker Error: ${err.stack}`))
|
|
61
|
+
})
|
|
62
|
+
worker.on('error', err => output.error(`Worker Error: ${err.stack}`))
|
|
62
63
|
|
|
63
|
-
WorkerStorage.addWorker(worker)
|
|
64
|
-
return worker
|
|
65
|
-
}
|
|
64
|
+
WorkerStorage.addWorker(worker)
|
|
65
|
+
return worker
|
|
66
|
+
}
|
|
66
67
|
|
|
67
|
-
const simplifyObject =
|
|
68
|
+
const simplifyObject = object => {
|
|
68
69
|
return Object.keys(object)
|
|
69
|
-
.filter(
|
|
70
|
-
.filter(
|
|
71
|
-
.filter(
|
|
70
|
+
.filter(k => k.indexOf('_') !== 0)
|
|
71
|
+
.filter(k => typeof object[k] !== 'function')
|
|
72
|
+
.filter(k => typeof object[k] !== 'object')
|
|
72
73
|
.reduce((obj, key) => {
|
|
73
|
-
obj[key] = object[key]
|
|
74
|
-
return obj
|
|
75
|
-
}, {})
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const repackTest = (test) => {
|
|
79
|
-
test = Object.assign(new Test(test.title || '', () => { }), test);
|
|
80
|
-
test.parent = Object.assign(new Suite(test.parent.title), test.parent);
|
|
81
|
-
return test;
|
|
82
|
-
};
|
|
74
|
+
obj[key] = object[key]
|
|
75
|
+
return obj
|
|
76
|
+
}, {})
|
|
77
|
+
}
|
|
83
78
|
|
|
84
79
|
const createWorkerObjects = (testGroups, config, testRoot, options, selectedRuns) => {
|
|
85
|
-
selectedRuns = options && options.all && config.multiple ? Object.keys(config.multiple) : selectedRuns
|
|
80
|
+
selectedRuns = options && options.all && config.multiple ? Object.keys(config.multiple) : selectedRuns
|
|
86
81
|
if (selectedRuns === undefined || !selectedRuns.length || config.multiple === undefined) {
|
|
87
82
|
return testGroups.map((tests, index) => {
|
|
88
|
-
const workerObj = new WorkerObject(index)
|
|
89
|
-
workerObj.addConfig(config)
|
|
90
|
-
workerObj.addTests(tests)
|
|
91
|
-
workerObj.setTestRoot(testRoot)
|
|
92
|
-
workerObj.addOptions(options)
|
|
93
|
-
return workerObj
|
|
94
|
-
})
|
|
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
|
+
})
|
|
95
90
|
}
|
|
96
|
-
const workersToExecute = []
|
|
91
|
+
const workersToExecute = []
|
|
97
92
|
|
|
98
|
-
const currentOutputFolder = config.output
|
|
99
|
-
let currentMochawesomeReportDir
|
|
100
|
-
let currentMochaJunitReporterFile
|
|
93
|
+
const currentOutputFolder = config.output
|
|
94
|
+
let currentMochawesomeReportDir
|
|
95
|
+
let currentMochaJunitReporterFile
|
|
101
96
|
|
|
102
97
|
if (config.mocha && config.mocha.reporterOptions) {
|
|
103
|
-
currentMochawesomeReportDir = config.mocha.reporterOptions?.mochawesome.options.reportDir
|
|
104
|
-
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
|
|
105
100
|
}
|
|
106
101
|
|
|
107
|
-
collection.createRuns(selectedRuns, config).forEach(
|
|
108
|
-
const separator = path.sep
|
|
109
|
-
const _config = { ...config }
|
|
110
|
-
let workerName = worker.name.replace(':', '_')
|
|
111
|
-
_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}`
|
|
112
107
|
if (config.mocha && config.mocha.reporterOptions) {
|
|
113
|
-
_config.mocha.reporterOptions.mochawesome.options.reportDir = `${currentMochawesomeReportDir}${separator}${workerName}
|
|
114
|
-
|
|
115
|
-
const _tempArray = currentMochaJunitReporterFile.split(separator)
|
|
116
|
-
_tempArray.splice(
|
|
117
|
-
|
|
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)
|
|
118
117
|
}
|
|
119
|
-
workerName = worker.getOriginalName() || worker.getName()
|
|
120
|
-
const workerConfig = worker.getConfig()
|
|
121
|
-
workersToExecute.push(getOverridenConfig(workerName, workerConfig, _config))
|
|
122
|
-
})
|
|
123
|
-
const workers = []
|
|
124
|
-
let index = 0
|
|
125
|
-
testGroups.forEach(
|
|
126
|
-
const testWorkerArray = []
|
|
127
|
-
workersToExecute.forEach(
|
|
128
|
-
const workerObj = new WorkerObject(index++)
|
|
129
|
-
workerObj.addConfig(finalConfig)
|
|
130
|
-
workerObj.addTests(tests)
|
|
131
|
-
workerObj.setTestRoot(testRoot)
|
|
132
|
-
workerObj.addOptions(options)
|
|
133
|
-
testWorkerArray.push(workerObj)
|
|
134
|
-
})
|
|
135
|
-
workers.push(...testWorkerArray)
|
|
136
|
-
})
|
|
137
|
-
return workers
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const indexOfSmallestElement =
|
|
141
|
-
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
|
|
142
141
|
for (let j = 1; j < groups.length; j++) {
|
|
143
142
|
if (groups[j - 1].length > groups[j].length) {
|
|
144
|
-
i = j
|
|
143
|
+
i = j
|
|
145
144
|
}
|
|
146
145
|
}
|
|
147
|
-
return i
|
|
148
|
-
}
|
|
146
|
+
return i
|
|
147
|
+
}
|
|
149
148
|
|
|
150
|
-
const convertToMochaTests =
|
|
151
|
-
const group = []
|
|
149
|
+
const convertToMochaTests = testGroup => {
|
|
150
|
+
const group = []
|
|
152
151
|
if (testGroup instanceof Array) {
|
|
153
|
-
const mocha = MochaFactory.create({}, {})
|
|
154
|
-
mocha.files = testGroup
|
|
155
|
-
mocha.loadFiles()
|
|
156
|
-
mocha.suite.eachTest(
|
|
157
|
-
group.push(test.uid)
|
|
158
|
-
})
|
|
159
|
-
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()
|
|
160
159
|
}
|
|
161
160
|
|
|
162
|
-
return group
|
|
163
|
-
}
|
|
161
|
+
return group
|
|
162
|
+
}
|
|
164
163
|
|
|
165
164
|
const getOverridenConfig = (workerName, workerConfig, config) => {
|
|
166
165
|
// clone config
|
|
167
|
-
const overriddenConfig = deepClone(config)
|
|
166
|
+
const overriddenConfig = deepClone(config)
|
|
168
167
|
|
|
169
168
|
// get configuration
|
|
170
|
-
const browserConfig = workerConfig.browser
|
|
169
|
+
const browserConfig = workerConfig.browser
|
|
171
170
|
|
|
172
171
|
for (const key in browserConfig) {
|
|
173
|
-
overriddenConfig.helpers = replaceValueDeep(overriddenConfig.helpers, key, browserConfig[key])
|
|
172
|
+
overriddenConfig.helpers = replaceValueDeep(overriddenConfig.helpers, key, browserConfig[key])
|
|
174
173
|
}
|
|
175
174
|
|
|
176
175
|
// override tests configuration
|
|
177
176
|
if (overriddenConfig.tests) {
|
|
178
|
-
overriddenConfig.tests = workerConfig.tests
|
|
177
|
+
overriddenConfig.tests = workerConfig.tests
|
|
179
178
|
}
|
|
180
179
|
|
|
181
180
|
if (overriddenConfig.gherkin && workerConfig.gherkin && workerConfig.gherkin.features) {
|
|
182
|
-
overriddenConfig.gherkin.features = workerConfig.gherkin.features
|
|
181
|
+
overriddenConfig.gherkin.features = workerConfig.gherkin.features
|
|
183
182
|
}
|
|
184
|
-
return overriddenConfig
|
|
185
|
-
}
|
|
183
|
+
return overriddenConfig
|
|
184
|
+
}
|
|
186
185
|
|
|
187
186
|
class WorkerObject {
|
|
188
187
|
/**
|
|
189
188
|
* @param {Number} workerIndex - Unique ID for worker
|
|
190
189
|
*/
|
|
191
190
|
constructor(workerIndex) {
|
|
192
|
-
this.workerIndex = workerIndex
|
|
193
|
-
this.options = {}
|
|
194
|
-
this.tests = []
|
|
195
|
-
this.testRoot = getTestRoot()
|
|
191
|
+
this.workerIndex = workerIndex
|
|
192
|
+
this.options = {}
|
|
193
|
+
this.tests = []
|
|
194
|
+
this.testRoot = getTestRoot()
|
|
196
195
|
}
|
|
197
196
|
|
|
198
197
|
addConfig(config) {
|
|
199
|
-
const oldConfig = JSON.parse(this.options.override || '{}')
|
|
198
|
+
const oldConfig = JSON.parse(this.options.override || '{}')
|
|
200
199
|
const newConfig = {
|
|
201
200
|
...oldConfig,
|
|
202
201
|
...config,
|
|
203
|
-
}
|
|
204
|
-
this.options.override = JSON.stringify(newConfig)
|
|
202
|
+
}
|
|
203
|
+
this.options.override = JSON.stringify(newConfig)
|
|
205
204
|
}
|
|
206
205
|
|
|
207
206
|
addTestFiles(testGroup) {
|
|
208
|
-
this.addTests(convertToMochaTests(testGroup))
|
|
207
|
+
this.addTests(convertToMochaTests(testGroup))
|
|
209
208
|
}
|
|
210
209
|
|
|
211
210
|
addTests(tests) {
|
|
212
|
-
this.tests = this.tests.concat(tests)
|
|
211
|
+
this.tests = this.tests.concat(tests)
|
|
213
212
|
}
|
|
214
213
|
|
|
215
214
|
setTestRoot(path) {
|
|
216
|
-
this.testRoot = getTestRoot(path)
|
|
215
|
+
this.testRoot = getTestRoot(path)
|
|
217
216
|
}
|
|
218
217
|
|
|
219
218
|
addOptions(opts) {
|
|
220
219
|
this.options = {
|
|
221
220
|
...this.options,
|
|
222
221
|
...opts,
|
|
223
|
-
}
|
|
222
|
+
}
|
|
224
223
|
}
|
|
225
224
|
}
|
|
226
225
|
|
|
@@ -230,30 +229,29 @@ class Workers extends EventEmitter {
|
|
|
230
229
|
* @param {Object} config
|
|
231
230
|
*/
|
|
232
231
|
constructor(numberOfWorkers, config = { by: 'test' }) {
|
|
233
|
-
super()
|
|
234
|
-
this.setMaxListeners(50)
|
|
235
|
-
this.codecept = initializeCodecept(config.testConfig, config.options)
|
|
236
|
-
this.
|
|
237
|
-
this.errors = []
|
|
238
|
-
this.numberOfWorkers = 0
|
|
239
|
-
this.closedWorkers = 0
|
|
240
|
-
this.workers = []
|
|
241
|
-
this.
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
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)
|
|
251
249
|
}
|
|
252
250
|
|
|
253
251
|
_initWorkers(numberOfWorkers, config) {
|
|
254
|
-
this.splitTestsByGroups(numberOfWorkers, config)
|
|
255
|
-
this.workers = createWorkerObjects(this.testGroups, this.codecept.config, config.testConfig, config.options, config.selectedRuns)
|
|
256
|
-
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
|
|
257
255
|
}
|
|
258
256
|
|
|
259
257
|
/**
|
|
@@ -264,22 +262,27 @@ class Workers extends EventEmitter {
|
|
|
264
262
|
*
|
|
265
263
|
* - `suite`
|
|
266
264
|
* - `test`
|
|
265
|
+
* - `pool`
|
|
267
266
|
* - function(numberOfWorkers)
|
|
268
267
|
*
|
|
269
268
|
* This method can be overridden for a better split.
|
|
270
269
|
*/
|
|
271
270
|
splitTestsByGroups(numberOfWorkers, config) {
|
|
272
271
|
if (isFunction(config.by)) {
|
|
273
|
-
const createTests = config.by
|
|
274
|
-
const testGroups = createTests(numberOfWorkers)
|
|
272
|
+
const createTests = config.by
|
|
273
|
+
const testGroups = createTests(numberOfWorkers)
|
|
275
274
|
if (!(testGroups instanceof Array)) {
|
|
276
|
-
throw new Error('Test group should be an array')
|
|
275
|
+
throw new Error('Test group should be an array')
|
|
277
276
|
}
|
|
278
277
|
for (const testGroup of testGroups) {
|
|
279
|
-
this.testGroups.push(convertToMochaTests(testGroup))
|
|
278
|
+
this.testGroups.push(convertToMochaTests(testGroup))
|
|
280
279
|
}
|
|
281
280
|
} else if (typeof numberOfWorkers === 'number' && numberOfWorkers > 0) {
|
|
282
|
-
|
|
281
|
+
if (config.by === 'pool') {
|
|
282
|
+
this.createTestPool(numberOfWorkers)
|
|
283
|
+
} else {
|
|
284
|
+
this.testGroups = config.by === 'suite' ? this.createGroupsOfSuites(numberOfWorkers) : this.createGroupsOfTests(numberOfWorkers)
|
|
285
|
+
}
|
|
283
286
|
}
|
|
284
287
|
}
|
|
285
288
|
|
|
@@ -289,53 +292,132 @@ class Workers extends EventEmitter {
|
|
|
289
292
|
* @returns {WorkerObject}
|
|
290
293
|
*/
|
|
291
294
|
spawn() {
|
|
292
|
-
const worker = new WorkerObject(this.numberOfWorkers)
|
|
293
|
-
this.workers.push(worker)
|
|
294
|
-
this.numberOfWorkers += 1
|
|
295
|
-
return worker
|
|
295
|
+
const worker = new WorkerObject(this.numberOfWorkers)
|
|
296
|
+
this.workers.push(worker)
|
|
297
|
+
this.numberOfWorkers += 1
|
|
298
|
+
return worker
|
|
296
299
|
}
|
|
297
300
|
|
|
298
301
|
/**
|
|
299
302
|
* @param {Number} numberOfWorkers
|
|
300
303
|
*/
|
|
301
304
|
createGroupsOfTests(numberOfWorkers) {
|
|
302
|
-
const files = this.codecept.testFiles
|
|
303
|
-
const mocha = Container.mocha()
|
|
304
|
-
mocha.files = files
|
|
305
|
-
mocha.loadFiles()
|
|
305
|
+
const files = this.codecept.testFiles
|
|
306
|
+
const mocha = Container.mocha()
|
|
307
|
+
mocha.files = files
|
|
308
|
+
mocha.loadFiles()
|
|
306
309
|
|
|
307
|
-
const groups = populateGroups(numberOfWorkers)
|
|
308
|
-
let groupCounter = 0
|
|
310
|
+
const groups = populateGroups(numberOfWorkers)
|
|
311
|
+
let groupCounter = 0
|
|
309
312
|
|
|
310
|
-
mocha.suite.eachTest(
|
|
311
|
-
const i = groupCounter % groups.length
|
|
313
|
+
mocha.suite.eachTest(test => {
|
|
314
|
+
const i = groupCounter % groups.length
|
|
312
315
|
if (test) {
|
|
313
|
-
groups[i].push(test.uid)
|
|
314
|
-
groupCounter
|
|
316
|
+
groups[i].push(test.uid)
|
|
317
|
+
groupCounter++
|
|
315
318
|
}
|
|
316
|
-
})
|
|
317
|
-
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
|
|
318
400
|
}
|
|
319
401
|
|
|
320
402
|
/**
|
|
321
403
|
* @param {Number} numberOfWorkers
|
|
322
404
|
*/
|
|
323
405
|
createGroupsOfSuites(numberOfWorkers) {
|
|
324
|
-
const files = this.codecept.testFiles
|
|
325
|
-
const groups = populateGroups(numberOfWorkers)
|
|
326
|
-
|
|
327
|
-
const mocha = Container.mocha()
|
|
328
|
-
mocha.files = files
|
|
329
|
-
mocha.loadFiles()
|
|
330
|
-
mocha.suite.suites.forEach(
|
|
331
|
-
const i = indexOfSmallestElement(groups)
|
|
332
|
-
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 => {
|
|
333
415
|
if (test) {
|
|
334
|
-
groups[i].push(test.uid)
|
|
416
|
+
groups[i].push(test.uid)
|
|
335
417
|
}
|
|
336
|
-
})
|
|
337
|
-
})
|
|
338
|
-
return groups
|
|
418
|
+
})
|
|
419
|
+
})
|
|
420
|
+
return groups
|
|
339
421
|
}
|
|
340
422
|
|
|
341
423
|
/**
|
|
@@ -343,160 +425,187 @@ class Workers extends EventEmitter {
|
|
|
343
425
|
*/
|
|
344
426
|
overrideConfig(config) {
|
|
345
427
|
for (const worker of this.workers) {
|
|
346
|
-
worker.addConfig(config)
|
|
428
|
+
worker.addConfig(config)
|
|
347
429
|
}
|
|
348
430
|
}
|
|
349
431
|
|
|
350
432
|
async bootstrapAll() {
|
|
351
|
-
return runHook(this.codecept.config.bootstrapAll, 'bootstrapAll')
|
|
433
|
+
return runHook(this.codecept.config.bootstrapAll, 'bootstrapAll')
|
|
352
434
|
}
|
|
353
435
|
|
|
354
436
|
async teardownAll() {
|
|
355
|
-
return runHook(this.codecept.config.teardownAll, 'teardownAll')
|
|
437
|
+
return runHook(this.codecept.config.teardownAll, 'teardownAll')
|
|
356
438
|
}
|
|
357
439
|
|
|
358
440
|
run() {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
event.dispatcher.emit(event.workers.before);
|
|
363
|
-
process.env.RUNS_WITH_WORKERS = 'true';
|
|
441
|
+
recorder.startUnlessRunning()
|
|
442
|
+
event.dispatcher.emit(event.workers.before)
|
|
443
|
+
process.env.RUNS_WITH_WORKERS = 'true'
|
|
364
444
|
recorder.add('starting workers', () => {
|
|
365
445
|
for (const worker of this.workers) {
|
|
366
|
-
const workerThread = createWorker(worker)
|
|
367
|
-
this._listenWorkerEvents(workerThread)
|
|
446
|
+
const workerThread = createWorker(worker, this.isPoolMode)
|
|
447
|
+
this._listenWorkerEvents(workerThread)
|
|
368
448
|
}
|
|
369
|
-
})
|
|
449
|
+
})
|
|
370
450
|
return new Promise(resolve => {
|
|
371
|
-
this.on('end', resolve)
|
|
372
|
-
})
|
|
451
|
+
this.on('end', resolve)
|
|
452
|
+
})
|
|
373
453
|
}
|
|
374
454
|
|
|
375
455
|
/**
|
|
376
456
|
* @returns {Array<WorkerObject>}
|
|
377
457
|
*/
|
|
378
458
|
getWorkers() {
|
|
379
|
-
return this.workers
|
|
459
|
+
return this.workers
|
|
380
460
|
}
|
|
381
461
|
|
|
382
462
|
/**
|
|
383
463
|
* @returns {Boolean}
|
|
384
464
|
*/
|
|
385
465
|
isFailed() {
|
|
386
|
-
return (
|
|
466
|
+
return (Container.result().failures.length || this.errors.length) > 0
|
|
387
467
|
}
|
|
388
468
|
|
|
389
469
|
_listenWorkerEvents(worker) {
|
|
390
|
-
worker
|
|
391
|
-
|
|
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
|
+
}
|
|
392
490
|
|
|
393
491
|
// deal with events that are not test cycle related
|
|
394
492
|
if (!message.event) {
|
|
395
|
-
return this.emit('message', message)
|
|
493
|
+
return this.emit('message', message)
|
|
396
494
|
}
|
|
397
495
|
|
|
398
496
|
switch (message.event) {
|
|
399
|
-
case event.all.
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
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
|
|
403
515
|
case event.suite.before:
|
|
404
|
-
this.emit(event.suite.before,
|
|
405
|
-
break
|
|
406
|
-
case event.hook.failed:
|
|
407
|
-
this.emit(event.hook.failed, repackTest(message.data));
|
|
408
|
-
this.errors.push(message.data.err);
|
|
409
|
-
break;
|
|
516
|
+
this.emit(event.suite.before, deserializeSuite(message.data))
|
|
517
|
+
break
|
|
410
518
|
case event.test.before:
|
|
411
|
-
this.emit(event.test.before,
|
|
412
|
-
break
|
|
519
|
+
this.emit(event.test.before, deserializeTest(message.data))
|
|
520
|
+
break
|
|
413
521
|
case event.test.started:
|
|
414
|
-
this.emit(event.test.started,
|
|
415
|
-
break
|
|
522
|
+
this.emit(event.test.started, deserializeTest(message.data))
|
|
523
|
+
break
|
|
416
524
|
case event.test.failed:
|
|
417
|
-
this.emit(event.test.failed,
|
|
418
|
-
break
|
|
525
|
+
this.emit(event.test.failed, deserializeTest(message.data))
|
|
526
|
+
break
|
|
419
527
|
case event.test.passed:
|
|
420
|
-
this.emit(event.test.passed,
|
|
421
|
-
break
|
|
528
|
+
this.emit(event.test.passed, deserializeTest(message.data))
|
|
529
|
+
break
|
|
422
530
|
case event.test.skipped:
|
|
423
|
-
this.emit(event.test.skipped,
|
|
424
|
-
break
|
|
531
|
+
this.emit(event.test.skipped, deserializeTest(message.data))
|
|
532
|
+
break
|
|
425
533
|
case event.test.finished:
|
|
426
|
-
this.emit(event.test.finished,
|
|
427
|
-
break
|
|
534
|
+
this.emit(event.test.finished, deserializeTest(message.data))
|
|
535
|
+
break
|
|
428
536
|
case event.test.after:
|
|
429
|
-
this.emit(event.test.after,
|
|
430
|
-
break
|
|
537
|
+
this.emit(event.test.after, deserializeTest(message.data))
|
|
538
|
+
break
|
|
431
539
|
case event.step.finished:
|
|
432
|
-
this.emit(event.step.finished, message.data)
|
|
433
|
-
break
|
|
540
|
+
this.emit(event.step.finished, message.data)
|
|
541
|
+
break
|
|
434
542
|
case event.step.started:
|
|
435
|
-
this.emit(event.step.started, message.data)
|
|
436
|
-
break
|
|
543
|
+
this.emit(event.step.started, message.data)
|
|
544
|
+
break
|
|
437
545
|
case event.step.passed:
|
|
438
|
-
this.emit(event.step.passed, message.data)
|
|
439
|
-
break
|
|
546
|
+
this.emit(event.step.passed, message.data)
|
|
547
|
+
break
|
|
440
548
|
case event.step.failed:
|
|
441
|
-
this.emit(event.step.failed, message.data)
|
|
442
|
-
break
|
|
549
|
+
this.emit(event.step.failed, message.data, message.data.error)
|
|
550
|
+
break
|
|
443
551
|
}
|
|
444
|
-
})
|
|
552
|
+
})
|
|
445
553
|
|
|
446
|
-
worker.on('error',
|
|
447
|
-
this.errors.push(err)
|
|
448
|
-
})
|
|
554
|
+
worker.on('error', err => {
|
|
555
|
+
this.errors.push(err)
|
|
556
|
+
})
|
|
449
557
|
|
|
450
558
|
worker.on('exit', () => {
|
|
451
|
-
this.closedWorkers += 1
|
|
452
|
-
|
|
453
|
-
|
|
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()
|
|
454
569
|
}
|
|
455
|
-
})
|
|
570
|
+
})
|
|
456
571
|
}
|
|
457
572
|
|
|
458
573
|
_finishRun() {
|
|
459
|
-
event.dispatcher.emit(event.workers.after)
|
|
460
|
-
if (
|
|
461
|
-
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
|
|
462
577
|
} else {
|
|
463
|
-
process.exitCode = 0
|
|
578
|
+
process.exitCode = 0
|
|
464
579
|
}
|
|
465
|
-
// removed this.finishedTests because in all /lib only first argument (!this.isFailed()) is used)
|
|
466
|
-
this.emit(event.all.result, !this.isFailed());
|
|
467
|
-
this.emit('end'); // internal event
|
|
468
|
-
}
|
|
469
580
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
this.
|
|
473
|
-
this.stats.tests += newStats.tests;
|
|
474
|
-
this.stats.pending += newStats.pending;
|
|
475
|
-
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
|
|
476
584
|
}
|
|
477
585
|
|
|
478
586
|
printResults() {
|
|
479
|
-
|
|
480
|
-
|
|
587
|
+
const result = Container.result()
|
|
588
|
+
result.finish()
|
|
481
589
|
|
|
482
590
|
// Reset process for logs in main thread
|
|
483
|
-
output.process(null)
|
|
484
|
-
output.print()
|
|
591
|
+
output.process(null)
|
|
592
|
+
output.print()
|
|
485
593
|
|
|
486
|
-
this.failuresLog =
|
|
594
|
+
this.failuresLog = result.failures
|
|
487
595
|
.filter(log => log.length && typeof log[1] === 'number')
|
|
488
596
|
// mocha/lib/reporters/base.js
|
|
489
|
-
.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])
|
|
490
598
|
|
|
491
599
|
if (this.failuresLog.length) {
|
|
492
|
-
output.print()
|
|
493
|
-
output.print('-- FAILURES:')
|
|
494
|
-
this.failuresLog.forEach(log => output.print(...log))
|
|
600
|
+
output.print()
|
|
601
|
+
output.print('-- FAILURES:')
|
|
602
|
+
this.failuresLog.forEach(log => output.print(...log))
|
|
495
603
|
}
|
|
496
604
|
|
|
497
|
-
output.result(
|
|
498
|
-
|
|
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'
|
|
499
608
|
}
|
|
500
609
|
}
|
|
501
610
|
|
|
502
|
-
module.exports = Workers
|
|
611
|
+
module.exports = Workers
|