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