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.
Files changed (127) hide show
  1. package/README.md +89 -119
  2. package/bin/codecept.js +9 -2
  3. package/docs/webapi/clearCookie.mustache +1 -1
  4. package/lib/actor.js +66 -102
  5. package/lib/ai.js +130 -121
  6. package/lib/assert/empty.js +3 -5
  7. package/lib/assert/equal.js +4 -7
  8. package/lib/assert/include.js +4 -6
  9. package/lib/assert/throws.js +2 -4
  10. package/lib/assert/truth.js +2 -2
  11. package/lib/codecept.js +87 -83
  12. package/lib/command/check.js +186 -0
  13. package/lib/command/configMigrate.js +2 -4
  14. package/lib/command/definitions.js +8 -26
  15. package/lib/command/generate.js +10 -14
  16. package/lib/command/gherkin/snippets.js +10 -8
  17. package/lib/command/gherkin/steps.js +1 -1
  18. package/lib/command/info.js +1 -3
  19. package/lib/command/init.js +8 -12
  20. package/lib/command/interactive.js +2 -2
  21. package/lib/command/list.js +1 -1
  22. package/lib/command/run-multiple.js +12 -35
  23. package/lib/command/run-workers.js +5 -57
  24. package/lib/command/utils.js +5 -6
  25. package/lib/command/workers/runTests.js +68 -232
  26. package/lib/container.js +354 -237
  27. package/lib/data/context.js +10 -13
  28. package/lib/data/dataScenarioConfig.js +8 -8
  29. package/lib/data/dataTableArgument.js +6 -6
  30. package/lib/data/table.js +5 -11
  31. package/lib/effects.js +218 -0
  32. package/lib/els.js +158 -0
  33. package/lib/event.js +19 -17
  34. package/lib/heal.js +88 -80
  35. package/lib/helper/AI.js +2 -1
  36. package/lib/helper/ApiDataFactory.js +3 -6
  37. package/lib/helper/Appium.js +45 -51
  38. package/lib/helper/FileSystem.js +3 -3
  39. package/lib/helper/GraphQLDataFactory.js +3 -3
  40. package/lib/helper/JSONResponse.js +57 -37
  41. package/lib/helper/Nightmare.js +35 -53
  42. package/lib/helper/Playwright.js +211 -252
  43. package/lib/helper/Protractor.js +54 -77
  44. package/lib/helper/Puppeteer.js +139 -232
  45. package/lib/helper/REST.js +5 -17
  46. package/lib/helper/TestCafe.js +21 -44
  47. package/lib/helper/WebDriver.js +131 -169
  48. package/lib/helper/testcafe/testcafe-utils.js +26 -27
  49. package/lib/listener/emptyRun.js +55 -0
  50. package/lib/listener/exit.js +7 -10
  51. package/lib/listener/{retry.js → globalRetry.js} +5 -5
  52. package/lib/listener/globalTimeout.js +165 -0
  53. package/lib/listener/helpers.js +15 -15
  54. package/lib/listener/mocha.js +1 -1
  55. package/lib/listener/result.js +12 -0
  56. package/lib/listener/steps.js +20 -18
  57. package/lib/listener/store.js +20 -0
  58. package/lib/mocha/asyncWrapper.js +216 -0
  59. package/lib/{interfaces → mocha}/bdd.js +3 -3
  60. package/lib/mocha/cli.js +308 -0
  61. package/lib/mocha/factory.js +104 -0
  62. package/lib/{interfaces → mocha}/featureConfig.js +24 -12
  63. package/lib/{interfaces → mocha}/gherkin.js +26 -28
  64. package/lib/mocha/hooks.js +112 -0
  65. package/lib/mocha/index.js +12 -0
  66. package/lib/mocha/inject.js +29 -0
  67. package/lib/{interfaces → mocha}/scenarioConfig.js +21 -6
  68. package/lib/mocha/suite.js +81 -0
  69. package/lib/mocha/test.js +159 -0
  70. package/lib/mocha/types.d.ts +42 -0
  71. package/lib/mocha/ui.js +219 -0
  72. package/lib/output.js +82 -62
  73. package/lib/pause.js +155 -138
  74. package/lib/plugin/analyze.js +349 -0
  75. package/lib/plugin/autoDelay.js +6 -6
  76. package/lib/plugin/autoLogin.js +6 -7
  77. package/lib/plugin/commentStep.js +6 -1
  78. package/lib/plugin/coverage.js +10 -19
  79. package/lib/plugin/customLocator.js +3 -3
  80. package/lib/plugin/customReporter.js +52 -0
  81. package/lib/plugin/eachElement.js +1 -1
  82. package/lib/plugin/fakerTransform.js +1 -1
  83. package/lib/plugin/heal.js +36 -9
  84. package/lib/plugin/pageInfo.js +140 -0
  85. package/lib/plugin/retryFailedStep.js +4 -4
  86. package/lib/plugin/retryTo.js +18 -118
  87. package/lib/plugin/screenshotOnFail.js +17 -49
  88. package/lib/plugin/selenoid.js +15 -35
  89. package/lib/plugin/standardActingHelpers.js +4 -1
  90. package/lib/plugin/stepByStepReport.js +56 -17
  91. package/lib/plugin/stepTimeout.js +5 -12
  92. package/lib/plugin/subtitles.js +4 -4
  93. package/lib/plugin/tryTo.js +17 -107
  94. package/lib/plugin/wdio.js +8 -10
  95. package/lib/recorder.js +146 -125
  96. package/lib/rerun.js +43 -42
  97. package/lib/result.js +161 -0
  98. package/lib/secret.js +1 -1
  99. package/lib/step/base.js +228 -0
  100. package/lib/step/config.js +50 -0
  101. package/lib/step/func.js +46 -0
  102. package/lib/step/helper.js +50 -0
  103. package/lib/step/meta.js +99 -0
  104. package/lib/step/record.js +74 -0
  105. package/lib/step/retry.js +11 -0
  106. package/lib/step/section.js +55 -0
  107. package/lib/step.js +21 -332
  108. package/lib/steps.js +50 -0
  109. package/lib/store.js +10 -2
  110. package/lib/template/heal.js +2 -11
  111. package/lib/timeout.js +66 -0
  112. package/lib/utils.js +317 -216
  113. package/lib/within.js +73 -55
  114. package/lib/workers.js +259 -275
  115. package/package.json +56 -54
  116. package/typings/index.d.ts +175 -186
  117. package/typings/promiseBasedTypes.d.ts +164 -17
  118. package/typings/types.d.ts +284 -115
  119. package/lib/cli.js +0 -256
  120. package/lib/helper/ExpectHelper.js +0 -391
  121. package/lib/helper/SoftExpectHelper.js +0 -381
  122. package/lib/listener/artifacts.js +0 -19
  123. package/lib/listener/timeout.js +0 -109
  124. package/lib/mochaFactory.js +0 -113
  125. package/lib/plugin/debugErrors.js +0 -67
  126. package/lib/scenario.js +0 -224
  127. 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 { Suite, Test, reporters: { Base } } = require('mocha');
5
- const { EventEmitter } = require('events');
6
- const ms = require('ms');
7
- const Codecept = require('./codecept');
8
- const MochaFactory = require('./mochaFactory');
9
- const Container = require('./container');
10
- const { getTestRoot } = require('./command/utils');
11
- const { isFunction, fileExists } = require('./utils');
12
- const { replaceValueDeep, deepClone } = require('./utils');
13
- const mainConfig = require('./config');
14
- const output = require('./output');
15
- const event = require('./event');
16
- const recorder = require('./recorder');
17
- const runHook = require('./hooks');
18
- const WorkerStorage = require('./workerStorage');
19
- const collection = require('./command/run-multiple/collection');
20
-
21
- 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')
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 = (configPath) => {
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 = (numberOfWorkers) => {
43
- const groups = [];
43
+ const populateGroups = numberOfWorkers => {
44
+ const groups = []
44
45
  for (let i = 0; i < numberOfWorkers; i++) {
45
- groups[i] = [];
46
+ groups[i] = []
46
47
  }
47
48
 
48
- return groups;
49
- };
49
+ return groups
50
+ }
50
51
 
51
- const createWorker = (workerObject) => {
52
+ const createWorker = workerObject => {
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 = (object) => {
67
+ const simplifyObject = object => {
67
68
  return Object.keys(object)
68
- .filter((k) => k.indexOf('_') !== 0)
69
- .filter((k) => typeof object[k] !== 'function')
70
- .filter((k) => typeof object[k] !== 'object')
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((worker) => {
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(_tempArray.findIndex(item => item.includes('.xml')), 0, workerName);
116
- _config.mocha.reporterOptions['mocha-junit-reporter'].options.mochaFile = _tempArray.join(separator);
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((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;
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 = (testGroup) => {
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((test) => {
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.failuresLog = [];
236
- this.errors = [];
237
- this.numberOfWorkers = 0;
238
- this.closedWorkers = 0;
239
- this.workers = [];
240
- this.stats = {
241
- passes: 0,
242
- failures: 0,
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((test) => {
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((suite) => {
330
- const i = indexOfSmallestElement(groups);
331
- suite.tests.forEach((test) => {
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
- this.stats.start = new Date();
359
- this.stats.failedHooks = 0
360
- recorder.startUnlessRunning();
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 (this.stats.failures || this.errors.length) > 0;
375
+ return (Container.result().failures.length || this.errors.length) > 0
386
376
  }
387
377
 
388
378
  _listenWorkerEvents(worker) {
389
- worker.on('message', (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.failures:
399
- this.failuresLog = this.failuresLog.concat(message.data.failuresLog);
400
- this._appendStats(message.data.stats);
401
- break;
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, 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;
397
+ this.emit(event.suite.before, deserializeSuite(message.data))
398
+ break
409
399
  case event.test.before:
410
- this.emit(event.test.before, repackTest(message.data));
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, repackTest(message.data));
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, repackTest(message.data));
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, repackTest(message.data));
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, repackTest(message.data));
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, repackTest(message.data));
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, repackTest(message.data));
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', (err) => {
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 (this.isFailed()) {
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
- _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;
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
- this.stats.end = new Date();
479
- this.stats.duration = this.stats.end - this.stats.start;
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 = 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(this.stats.passes, this.stats.failures, this.stats.pending, ms(this.stats.duration), this.stats.failedHooks);
497
- process.env.RUNS_WITH_WORKERS = 'false';
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