codeceptjs 3.6.10 → 3.7.0-beta.1
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 +81 -110
- package/bin/codecept.js +2 -2
- package/docs/webapi/clearCookie.mustache +1 -1
- package/lib/actor.js +46 -36
- 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 +87 -83
- package/lib/command/configMigrate.js +2 -4
- package/lib/command/definitions.js +5 -25
- package/lib/command/generate.js +10 -14
- package/lib/command/gherkin/snippets.js +10 -8
- package/lib/command/gherkin/steps.js +1 -1
- package/lib/command/info.js +1 -3
- package/lib/command/init.js +8 -12
- package/lib/command/interactive.js +1 -1
- package/lib/command/list.js +1 -1
- package/lib/command/run-multiple.js +12 -35
- package/lib/command/run-workers.js +10 -10
- package/lib/command/utils.js +5 -6
- package/lib/command/workers/runTests.js +14 -17
- package/lib/container.js +327 -237
- 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/els.js +177 -0
- package/lib/event.js +1 -0
- package/lib/heal.js +78 -80
- package/lib/helper/ApiDataFactory.js +3 -6
- package/lib/helper/Appium.js +15 -30
- package/lib/helper/FileSystem.js +3 -3
- package/lib/helper/GraphQLDataFactory.js +3 -3
- package/lib/helper/JSONResponse.js +57 -37
- package/lib/helper/Nightmare.js +35 -53
- package/lib/helper/Playwright.js +189 -251
- package/lib/helper/Protractor.js +54 -77
- package/lib/helper/Puppeteer.js +134 -232
- package/lib/helper/REST.js +5 -17
- package/lib/helper/TestCafe.js +21 -44
- package/lib/helper/WebDriver.js +103 -162
- package/lib/helper/testcafe/testcafe-utils.js +26 -27
- package/lib/listener/artifacts.js +2 -2
- package/lib/listener/emptyRun.js +58 -0
- package/lib/listener/exit.js +4 -4
- package/lib/listener/{retry.js → globalRetry.js} +5 -5
- package/lib/listener/{timeout.js → globalTimeout.js} +8 -8
- package/lib/listener/helpers.js +15 -15
- package/lib/listener/mocha.js +1 -1
- package/lib/listener/steps.js +17 -12
- package/lib/listener/store.js +12 -0
- package/lib/mocha/asyncWrapper.js +204 -0
- package/lib/{interfaces → mocha}/bdd.js +3 -3
- package/lib/mocha/cli.js +257 -0
- package/lib/mocha/factory.js +104 -0
- package/lib/{interfaces → mocha}/featureConfig.js +11 -12
- package/lib/{interfaces → mocha}/gherkin.js +26 -28
- package/lib/mocha/hooks.js +83 -0
- package/lib/mocha/index.js +12 -0
- package/lib/mocha/inject.js +24 -0
- package/lib/{interfaces → mocha}/scenarioConfig.js +10 -6
- package/lib/mocha/suite.js +55 -0
- package/lib/mocha/test.js +60 -0
- package/lib/mocha/types.d.ts +31 -0
- package/lib/mocha/ui.js +219 -0
- package/lib/output.js +28 -10
- package/lib/pause.js +159 -135
- package/lib/plugin/autoDelay.js +4 -4
- package/lib/plugin/autoLogin.js +6 -7
- package/lib/plugin/commentStep.js +1 -1
- package/lib/plugin/coverage.js +10 -19
- package/lib/plugin/customLocator.js +3 -3
- package/lib/plugin/debugErrors.js +2 -2
- package/lib/plugin/eachElement.js +1 -1
- package/lib/plugin/fakerTransform.js +1 -1
- package/lib/plugin/heal.js +6 -9
- package/lib/plugin/retryFailedStep.js +4 -4
- package/lib/plugin/retryTo.js +2 -2
- package/lib/plugin/screenshotOnFail.js +9 -36
- package/lib/plugin/selenoid.js +15 -35
- package/lib/plugin/stepByStepReport.js +51 -13
- package/lib/plugin/stepTimeout.js +4 -11
- package/lib/plugin/subtitles.js +4 -4
- package/lib/plugin/tryTo.js +1 -1
- package/lib/plugin/wdio.js +8 -10
- package/lib/recorder.js +142 -121
- package/lib/secret.js +1 -1
- package/lib/step.js +160 -144
- package/lib/store.js +6 -2
- package/lib/template/heal.js +2 -11
- package/lib/utils.js +224 -216
- package/lib/within.js +73 -55
- package/lib/workers.js +265 -261
- package/package.json +46 -47
- package/typings/index.d.ts +172 -184
- package/typings/promiseBasedTypes.d.ts +53 -516
- package/typings/types.d.ts +127 -587
- package/lib/cli.js +0 -256
- package/lib/helper/ExpectHelper.js +0 -391
- package/lib/helper/SoftExpectHelper.js +0 -381
- package/lib/mochaFactory.js +0 -113
- package/lib/scenario.js +0 -224
- package/lib/ui.js +0 -236
package/lib/workers.js
CHANGED
|
@@ -1,54 +1,58 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
const mkdirp = require('mkdirp')
|
|
3
|
-
const { Worker } = require('worker_threads')
|
|
4
|
-
const {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
const
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const mkdirp = require('mkdirp')
|
|
3
|
+
const { Worker } = require('worker_threads')
|
|
4
|
+
const {
|
|
5
|
+
Suite,
|
|
6
|
+
Test,
|
|
7
|
+
reporters: { Base },
|
|
8
|
+
} = require('mocha')
|
|
9
|
+
const { EventEmitter } = require('events')
|
|
10
|
+
const ms = require('ms')
|
|
11
|
+
const Codecept = require('./codecept')
|
|
12
|
+
const MochaFactory = require('./mocha/factory')
|
|
13
|
+
const Container = require('./container')
|
|
14
|
+
const { getTestRoot } = require('./command/utils')
|
|
15
|
+
const { isFunction, fileExists } = require('./utils')
|
|
16
|
+
const { replaceValueDeep, deepClone } = require('./utils')
|
|
17
|
+
const mainConfig = require('./config')
|
|
18
|
+
const output = require('./output')
|
|
19
|
+
const event = require('./event')
|
|
20
|
+
const recorder = require('./recorder')
|
|
21
|
+
const runHook = require('./hooks')
|
|
22
|
+
const WorkerStorage = require('./workerStorage')
|
|
23
|
+
const collection = require('./command/run-multiple/collection')
|
|
24
|
+
|
|
25
|
+
const pathToWorker = path.join(__dirname, 'command', 'workers', 'runTests.js')
|
|
22
26
|
|
|
23
27
|
const initializeCodecept = (configPath, options = {}) => {
|
|
24
|
-
const codecept = new Codecept(mainConfig.load(configPath || '.'), options)
|
|
25
|
-
codecept.init(getTestRoot(configPath))
|
|
26
|
-
codecept.loadTests()
|
|
28
|
+
const codecept = new Codecept(mainConfig.load(configPath || '.'), options)
|
|
29
|
+
codecept.init(getTestRoot(configPath))
|
|
30
|
+
codecept.loadTests()
|
|
27
31
|
|
|
28
|
-
return codecept
|
|
29
|
-
}
|
|
32
|
+
return codecept
|
|
33
|
+
}
|
|
30
34
|
|
|
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)
|
|
35
|
+
const createOutputDir = configPath => {
|
|
36
|
+
const config = mainConfig.load(configPath || '.')
|
|
37
|
+
const testRoot = getTestRoot(configPath)
|
|
38
|
+
const outputDir = path.isAbsolute(config.output) ? config.output : path.join(testRoot, config.output)
|
|
35
39
|
|
|
36
40
|
if (!fileExists(outputDir)) {
|
|
37
|
-
output.print(`creating output directory: ${outputDir}`)
|
|
38
|
-
mkdirp.sync(outputDir)
|
|
41
|
+
output.print(`creating output directory: ${outputDir}`)
|
|
42
|
+
mkdirp.sync(outputDir)
|
|
39
43
|
}
|
|
40
|
-
}
|
|
44
|
+
}
|
|
41
45
|
|
|
42
|
-
const populateGroups =
|
|
43
|
-
const groups = []
|
|
46
|
+
const populateGroups = numberOfWorkers => {
|
|
47
|
+
const groups = []
|
|
44
48
|
for (let i = 0; i < numberOfWorkers; i++) {
|
|
45
|
-
groups[i] = []
|
|
49
|
+
groups[i] = []
|
|
46
50
|
}
|
|
47
51
|
|
|
48
|
-
return groups
|
|
49
|
-
}
|
|
52
|
+
return groups
|
|
53
|
+
}
|
|
50
54
|
|
|
51
|
-
const createWorker =
|
|
55
|
+
const createWorker = workerObject => {
|
|
52
56
|
const worker = new Worker(pathToWorker, {
|
|
53
57
|
workerData: {
|
|
54
58
|
options: simplifyObject(workerObject.options),
|
|
@@ -56,170 +60,174 @@ const createWorker = (workerObject) => {
|
|
|
56
60
|
testRoot: workerObject.testRoot,
|
|
57
61
|
workerIndex: workerObject.workerIndex + 1,
|
|
58
62
|
},
|
|
59
|
-
})
|
|
60
|
-
worker.on('error', err => output.error(`Worker Error: ${err.stack}`))
|
|
63
|
+
})
|
|
64
|
+
worker.on('error', err => output.error(`Worker Error: ${err.stack}`))
|
|
61
65
|
|
|
62
|
-
WorkerStorage.addWorker(worker)
|
|
63
|
-
return worker
|
|
64
|
-
}
|
|
66
|
+
WorkerStorage.addWorker(worker)
|
|
67
|
+
return worker
|
|
68
|
+
}
|
|
65
69
|
|
|
66
|
-
const simplifyObject =
|
|
70
|
+
const simplifyObject = object => {
|
|
67
71
|
return Object.keys(object)
|
|
68
|
-
.filter(
|
|
69
|
-
.filter(
|
|
70
|
-
.filter(
|
|
72
|
+
.filter(k => k.indexOf('_') !== 0)
|
|
73
|
+
.filter(k => typeof object[k] !== 'function')
|
|
74
|
+
.filter(k => typeof object[k] !== 'object')
|
|
71
75
|
.reduce((obj, key) => {
|
|
72
|
-
obj[key] = object[key]
|
|
73
|
-
return obj
|
|
74
|
-
}, {})
|
|
75
|
-
}
|
|
76
|
+
obj[key] = object[key]
|
|
77
|
+
return obj
|
|
78
|
+
}, {})
|
|
79
|
+
}
|
|
76
80
|
|
|
77
|
-
const repackTest =
|
|
78
|
-
test = Object.assign(new Test(test.title || '', () => {
|
|
79
|
-
test.parent = Object.assign(new Suite(test.parent.title), test.parent)
|
|
80
|
-
return test
|
|
81
|
-
}
|
|
81
|
+
const repackTest = test => {
|
|
82
|
+
test = Object.assign(new Test(test.title || '', () => {}), test)
|
|
83
|
+
test.parent = Object.assign(new Suite(test.parent.title), test.parent)
|
|
84
|
+
return test
|
|
85
|
+
}
|
|
82
86
|
|
|
83
87
|
const createWorkerObjects = (testGroups, config, testRoot, options, selectedRuns) => {
|
|
84
|
-
selectedRuns = options && options.all && config.multiple ? Object.keys(config.multiple) : selectedRuns
|
|
88
|
+
selectedRuns = options && options.all && config.multiple ? Object.keys(config.multiple) : selectedRuns
|
|
85
89
|
if (selectedRuns === undefined || !selectedRuns.length || config.multiple === undefined) {
|
|
86
90
|
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
|
-
})
|
|
91
|
+
const workerObj = new WorkerObject(index)
|
|
92
|
+
workerObj.addConfig(config)
|
|
93
|
+
workerObj.addTests(tests)
|
|
94
|
+
workerObj.setTestRoot(testRoot)
|
|
95
|
+
workerObj.addOptions(options)
|
|
96
|
+
return workerObj
|
|
97
|
+
})
|
|
94
98
|
}
|
|
95
|
-
const workersToExecute = []
|
|
99
|
+
const workersToExecute = []
|
|
96
100
|
|
|
97
|
-
const currentOutputFolder = config.output
|
|
98
|
-
let currentMochawesomeReportDir
|
|
99
|
-
let currentMochaJunitReporterFile
|
|
101
|
+
const currentOutputFolder = config.output
|
|
102
|
+
let currentMochawesomeReportDir
|
|
103
|
+
let currentMochaJunitReporterFile
|
|
100
104
|
|
|
101
105
|
if (config.mocha && config.mocha.reporterOptions) {
|
|
102
|
-
currentMochawesomeReportDir = config.mocha.reporterOptions?.mochawesome.options.reportDir
|
|
103
|
-
currentMochaJunitReporterFile = config.mocha.reporterOptions['mocha-junit-reporter'].options.mochaFile
|
|
106
|
+
currentMochawesomeReportDir = config.mocha.reporterOptions?.mochawesome.options.reportDir
|
|
107
|
+
currentMochaJunitReporterFile = config.mocha.reporterOptions['mocha-junit-reporter'].options.mochaFile
|
|
104
108
|
}
|
|
105
109
|
|
|
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}
|
|
110
|
+
collection.createRuns(selectedRuns, config).forEach(worker => {
|
|
111
|
+
const separator = path.sep
|
|
112
|
+
const _config = { ...config }
|
|
113
|
+
let workerName = worker.name.replace(':', '_')
|
|
114
|
+
_config.output = `${currentOutputFolder}${separator}${workerName}`
|
|
111
115
|
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
|
-
|
|
116
|
+
_config.mocha.reporterOptions.mochawesome.options.reportDir = `${currentMochawesomeReportDir}${separator}${workerName}`
|
|
117
|
+
|
|
118
|
+
const _tempArray = currentMochaJunitReporterFile.split(separator)
|
|
119
|
+
_tempArray.splice(
|
|
120
|
+
_tempArray.findIndex(item => item.includes('.xml')),
|
|
121
|
+
0,
|
|
122
|
+
workerName,
|
|
123
|
+
)
|
|
124
|
+
_config.mocha.reporterOptions['mocha-junit-reporter'].options.mochaFile = _tempArray.join(separator)
|
|
117
125
|
}
|
|
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
|
|
126
|
+
workerName = worker.getOriginalName() || worker.getName()
|
|
127
|
+
const workerConfig = worker.getConfig()
|
|
128
|
+
workersToExecute.push(getOverridenConfig(workerName, workerConfig, _config))
|
|
129
|
+
})
|
|
130
|
+
const workers = []
|
|
131
|
+
let index = 0
|
|
132
|
+
testGroups.forEach(tests => {
|
|
133
|
+
const testWorkerArray = []
|
|
134
|
+
workersToExecute.forEach(finalConfig => {
|
|
135
|
+
const workerObj = new WorkerObject(index++)
|
|
136
|
+
workerObj.addConfig(finalConfig)
|
|
137
|
+
workerObj.addTests(tests)
|
|
138
|
+
workerObj.setTestRoot(testRoot)
|
|
139
|
+
workerObj.addOptions(options)
|
|
140
|
+
testWorkerArray.push(workerObj)
|
|
141
|
+
})
|
|
142
|
+
workers.push(...testWorkerArray)
|
|
143
|
+
})
|
|
144
|
+
return workers
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const indexOfSmallestElement = groups => {
|
|
148
|
+
let i = 0
|
|
141
149
|
for (let j = 1; j < groups.length; j++) {
|
|
142
150
|
if (groups[j - 1].length > groups[j].length) {
|
|
143
|
-
i = j
|
|
151
|
+
i = j
|
|
144
152
|
}
|
|
145
153
|
}
|
|
146
|
-
return i
|
|
147
|
-
}
|
|
154
|
+
return i
|
|
155
|
+
}
|
|
148
156
|
|
|
149
|
-
const convertToMochaTests =
|
|
150
|
-
const group = []
|
|
157
|
+
const convertToMochaTests = testGroup => {
|
|
158
|
+
const group = []
|
|
151
159
|
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()
|
|
160
|
+
const mocha = MochaFactory.create({}, {})
|
|
161
|
+
mocha.files = testGroup
|
|
162
|
+
mocha.loadFiles()
|
|
163
|
+
mocha.suite.eachTest(test => {
|
|
164
|
+
group.push(test.uid)
|
|
165
|
+
})
|
|
166
|
+
mocha.unloadFiles()
|
|
159
167
|
}
|
|
160
168
|
|
|
161
|
-
return group
|
|
162
|
-
}
|
|
169
|
+
return group
|
|
170
|
+
}
|
|
163
171
|
|
|
164
172
|
const getOverridenConfig = (workerName, workerConfig, config) => {
|
|
165
173
|
// clone config
|
|
166
|
-
const overriddenConfig = deepClone(config)
|
|
174
|
+
const overriddenConfig = deepClone(config)
|
|
167
175
|
|
|
168
176
|
// get configuration
|
|
169
|
-
const browserConfig = workerConfig.browser
|
|
177
|
+
const browserConfig = workerConfig.browser
|
|
170
178
|
|
|
171
179
|
for (const key in browserConfig) {
|
|
172
|
-
overriddenConfig.helpers = replaceValueDeep(overriddenConfig.helpers, key, browserConfig[key])
|
|
180
|
+
overriddenConfig.helpers = replaceValueDeep(overriddenConfig.helpers, key, browserConfig[key])
|
|
173
181
|
}
|
|
174
182
|
|
|
175
183
|
// override tests configuration
|
|
176
184
|
if (overriddenConfig.tests) {
|
|
177
|
-
overriddenConfig.tests = workerConfig.tests
|
|
185
|
+
overriddenConfig.tests = workerConfig.tests
|
|
178
186
|
}
|
|
179
187
|
|
|
180
188
|
if (overriddenConfig.gherkin && workerConfig.gherkin && workerConfig.gherkin.features) {
|
|
181
|
-
overriddenConfig.gherkin.features = workerConfig.gherkin.features
|
|
189
|
+
overriddenConfig.gherkin.features = workerConfig.gherkin.features
|
|
182
190
|
}
|
|
183
|
-
return overriddenConfig
|
|
184
|
-
}
|
|
191
|
+
return overriddenConfig
|
|
192
|
+
}
|
|
185
193
|
|
|
186
194
|
class WorkerObject {
|
|
187
195
|
/**
|
|
188
196
|
* @param {Number} workerIndex - Unique ID for worker
|
|
189
197
|
*/
|
|
190
198
|
constructor(workerIndex) {
|
|
191
|
-
this.workerIndex = workerIndex
|
|
192
|
-
this.options = {}
|
|
193
|
-
this.tests = []
|
|
194
|
-
this.testRoot = getTestRoot()
|
|
199
|
+
this.workerIndex = workerIndex
|
|
200
|
+
this.options = {}
|
|
201
|
+
this.tests = []
|
|
202
|
+
this.testRoot = getTestRoot()
|
|
195
203
|
}
|
|
196
204
|
|
|
197
205
|
addConfig(config) {
|
|
198
|
-
const oldConfig = JSON.parse(this.options.override || '{}')
|
|
206
|
+
const oldConfig = JSON.parse(this.options.override || '{}')
|
|
199
207
|
const newConfig = {
|
|
200
208
|
...oldConfig,
|
|
201
209
|
...config,
|
|
202
|
-
}
|
|
203
|
-
this.options.override = JSON.stringify(newConfig)
|
|
210
|
+
}
|
|
211
|
+
this.options.override = JSON.stringify(newConfig)
|
|
204
212
|
}
|
|
205
213
|
|
|
206
214
|
addTestFiles(testGroup) {
|
|
207
|
-
this.addTests(convertToMochaTests(testGroup))
|
|
215
|
+
this.addTests(convertToMochaTests(testGroup))
|
|
208
216
|
}
|
|
209
217
|
|
|
210
218
|
addTests(tests) {
|
|
211
|
-
this.tests = this.tests.concat(tests)
|
|
219
|
+
this.tests = this.tests.concat(tests)
|
|
212
220
|
}
|
|
213
221
|
|
|
214
222
|
setTestRoot(path) {
|
|
215
|
-
this.testRoot = getTestRoot(path)
|
|
223
|
+
this.testRoot = getTestRoot(path)
|
|
216
224
|
}
|
|
217
225
|
|
|
218
226
|
addOptions(opts) {
|
|
219
227
|
this.options = {
|
|
220
228
|
...this.options,
|
|
221
229
|
...opts,
|
|
222
|
-
}
|
|
230
|
+
}
|
|
223
231
|
}
|
|
224
232
|
}
|
|
225
233
|
|
|
@@ -229,30 +237,30 @@ class Workers extends EventEmitter {
|
|
|
229
237
|
* @param {Object} config
|
|
230
238
|
*/
|
|
231
239
|
constructor(numberOfWorkers, config = { by: 'test' }) {
|
|
232
|
-
super()
|
|
233
|
-
this.setMaxListeners(50)
|
|
234
|
-
this.codecept = initializeCodecept(config.testConfig, config.options)
|
|
235
|
-
this.failuresLog = []
|
|
236
|
-
this.errors = []
|
|
237
|
-
this.numberOfWorkers = 0
|
|
238
|
-
this.closedWorkers = 0
|
|
239
|
-
this.workers = []
|
|
240
|
+
super()
|
|
241
|
+
this.setMaxListeners(50)
|
|
242
|
+
this.codecept = initializeCodecept(config.testConfig, config.options)
|
|
243
|
+
this.failuresLog = []
|
|
244
|
+
this.errors = []
|
|
245
|
+
this.numberOfWorkers = 0
|
|
246
|
+
this.closedWorkers = 0
|
|
247
|
+
this.workers = []
|
|
240
248
|
this.stats = {
|
|
241
249
|
passes: 0,
|
|
242
250
|
failures: 0,
|
|
243
251
|
tests: 0,
|
|
244
252
|
pending: 0,
|
|
245
|
-
}
|
|
246
|
-
this.testGroups = []
|
|
253
|
+
}
|
|
254
|
+
this.testGroups = []
|
|
247
255
|
|
|
248
|
-
createOutputDir(config.testConfig)
|
|
249
|
-
if (numberOfWorkers) this._initWorkers(numberOfWorkers, config)
|
|
256
|
+
createOutputDir(config.testConfig)
|
|
257
|
+
if (numberOfWorkers) this._initWorkers(numberOfWorkers, config)
|
|
250
258
|
}
|
|
251
259
|
|
|
252
260
|
_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
|
|
261
|
+
this.splitTestsByGroups(numberOfWorkers, config)
|
|
262
|
+
this.workers = createWorkerObjects(this.testGroups, this.codecept.config, config.testConfig, config.options, config.selectedRuns)
|
|
263
|
+
this.numberOfWorkers = this.workers.length
|
|
256
264
|
}
|
|
257
265
|
|
|
258
266
|
/**
|
|
@@ -269,16 +277,16 @@ class Workers extends EventEmitter {
|
|
|
269
277
|
*/
|
|
270
278
|
splitTestsByGroups(numberOfWorkers, config) {
|
|
271
279
|
if (isFunction(config.by)) {
|
|
272
|
-
const createTests = config.by
|
|
273
|
-
const testGroups = createTests(numberOfWorkers)
|
|
280
|
+
const createTests = config.by
|
|
281
|
+
const testGroups = createTests(numberOfWorkers)
|
|
274
282
|
if (!(testGroups instanceof Array)) {
|
|
275
|
-
throw new Error('Test group should be an array')
|
|
283
|
+
throw new Error('Test group should be an array')
|
|
276
284
|
}
|
|
277
285
|
for (const testGroup of testGroups) {
|
|
278
|
-
this.testGroups.push(convertToMochaTests(testGroup))
|
|
286
|
+
this.testGroups.push(convertToMochaTests(testGroup))
|
|
279
287
|
}
|
|
280
288
|
} else if (typeof numberOfWorkers === 'number' && numberOfWorkers > 0) {
|
|
281
|
-
this.testGroups = config.by === 'suite' ? this.createGroupsOfSuites(numberOfWorkers) : this.createGroupsOfTests(numberOfWorkers)
|
|
289
|
+
this.testGroups = config.by === 'suite' ? this.createGroupsOfSuites(numberOfWorkers) : this.createGroupsOfTests(numberOfWorkers)
|
|
282
290
|
}
|
|
283
291
|
}
|
|
284
292
|
|
|
@@ -288,53 +296,53 @@ class Workers extends EventEmitter {
|
|
|
288
296
|
* @returns {WorkerObject}
|
|
289
297
|
*/
|
|
290
298
|
spawn() {
|
|
291
|
-
const worker = new WorkerObject(this.numberOfWorkers)
|
|
292
|
-
this.workers.push(worker)
|
|
293
|
-
this.numberOfWorkers += 1
|
|
294
|
-
return worker
|
|
299
|
+
const worker = new WorkerObject(this.numberOfWorkers)
|
|
300
|
+
this.workers.push(worker)
|
|
301
|
+
this.numberOfWorkers += 1
|
|
302
|
+
return worker
|
|
295
303
|
}
|
|
296
304
|
|
|
297
305
|
/**
|
|
298
306
|
* @param {Number} numberOfWorkers
|
|
299
307
|
*/
|
|
300
308
|
createGroupsOfTests(numberOfWorkers) {
|
|
301
|
-
const files = this.codecept.testFiles
|
|
302
|
-
const mocha = Container.mocha()
|
|
303
|
-
mocha.files = files
|
|
304
|
-
mocha.loadFiles()
|
|
309
|
+
const files = this.codecept.testFiles
|
|
310
|
+
const mocha = Container.mocha()
|
|
311
|
+
mocha.files = files
|
|
312
|
+
mocha.loadFiles()
|
|
305
313
|
|
|
306
|
-
const groups = populateGroups(numberOfWorkers)
|
|
307
|
-
let groupCounter = 0
|
|
314
|
+
const groups = populateGroups(numberOfWorkers)
|
|
315
|
+
let groupCounter = 0
|
|
308
316
|
|
|
309
|
-
mocha.suite.eachTest(
|
|
310
|
-
const i = groupCounter % groups.length
|
|
317
|
+
mocha.suite.eachTest(test => {
|
|
318
|
+
const i = groupCounter % groups.length
|
|
311
319
|
if (test) {
|
|
312
|
-
groups[i].push(test.uid)
|
|
313
|
-
groupCounter
|
|
320
|
+
groups[i].push(test.uid)
|
|
321
|
+
groupCounter++
|
|
314
322
|
}
|
|
315
|
-
})
|
|
316
|
-
return groups
|
|
323
|
+
})
|
|
324
|
+
return groups
|
|
317
325
|
}
|
|
318
326
|
|
|
319
327
|
/**
|
|
320
328
|
* @param {Number} numberOfWorkers
|
|
321
329
|
*/
|
|
322
330
|
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(
|
|
331
|
+
const files = this.codecept.testFiles
|
|
332
|
+
const groups = populateGroups(numberOfWorkers)
|
|
333
|
+
|
|
334
|
+
const mocha = Container.mocha()
|
|
335
|
+
mocha.files = files
|
|
336
|
+
mocha.loadFiles()
|
|
337
|
+
mocha.suite.suites.forEach(suite => {
|
|
338
|
+
const i = indexOfSmallestElement(groups)
|
|
339
|
+
suite.tests.forEach(test => {
|
|
332
340
|
if (test) {
|
|
333
|
-
groups[i].push(test.uid)
|
|
341
|
+
groups[i].push(test.uid)
|
|
334
342
|
}
|
|
335
|
-
})
|
|
336
|
-
})
|
|
337
|
-
return groups
|
|
343
|
+
})
|
|
344
|
+
})
|
|
345
|
+
return groups
|
|
338
346
|
}
|
|
339
347
|
|
|
340
348
|
/**
|
|
@@ -342,160 +350,156 @@ class Workers extends EventEmitter {
|
|
|
342
350
|
*/
|
|
343
351
|
overrideConfig(config) {
|
|
344
352
|
for (const worker of this.workers) {
|
|
345
|
-
worker.addConfig(config)
|
|
353
|
+
worker.addConfig(config)
|
|
346
354
|
}
|
|
347
355
|
}
|
|
348
356
|
|
|
349
357
|
async bootstrapAll() {
|
|
350
|
-
return runHook(this.codecept.config.bootstrapAll, 'bootstrapAll')
|
|
358
|
+
return runHook(this.codecept.config.bootstrapAll, 'bootstrapAll')
|
|
351
359
|
}
|
|
352
360
|
|
|
353
361
|
async teardownAll() {
|
|
354
|
-
return runHook(this.codecept.config.teardownAll, 'teardownAll')
|
|
362
|
+
return runHook(this.codecept.config.teardownAll, 'teardownAll')
|
|
355
363
|
}
|
|
356
364
|
|
|
357
365
|
run() {
|
|
358
|
-
this.stats.start = new Date()
|
|
366
|
+
this.stats.start = new Date()
|
|
359
367
|
this.stats.failedHooks = 0
|
|
360
|
-
recorder.startUnlessRunning()
|
|
361
|
-
event.dispatcher.emit(event.workers.before)
|
|
362
|
-
process.env.RUNS_WITH_WORKERS = 'true'
|
|
368
|
+
recorder.startUnlessRunning()
|
|
369
|
+
event.dispatcher.emit(event.workers.before)
|
|
370
|
+
process.env.RUNS_WITH_WORKERS = 'true'
|
|
363
371
|
recorder.add('starting workers', () => {
|
|
364
372
|
for (const worker of this.workers) {
|
|
365
|
-
const workerThread = createWorker(worker)
|
|
366
|
-
this._listenWorkerEvents(workerThread)
|
|
373
|
+
const workerThread = createWorker(worker)
|
|
374
|
+
this._listenWorkerEvents(workerThread)
|
|
367
375
|
}
|
|
368
|
-
})
|
|
376
|
+
})
|
|
369
377
|
return new Promise(resolve => {
|
|
370
|
-
this.on('end', resolve)
|
|
371
|
-
})
|
|
378
|
+
this.on('end', resolve)
|
|
379
|
+
})
|
|
372
380
|
}
|
|
373
381
|
|
|
374
382
|
/**
|
|
375
383
|
* @returns {Array<WorkerObject>}
|
|
376
384
|
*/
|
|
377
385
|
getWorkers() {
|
|
378
|
-
return this.workers
|
|
386
|
+
return this.workers
|
|
379
387
|
}
|
|
380
388
|
|
|
381
389
|
/**
|
|
382
390
|
* @returns {Boolean}
|
|
383
391
|
*/
|
|
384
392
|
isFailed() {
|
|
385
|
-
return (this.stats.failures || this.errors.length) > 0
|
|
393
|
+
return (this.stats.failures || this.errors.length) > 0
|
|
386
394
|
}
|
|
387
395
|
|
|
388
396
|
_listenWorkerEvents(worker) {
|
|
389
|
-
worker.on('message',
|
|
390
|
-
output.process(message.workerIndex)
|
|
397
|
+
worker.on('message', message => {
|
|
398
|
+
output.process(message.workerIndex)
|
|
391
399
|
|
|
392
400
|
// deal with events that are not test cycle related
|
|
393
401
|
if (!message.event) {
|
|
394
|
-
return this.emit('message', message)
|
|
402
|
+
return this.emit('message', message)
|
|
395
403
|
}
|
|
396
404
|
|
|
397
405
|
switch (message.event) {
|
|
398
406
|
case event.all.failures:
|
|
399
|
-
this.failuresLog = this.failuresLog.concat(message.data.failuresLog)
|
|
400
|
-
this._appendStats(message.data.stats)
|
|
401
|
-
break
|
|
407
|
+
this.failuresLog = this.failuresLog.concat(message.data.failuresLog)
|
|
408
|
+
this._appendStats(message.data.stats)
|
|
409
|
+
break
|
|
402
410
|
case event.suite.before:
|
|
403
|
-
this.emit(event.suite.before, repackTest(message.data))
|
|
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;
|
|
411
|
+
this.emit(event.suite.before, repackTest(message.data))
|
|
412
|
+
break
|
|
409
413
|
case event.test.before:
|
|
410
|
-
this.emit(event.test.before, repackTest(message.data))
|
|
411
|
-
break
|
|
414
|
+
this.emit(event.test.before, repackTest(message.data))
|
|
415
|
+
break
|
|
412
416
|
case event.test.started:
|
|
413
|
-
this.emit(event.test.started, repackTest(message.data))
|
|
414
|
-
break
|
|
417
|
+
this.emit(event.test.started, repackTest(message.data))
|
|
418
|
+
break
|
|
415
419
|
case event.test.failed:
|
|
416
|
-
this.emit(event.test.failed, repackTest(message.data))
|
|
417
|
-
break
|
|
420
|
+
this.emit(event.test.failed, repackTest(message.data))
|
|
421
|
+
break
|
|
418
422
|
case event.test.passed:
|
|
419
|
-
this.emit(event.test.passed, repackTest(message.data))
|
|
420
|
-
break
|
|
423
|
+
this.emit(event.test.passed, repackTest(message.data))
|
|
424
|
+
break
|
|
421
425
|
case event.test.skipped:
|
|
422
|
-
this.emit(event.test.skipped, repackTest(message.data))
|
|
423
|
-
break
|
|
426
|
+
this.emit(event.test.skipped, repackTest(message.data))
|
|
427
|
+
break
|
|
424
428
|
case event.test.finished:
|
|
425
|
-
this.emit(event.test.finished, repackTest(message.data))
|
|
426
|
-
break
|
|
429
|
+
this.emit(event.test.finished, repackTest(message.data))
|
|
430
|
+
break
|
|
427
431
|
case event.test.after:
|
|
428
|
-
this.emit(event.test.after, repackTest(message.data))
|
|
429
|
-
break
|
|
432
|
+
this.emit(event.test.after, repackTest(message.data))
|
|
433
|
+
break
|
|
430
434
|
case event.step.finished:
|
|
431
|
-
this.emit(event.step.finished, message.data)
|
|
432
|
-
break
|
|
435
|
+
this.emit(event.step.finished, message.data)
|
|
436
|
+
break
|
|
433
437
|
case event.step.started:
|
|
434
|
-
this.emit(event.step.started, message.data)
|
|
435
|
-
break
|
|
438
|
+
this.emit(event.step.started, message.data)
|
|
439
|
+
break
|
|
436
440
|
case event.step.passed:
|
|
437
|
-
this.emit(event.step.passed, message.data)
|
|
438
|
-
break
|
|
441
|
+
this.emit(event.step.passed, message.data)
|
|
442
|
+
break
|
|
439
443
|
case event.step.failed:
|
|
440
|
-
this.emit(event.step.failed, message.data)
|
|
441
|
-
break
|
|
444
|
+
this.emit(event.step.failed, message.data)
|
|
445
|
+
break
|
|
442
446
|
}
|
|
443
|
-
})
|
|
447
|
+
})
|
|
444
448
|
|
|
445
|
-
worker.on('error',
|
|
446
|
-
this.errors.push(err)
|
|
447
|
-
})
|
|
449
|
+
worker.on('error', err => {
|
|
450
|
+
this.errors.push(err)
|
|
451
|
+
})
|
|
448
452
|
|
|
449
453
|
worker.on('exit', () => {
|
|
450
|
-
this.closedWorkers += 1
|
|
454
|
+
this.closedWorkers += 1
|
|
451
455
|
if (this.closedWorkers === this.numberOfWorkers) {
|
|
452
|
-
this._finishRun()
|
|
456
|
+
this._finishRun()
|
|
453
457
|
}
|
|
454
|
-
})
|
|
458
|
+
})
|
|
455
459
|
}
|
|
456
460
|
|
|
457
461
|
_finishRun() {
|
|
458
|
-
event.dispatcher.emit(event.workers.after)
|
|
462
|
+
event.dispatcher.emit(event.workers.after)
|
|
459
463
|
if (this.isFailed()) {
|
|
460
|
-
process.exitCode = 1
|
|
464
|
+
process.exitCode = 1
|
|
461
465
|
} else {
|
|
462
|
-
process.exitCode = 0
|
|
466
|
+
process.exitCode = 0
|
|
463
467
|
}
|
|
464
468
|
// 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')
|
|
469
|
+
this.emit(event.all.result, !this.isFailed())
|
|
470
|
+
this.emit('end') // internal event
|
|
467
471
|
}
|
|
468
472
|
|
|
469
473
|
_appendStats(newStats) {
|
|
470
|
-
this.stats.passes += newStats.passes
|
|
471
|
-
this.stats.failures += newStats.failures
|
|
472
|
-
this.stats.tests += newStats.tests
|
|
473
|
-
this.stats.pending += newStats.pending
|
|
474
|
-
this.stats.failedHooks += newStats.failedHooks
|
|
474
|
+
this.stats.passes += newStats.passes
|
|
475
|
+
this.stats.failures += newStats.failures
|
|
476
|
+
this.stats.tests += newStats.tests
|
|
477
|
+
this.stats.pending += newStats.pending
|
|
478
|
+
this.stats.failedHooks += newStats.failedHooks
|
|
475
479
|
}
|
|
476
480
|
|
|
477
481
|
printResults() {
|
|
478
|
-
this.stats.end = new Date()
|
|
479
|
-
this.stats.duration = this.stats.end - this.stats.start
|
|
482
|
+
this.stats.end = new Date()
|
|
483
|
+
this.stats.duration = this.stats.end - this.stats.start
|
|
480
484
|
|
|
481
485
|
// Reset process for logs in main thread
|
|
482
|
-
output.process(null)
|
|
483
|
-
output.print()
|
|
486
|
+
output.process(null)
|
|
487
|
+
output.print()
|
|
484
488
|
|
|
485
489
|
this.failuresLog = this.failuresLog
|
|
486
490
|
.filter(log => log.length && typeof log[1] === 'number')
|
|
487
491
|
// mocha/lib/reporters/base.js
|
|
488
|
-
.map(([format, num, title, message, stack], i) => [format, i + 1, title, message, stack])
|
|
492
|
+
.map(([format, num, title, message, stack], i) => [format, i + 1, title, message, stack])
|
|
489
493
|
|
|
490
494
|
if (this.failuresLog.length) {
|
|
491
|
-
output.print()
|
|
492
|
-
output.print('-- FAILURES:')
|
|
493
|
-
this.failuresLog.forEach(log => output.print(...log))
|
|
495
|
+
output.print()
|
|
496
|
+
output.print('-- FAILURES:')
|
|
497
|
+
this.failuresLog.forEach(log => output.print(...log))
|
|
494
498
|
}
|
|
495
499
|
|
|
496
|
-
output.result(this.stats.passes, this.stats.failures, this.stats.pending, ms(this.stats.duration), this.stats.failedHooks)
|
|
497
|
-
process.env.RUNS_WITH_WORKERS = 'false'
|
|
500
|
+
output.result(this.stats.passes, this.stats.failures, this.stats.pending, ms(this.stats.duration), this.stats.failedHooks)
|
|
501
|
+
process.env.RUNS_WITH_WORKERS = 'false'
|
|
498
502
|
}
|
|
499
503
|
}
|
|
500
504
|
|
|
501
|
-
module.exports = Workers
|
|
505
|
+
module.exports = Workers
|