codeceptjs 4.0.0-beta.1 → 4.0.0-beta.11.esm-aria

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 (207) hide show
  1. package/README.md +133 -120
  2. package/bin/codecept.js +107 -96
  3. package/bin/test-server.js +64 -0
  4. package/docs/webapi/clearCookie.mustache +1 -1
  5. package/docs/webapi/click.mustache +5 -1
  6. package/lib/actor.js +71 -103
  7. package/lib/ai.js +159 -188
  8. package/lib/assert/empty.js +22 -24
  9. package/lib/assert/equal.js +30 -37
  10. package/lib/assert/error.js +14 -14
  11. package/lib/assert/include.js +43 -48
  12. package/lib/assert/throws.js +11 -11
  13. package/lib/assert/truth.js +22 -22
  14. package/lib/assert.js +20 -18
  15. package/lib/codecept.js +238 -162
  16. package/lib/colorUtils.js +50 -52
  17. package/lib/command/check.js +206 -0
  18. package/lib/command/configMigrate.js +56 -51
  19. package/lib/command/definitions.js +96 -109
  20. package/lib/command/dryRun.js +77 -79
  21. package/lib/command/generate.js +234 -194
  22. package/lib/command/gherkin/init.js +42 -33
  23. package/lib/command/gherkin/snippets.js +76 -74
  24. package/lib/command/gherkin/steps.js +20 -17
  25. package/lib/command/info.js +74 -38
  26. package/lib/command/init.js +300 -290
  27. package/lib/command/interactive.js +41 -32
  28. package/lib/command/list.js +28 -27
  29. package/lib/command/run-multiple/chunk.js +51 -48
  30. package/lib/command/run-multiple/collection.js +5 -5
  31. package/lib/command/run-multiple/run.js +5 -1
  32. package/lib/command/run-multiple.js +97 -97
  33. package/lib/command/run-rerun.js +19 -25
  34. package/lib/command/run-workers.js +68 -92
  35. package/lib/command/run.js +39 -27
  36. package/lib/command/utils.js +80 -64
  37. package/lib/command/workers/runTests.js +388 -226
  38. package/lib/config.js +124 -50
  39. package/lib/container.js +765 -260
  40. package/lib/data/context.js +60 -61
  41. package/lib/data/dataScenarioConfig.js +47 -47
  42. package/lib/data/dataTableArgument.js +32 -32
  43. package/lib/data/table.js +22 -22
  44. package/lib/effects.js +307 -0
  45. package/lib/element/WebElement.js +327 -0
  46. package/lib/els.js +160 -0
  47. package/lib/event.js +173 -163
  48. package/lib/globals.js +141 -0
  49. package/lib/heal.js +89 -85
  50. package/lib/helper/AI.js +131 -41
  51. package/lib/helper/ApiDataFactory.js +107 -75
  52. package/lib/helper/Appium.js +542 -404
  53. package/lib/helper/FileSystem.js +100 -79
  54. package/lib/helper/GraphQL.js +44 -43
  55. package/lib/helper/GraphQLDataFactory.js +52 -52
  56. package/lib/helper/JSONResponse.js +126 -88
  57. package/lib/helper/Mochawesome.js +54 -29
  58. package/lib/helper/Playwright.js +2547 -1316
  59. package/lib/helper/Puppeteer.js +1578 -1181
  60. package/lib/helper/REST.js +209 -68
  61. package/lib/helper/WebDriver.js +1482 -1342
  62. package/lib/helper/errors/ConnectionRefused.js +6 -6
  63. package/lib/helper/errors/ElementAssertion.js +11 -16
  64. package/lib/helper/errors/ElementNotFound.js +5 -9
  65. package/lib/helper/errors/RemoteBrowserConnectionRefused.js +5 -5
  66. package/lib/helper/extras/Console.js +11 -11
  67. package/lib/helper/extras/PlaywrightLocator.js +110 -0
  68. package/lib/helper/extras/PlaywrightPropEngine.js +18 -18
  69. package/lib/helper/extras/PlaywrightReactVueLocator.js +17 -8
  70. package/lib/helper/extras/PlaywrightRestartOpts.js +25 -11
  71. package/lib/helper/extras/Popup.js +22 -22
  72. package/lib/helper/extras/React.js +27 -28
  73. package/lib/helper/network/actions.js +36 -42
  74. package/lib/helper/network/utils.js +78 -84
  75. package/lib/helper/scripts/blurElement.js +5 -5
  76. package/lib/helper/scripts/focusElement.js +5 -5
  77. package/lib/helper/scripts/highlightElement.js +8 -8
  78. package/lib/helper/scripts/isElementClickable.js +34 -34
  79. package/lib/helper.js +2 -3
  80. package/lib/history.js +23 -19
  81. package/lib/hooks.js +8 -8
  82. package/lib/html.js +94 -104
  83. package/lib/index.js +38 -27
  84. package/lib/listener/config.js +30 -23
  85. package/lib/listener/emptyRun.js +54 -0
  86. package/lib/listener/enhancedGlobalRetry.js +110 -0
  87. package/lib/listener/exit.js +16 -18
  88. package/lib/listener/globalRetry.js +70 -0
  89. package/lib/listener/globalTimeout.js +181 -0
  90. package/lib/listener/helpers.js +76 -51
  91. package/lib/listener/mocha.js +10 -11
  92. package/lib/listener/result.js +11 -0
  93. package/lib/listener/retryEnhancer.js +85 -0
  94. package/lib/listener/steps.js +71 -59
  95. package/lib/listener/store.js +20 -0
  96. package/lib/locator.js +214 -197
  97. package/lib/mocha/asyncWrapper.js +274 -0
  98. package/lib/mocha/bdd.js +167 -0
  99. package/lib/mocha/cli.js +341 -0
  100. package/lib/mocha/factory.js +163 -0
  101. package/lib/mocha/featureConfig.js +89 -0
  102. package/lib/mocha/gherkin.js +231 -0
  103. package/lib/mocha/hooks.js +121 -0
  104. package/lib/mocha/index.js +21 -0
  105. package/lib/mocha/inject.js +46 -0
  106. package/lib/{interfaces → mocha}/scenarioConfig.js +58 -34
  107. package/lib/mocha/suite.js +89 -0
  108. package/lib/mocha/test.js +184 -0
  109. package/lib/mocha/types.d.ts +42 -0
  110. package/lib/mocha/ui.js +242 -0
  111. package/lib/output.js +141 -71
  112. package/lib/parser.js +47 -44
  113. package/lib/pause.js +173 -145
  114. package/lib/plugin/analyze.js +403 -0
  115. package/lib/plugin/{autoLogin.js → auth.js} +178 -79
  116. package/lib/plugin/autoDelay.js +36 -40
  117. package/lib/plugin/coverage.js +131 -78
  118. package/lib/plugin/customLocator.js +22 -21
  119. package/lib/plugin/customReporter.js +53 -0
  120. package/lib/plugin/enhancedRetryFailedStep.js +99 -0
  121. package/lib/plugin/heal.js +101 -110
  122. package/lib/plugin/htmlReporter.js +3648 -0
  123. package/lib/plugin/pageInfo.js +140 -0
  124. package/lib/plugin/pauseOnFail.js +12 -11
  125. package/lib/plugin/retryFailedStep.js +82 -47
  126. package/lib/plugin/screenshotOnFail.js +111 -92
  127. package/lib/plugin/stepByStepReport.js +159 -101
  128. package/lib/plugin/stepTimeout.js +20 -25
  129. package/lib/plugin/subtitles.js +38 -38
  130. package/lib/recorder.js +193 -130
  131. package/lib/rerun.js +94 -49
  132. package/lib/result.js +238 -0
  133. package/lib/retryCoordinator.js +207 -0
  134. package/lib/secret.js +20 -18
  135. package/lib/session.js +95 -89
  136. package/lib/step/base.js +239 -0
  137. package/lib/step/comment.js +10 -0
  138. package/lib/step/config.js +50 -0
  139. package/lib/step/func.js +46 -0
  140. package/lib/step/helper.js +50 -0
  141. package/lib/step/meta.js +99 -0
  142. package/lib/step/record.js +74 -0
  143. package/lib/step/retry.js +11 -0
  144. package/lib/step/section.js +55 -0
  145. package/lib/step.js +18 -329
  146. package/lib/steps.js +54 -0
  147. package/lib/store.js +38 -7
  148. package/lib/template/heal.js +3 -12
  149. package/lib/template/prompts/generatePageObject.js +31 -0
  150. package/lib/template/prompts/healStep.js +13 -0
  151. package/lib/template/prompts/writeStep.js +9 -0
  152. package/lib/test-server.js +334 -0
  153. package/lib/timeout.js +60 -0
  154. package/lib/transform.js +8 -8
  155. package/lib/translation.js +34 -21
  156. package/lib/utils/mask_data.js +47 -0
  157. package/lib/utils.js +411 -228
  158. package/lib/workerStorage.js +37 -34
  159. package/lib/workers.js +532 -296
  160. package/package.json +115 -95
  161. package/translations/de-DE.js +5 -3
  162. package/translations/fr-FR.js +5 -4
  163. package/translations/index.js +22 -12
  164. package/translations/it-IT.js +4 -3
  165. package/translations/ja-JP.js +4 -3
  166. package/translations/nl-NL.js +76 -0
  167. package/translations/pl-PL.js +4 -3
  168. package/translations/pt-BR.js +4 -3
  169. package/translations/ru-RU.js +4 -3
  170. package/translations/utils.js +10 -0
  171. package/translations/zh-CN.js +4 -3
  172. package/translations/zh-TW.js +4 -3
  173. package/typings/index.d.ts +546 -185
  174. package/typings/promiseBasedTypes.d.ts +150 -879
  175. package/typings/types.d.ts +547 -996
  176. package/lib/cli.js +0 -249
  177. package/lib/dirname.js +0 -5
  178. package/lib/helper/Expect.js +0 -425
  179. package/lib/helper/ExpectHelper.js +0 -399
  180. package/lib/helper/MockServer.js +0 -223
  181. package/lib/helper/Nightmare.js +0 -1411
  182. package/lib/helper/Protractor.js +0 -1835
  183. package/lib/helper/SoftExpectHelper.js +0 -381
  184. package/lib/helper/TestCafe.js +0 -1410
  185. package/lib/helper/clientscripts/nightmare.js +0 -213
  186. package/lib/helper/testcafe/testControllerHolder.js +0 -42
  187. package/lib/helper/testcafe/testcafe-utils.js +0 -63
  188. package/lib/interfaces/bdd.js +0 -98
  189. package/lib/interfaces/featureConfig.js +0 -69
  190. package/lib/interfaces/gherkin.js +0 -195
  191. package/lib/listener/artifacts.js +0 -19
  192. package/lib/listener/retry.js +0 -68
  193. package/lib/listener/timeout.js +0 -109
  194. package/lib/mochaFactory.js +0 -110
  195. package/lib/plugin/allure.js +0 -15
  196. package/lib/plugin/commentStep.js +0 -136
  197. package/lib/plugin/debugErrors.js +0 -67
  198. package/lib/plugin/eachElement.js +0 -127
  199. package/lib/plugin/fakerTransform.js +0 -49
  200. package/lib/plugin/retryTo.js +0 -121
  201. package/lib/plugin/selenoid.js +0 -371
  202. package/lib/plugin/standardActingHelpers.js +0 -9
  203. package/lib/plugin/tryTo.js +0 -105
  204. package/lib/plugin/wdio.js +0 -246
  205. package/lib/scenario.js +0 -222
  206. package/lib/ui.js +0 -238
  207. package/lib/within.js +0 -70
@@ -1,55 +1,64 @@
1
- import { getConfig, getTestRoot } from './utils.js';
2
- import recorder from '../recorder.js';
3
- import Codecept from '../codecept.js';
4
- import Container from '../container.js';
5
- import * as event from '../event.js';
6
- import * as output from '../output.js';
7
- import webHelpers from '../plugin/standardActingHelpers.js';
1
+ import { getConfig, getTestRoot } from './utils.js'
2
+ import recorder from '../recorder.js'
3
+ import Codecept from '../codecept.js'
4
+ import Container from '../container.js'
5
+ import event from '../event.js'
6
+ import pause from '../pause.js'
7
+ import output from '../output.js'
8
+ const webHelpers = Container.STANDARD_ACTING_HELPERS
8
9
 
9
10
  export default async function (path, options) {
10
11
  // Backward compatibility for --profile
11
- process.profile = options.profile;
12
- process.env.profile = options.profile;
13
- const configFile = options.config;
12
+ process.profile = options.profile
13
+ process.env.profile = options.profile
14
+ const configFile = options.config
14
15
 
15
- const config = getConfig(configFile);
16
- const testsPath = getTestRoot(configFile);
16
+ const config = await getConfig(configFile)
17
+ const testsPath = getTestRoot(configFile)
17
18
 
18
- const codecept = new Codecept(config, options);
19
- codecept.init(testsPath);
19
+ const codecept = new Codecept(config, options)
20
+ codecept.init(testsPath)
20
21
 
21
22
  try {
22
- await codecept.bootstrap();
23
+ await codecept.bootstrap()
24
+ await Container.started()
23
25
 
24
- if (options.verbose) output.level(3);
26
+ if (options.verbose) output.level(3)
25
27
 
26
- output.print('Starting interactive shell for current suite...');
27
- recorder.start();
28
+ let addGlobalRetries
29
+
30
+ if (config.retry) {
31
+ addGlobalRetries = function retries() {}
32
+ }
33
+
34
+ output.print('Starting interactive shell for current suite...')
35
+ recorder.start()
28
36
  event.emit(event.suite.before, {
29
37
  fullTitle: () => 'Interactive Shell',
30
38
  tests: [],
31
- });
39
+ retries: addGlobalRetries,
40
+ })
32
41
  event.emit(event.test.before, {
33
42
  title: '',
34
43
  artifacts: {},
35
- });
44
+ retries: addGlobalRetries,
45
+ })
36
46
 
37
- const enabledHelpers = Container.helpers();
47
+ const enabledHelpers = Container.helpers()
38
48
  for (const helperName of Object.keys(enabledHelpers)) {
39
49
  if (webHelpers.includes(helperName)) {
40
- const I = enabledHelpers[helperName];
41
- recorder.add(() => I.amOnPage('/'));
42
- recorder.catchWithoutStop(e => output.print(`Error while loading home page: ${e.message}}`));
43
- break;
50
+ const I = enabledHelpers[helperName]
51
+ recorder.add(() => I.amOnPage('/'))
52
+ recorder.catchWithoutStop(e => output.print(`Error while loading home page: ${e.message}}`))
53
+ break
44
54
  }
45
55
  }
46
- require('../pause')();
47
- // recorder.catchWithoutStop((err) => console.log(err.stack));
48
- recorder.add(() => event.emit(event.test.after, {}));
49
- recorder.add(() => event.emit(event.suite.after, {}));
50
- recorder.add(() => event.emit(event.all.result, {}));
51
- recorder.add(() => codecept.teardown());
56
+ pause()
57
+ recorder.add(() => event.emit(event.test.after, {}))
58
+ recorder.add(() => event.emit(event.suite.after, {}))
59
+ recorder.add(() => event.emit(event.all.result, {}))
60
+ recorder.add(() => codecept.teardown())
52
61
  } catch (err) {
53
- output.output.error(`Error while running bootstrap file :${err}`);
62
+ output.error(`Error while running bootstrap file :${err}`)
54
63
  }
55
64
  }
@@ -1,36 +1,37 @@
1
- import { getConfig, getTestRoot } from './utils.js';
2
- import Codecept from '../codecept.js';
3
- import container from '../container.js';
4
- import { getParamsToString } from '../parser.js';
5
- import { methodsOfObject } from '../utils.js';
6
- import * as output from '../output.js';
1
+ import { getConfig, getTestRoot } from './utils.js'
2
+ import Codecept from '../codecept.js'
3
+ import container from '../container.js'
4
+ import { getParamsToString } from '../parser.js'
5
+ import { methodsOfObject } from '../utils.js'
6
+ import output from '../output.js'
7
7
 
8
- export default function (path) {
9
- const testsPath = getTestRoot(path);
10
- const config = getConfig(testsPath);
11
- const codecept = new Codecept(config, {});
12
- codecept.init(testsPath);
8
+ export default async function (path) {
9
+ const testsPath = getTestRoot(path)
10
+ const config = await getConfig(testsPath)
11
+ const codecept = new Codecept(config, {})
12
+ await codecept.init(testsPath)
13
+ await container.started()
13
14
 
14
- output.print('List of test actions: -- ');
15
- const helpers = container.helpers();
16
- const supportI = container.support('I');
17
- const actions = [];
15
+ output.print('List of test actions: -- ')
16
+ const helpers = container.helpers()
17
+ const supportI = container.support('I')
18
+ const actions = []
18
19
  for (const name in helpers) {
19
- const helper = helpers[name];
20
- methodsOfObject(helper).forEach((action) => {
21
- const params = getParamsToString(helper[action]);
22
- actions[action] = 1;
23
- output.print(` ${output.output.colors.grey(name)} I.${output.output.colors.bold(action)}(${params})`);
24
- });
20
+ const helper = helpers[name]
21
+ methodsOfObject(helper).forEach(action => {
22
+ const params = getParamsToString(helper[action])
23
+ actions[action] = 1
24
+ output.print(` ${output.colors.grey(name)} I.${output.colors.bold(action)}(${params})`)
25
+ })
25
26
  }
26
27
  for (const name in supportI) {
27
28
  if (actions[name]) {
28
- continue;
29
+ continue
29
30
  }
30
- const actor = supportI[name];
31
- const params = getParamsToString(actor);
32
- output.print(` I.${output.output.colors.bold(name)}(${params})`);
31
+ const actor = supportI[name]
32
+ const params = getParamsToString(actor)
33
+ output.print(` I.${output.colors.bold(name)}(${params})`)
33
34
  }
34
- output.print('PS: Actions are retrieved from enabled helpers. ');
35
- output.print('Implement custom actions in your helper classes.');
35
+ output.print('PS: Actions are retrieved from enabled helpers. ')
36
+ output.print('Implement custom actions in your helper classes.')
36
37
  }
@@ -1,91 +1,94 @@
1
- import glob from 'glob';
2
- import path from 'path';
3
- import fs from 'fs';
1
+ import { globSync } from 'glob'
2
+ import path from 'path'
3
+ import fs from 'fs'
4
4
 
5
5
  /**
6
6
  * Splits a list to (n) parts, defined via the size argument.
7
7
  */
8
8
  const splitFiles = (list, size) => {
9
- const sets = [];
10
- const chunks = list.length / size;
11
- let i = 0;
9
+ const sets = []
10
+ const chunks = list.length / size
11
+ let i = 0
12
12
 
13
13
  while (i < chunks) {
14
- sets[i] = list.splice(0, size);
15
- i++;
14
+ sets[i] = list.splice(0, size)
15
+ i++
16
16
  }
17
17
 
18
- return sets;
19
- };
18
+ return sets
19
+ }
20
20
 
21
21
  /**
22
22
  * Executes a glob pattern and pushes the results to a list.
23
23
  */
24
- const findFiles = (pattern) => {
25
- const files = [];
24
+ const findFiles = pattern => {
25
+ const files = []
26
26
 
27
- glob.sync(pattern).forEach((file) => {
28
- files.push(path.resolve(file));
29
- });
27
+ globSync(pattern).forEach(file => {
28
+ files.push(path.resolve(file))
29
+ })
30
30
 
31
- return files;
32
- };
31
+ return files
32
+ }
33
33
 
34
34
  /**
35
35
  * Joins a list of files to a valid glob pattern
36
36
  */
37
- const flattenFiles = (list) => {
38
- const pattern = list.join(',');
39
- return pattern.indexOf(',') > -1 ? `{${pattern}}` : pattern;
40
- };
37
+ const flattenFiles = list => {
38
+ const pattern = list.join(',')
39
+ return pattern.indexOf(',') > -1 ? `{${pattern}}` : pattern
40
+ }
41
41
 
42
42
  /**
43
43
  * Greps a file by its content, checks if Scenario or Feature text'
44
44
  * matches the grep text.
45
45
  */
46
46
  const grepFile = (file, grep) => {
47
- const contents = fs.readFileSync(file, 'utf8');
48
- const pattern = new RegExp(`((Scenario|Feature)\(.*${grep}.*\))`, 'g'); // <- How future proof/solid is this?
49
- return !!pattern.exec(contents);
50
- };
47
+ const contents = fs.readFileSync(file, 'utf8')
48
+ const pattern = new RegExp(`((Scenario|Feature)\(.*${grep}.*\))`, 'g') // <- How future proof/solid is this?
49
+ return !!pattern.exec(contents)
50
+ }
51
51
 
52
- const mapFileFormats = (files) => {
52
+ const mapFileFormats = files => {
53
53
  return {
54
54
  gherkin: files.filter(file => file.match(/\.feature$/)),
55
55
  js: files.filter(file => file.match(/\.t|js$/)),
56
- };
57
- };
56
+ }
57
+ }
58
58
 
59
59
  /**
60
60
  * Creates a list of chunks incl. configuration by either dividing a list of scenario
61
61
  * files by the passed number or executing a usder deifned function to perform
62
62
  * the splitting.
63
63
  */
64
- export const createChunks = (config, patterns = []) => {
65
- const files = patterns.filter(pattern => !!pattern).map((pattern) => {
66
- return findFiles(pattern).filter((file) => {
67
- return config.grep ? grepFile(file, config.grep) : true;
68
- });
69
- }).reduce((acc, val) => acc.concat(val), []);
64
+ const createChunks = (config, patterns = []) => {
65
+ const files = patterns
66
+ .filter(pattern => !!pattern)
67
+ .map(pattern => {
68
+ return findFiles(pattern).filter(file => {
69
+ return config.grep ? grepFile(file, config.grep) : true
70
+ })
71
+ })
72
+ .reduce((acc, val) => acc.concat(val), [])
70
73
 
71
- let chunks = [];
74
+ let chunks = []
72
75
  if (typeof config.chunks === 'function') {
73
- chunks = config.chunks.call(this, files);
76
+ chunks = config.chunks.call(this, files)
74
77
  } else if (typeof config.chunks === 'number' || typeof config.chunks === 'string') {
75
- chunks = splitFiles(files, Math.ceil(files.length / config.chunks));
78
+ chunks = splitFiles(files, Math.ceil(files.length / config.chunks))
76
79
  } else {
77
- throw new Error('chunks is neither a finite number or a valid function');
80
+ throw new Error('chunks is neither a finite number or a valid function')
78
81
  }
79
82
 
80
- const chunkConfig = { ...config };
81
- delete chunkConfig.chunks;
83
+ const chunkConfig = { ...config }
84
+ delete chunkConfig.chunks
82
85
 
83
- return chunks.map((chunkFiles) => {
84
- const { js, gherkin } = mapFileFormats(chunkFiles);
85
- return { ...chunkConfig, tests: flattenFiles(js), gherkin: { features: flattenFiles(gherkin) } };
86
- });
87
- };
86
+ return chunks.map(chunkFiles => {
87
+ const { js, gherkin } = mapFileFormats(chunkFiles)
88
+ return { ...chunkConfig, tests: flattenFiles(js), gherkin: { features: flattenFiles(gherkin) } }
89
+ })
90
+ }
88
91
 
89
- export default {
90
- createChunks,
91
- };
92
+ export {
93
+ createChunks
94
+ }
@@ -1,5 +1,5 @@
1
- import { createChunks } from './chunk.js';
2
- import { createRun } from './run.js';
1
+ import { createChunks } from './chunk.js'
2
+ import { createRun } from './run.js'
3
3
 
4
4
  /**
5
5
  * Bootstraps a collection of runs, it combines user defined selection of runs
@@ -190,6 +190,6 @@ function guessBrowser(config) {
190
190
  return [config.helpers[firstHelper].browser];
191
191
  }
192
192
 
193
- export default {
194
- createRuns,
195
- };
193
+ export {
194
+ createRuns
195
+ }
@@ -21,6 +21,10 @@ class Run {
21
21
  }
22
22
  }
23
23
 
24
- export function createRun(name, config) {
24
+ const createRun = (name, config) => {
25
25
  return new Run(name, config);
26
+ };
27
+
28
+ export {
29
+ createRun
26
30
  }
@@ -1,186 +1,186 @@
1
- import { fork } from 'child_process';
2
- import path, { dirname } from 'path';
3
- import crypto from 'crypto';
4
- import { fileURLToPath } from 'url';
5
- import runHook from '../hooks.js';
6
- import * as event from '../event.js';
7
- import collection from './run-multiple/collection.js';
8
- import { clearString, replaceValueDeep } from '../utils.js';
9
- import { getConfig, getTestRoot, fail } from './utils.js';
10
-
11
- const __dirname = dirname(fileURLToPath(import.meta.url));
12
-
13
- const runner = path.join(__dirname, '../../bin/codecept.js');
14
- let config;
15
- const childOpts = {};
16
- const copyOptions = ['override', 'steps', 'reporter', 'verbose', 'config', 'reporter-options', 'grep', 'fgrep', 'invert', 'debug', 'plugins', 'colors'];
17
- let overrides = {};
1
+ import { fork } from 'child_process'
2
+ import path from 'path'
3
+ import crypto from 'crypto'
4
+ import { fileURLToPath } from 'url'
5
+
6
+ import runHook from '../hooks.js'
7
+ import event from '../event.js'
8
+ import { createRuns } from './run-multiple/collection.js'
9
+ import { clearString, replaceValueDeep } from '../utils.js'
10
+ import { getConfig, getTestRoot, fail } from './utils.js'
11
+
12
+ const __filename = fileURLToPath(import.meta.url)
13
+ const __dirname = path.dirname(__filename)
14
+ const runner = path.join(__dirname, '/../../bin/codecept')
15
+ let config
16
+ const childOpts = {}
17
+ const copyOptions = ['override', 'steps', 'reporter', 'verbose', 'config', 'reporter-options', 'grep', 'fgrep', 'invert', 'debug', 'plugins', 'colors']
18
+ let overrides = {}
18
19
 
19
20
  // codeceptjs run-multiple smoke:chrome regression:firefox - will launch smoke run in chrome and regression in firefox
20
21
  // codeceptjs run-multiple smoke:chrome regression - will launch smoke run in chrome and regression in firefox and chrome
21
22
  // codeceptjs run-multiple --all - will launch all runs
22
23
  // codeceptjs run-multiple smoke regression'
23
24
 
24
- let runId = 1;
25
- let subprocessCount = 0;
26
- let totalSubprocessCount = 0;
27
- let processesDone;
25
+ let runId = 1
26
+ let subprocessCount = 0
27
+ let totalSubprocessCount = 0
28
+ let processesDone
28
29
 
29
30
  export default async function (selectedRuns, options) {
30
31
  // registering options globally to use in config
31
32
  if (options.profile) {
32
- process.env.profile = options.profile;
33
+ process.env.profile = options.profile
33
34
  }
34
- const configFile = options.config;
35
+ const configFile = options.config
35
36
 
36
- const testRoot = getTestRoot(configFile);
37
- global.codecept_dir = testRoot;
37
+ const testRoot = getTestRoot(configFile)
38
+ global.codecept_dir = testRoot
38
39
 
39
40
  // copy opts to run
40
41
  Object.keys(options)
41
42
  .filter(key => copyOptions.indexOf(key) > -1)
42
- .forEach((key) => {
43
- childOpts[key] = options[key];
44
- });
43
+ .forEach(key => {
44
+ childOpts[key] = options[key]
45
+ })
45
46
 
46
47
  try {
47
- overrides = JSON.parse(childOpts.override);
48
- delete childOpts.override;
48
+ overrides = JSON.parse(childOpts.override)
49
+ delete childOpts.override
49
50
  } catch (e) {
50
- overrides = {};
51
+ overrides = {}
51
52
  }
52
53
 
53
54
  config = {
54
- ...getConfig(configFile),
55
+ ...(await getConfig(configFile)),
55
56
  ...overrides,
56
- };
57
+ }
57
58
 
58
59
  if (!config.multiple) {
59
- fail('Multiple runs not configured, add "multiple": { /../ } section to config');
60
+ fail('Multiple runs not configured, add "multiple": { /../ } section to config')
60
61
  }
61
62
 
62
- selectedRuns = options.all ? Object.keys(config.multiple) : selectedRuns;
63
+ selectedRuns = options.all ? Object.keys(config.multiple) : selectedRuns
63
64
  if (!selectedRuns.length) {
64
- fail('No runs provided. Use --all option to run all configured runs');
65
+ fail('No runs provided. Use --all option to run all configured runs')
65
66
  }
66
67
 
67
- await runHook(config.bootstrapAll, 'bootstrapAll');
68
+ await runHook(config.bootstrapAll, 'bootstrapAll')
68
69
 
69
- event.emit(event.multiple.before, null);
70
- if (options.config) { // update paths to config path
70
+ event.emit(event.multiple.before, null)
71
+ if (options.config) {
72
+ // update paths to config path
71
73
  if (config.tests) {
72
- config.tests = path.resolve(testRoot, config.tests);
74
+ config.tests = path.resolve(testRoot, config.tests)
73
75
  }
74
76
  if (config.gherkin && config.gherkin.features) {
75
- config.gherkin.features = path.resolve(testRoot, config.gherkin.features);
77
+ config.gherkin.features = path.resolve(testRoot, config.gherkin.features)
76
78
  }
77
79
  }
78
80
 
79
81
  if (options.features) {
80
- config.tests = '';
82
+ config.tests = ''
81
83
  }
82
84
 
83
85
  if (options.tests && config.gherkin) {
84
- config.gherkin.features = '';
86
+ config.gherkin.features = ''
85
87
  }
86
88
 
87
- const childProcessesPromise = new Promise((resolve) => {
88
- processesDone = resolve;
89
- });
89
+ const childProcessesPromise = new Promise(resolve => {
90
+ processesDone = resolve
91
+ })
90
92
 
91
- const runsToExecute = [];
92
- collection.createRuns(selectedRuns, config).forEach((run) => {
93
- const runName = run.getOriginalName() || run.getName();
94
- const runConfig = run.getConfig();
95
- runsToExecute.push(executeRun(runName, runConfig));
96
- });
93
+ const runsToExecute = []
94
+ createRuns(selectedRuns, config).forEach(run => {
95
+ const runName = run.getOriginalName() || run.getName()
96
+ const runConfig = run.getConfig()
97
+ runsToExecute.push(executeRun(runName, runConfig))
98
+ })
97
99
 
98
100
  if (!runsToExecute.length) {
99
- fail('Nothing scheduled for execution');
101
+ fail('Nothing scheduled for execution')
100
102
  }
101
103
 
102
104
  // Execute all forks
103
- totalSubprocessCount = runsToExecute.length;
104
- runsToExecute.forEach(runToExecute => runToExecute.call(this));
105
+ totalSubprocessCount = runsToExecute.length
106
+ runsToExecute.forEach(runToExecute => runToExecute.call(this))
105
107
 
106
108
  return childProcessesPromise.then(async () => {
107
109
  // fire hook
108
- await runHook(config.teardownAll, 'teardownAll');
109
- event.emit(event.multiple.after, null);
110
- });
110
+ await runHook(config.teardownAll, 'teardownAll')
111
+ event.emit(event.multiple.after, null)
112
+ })
111
113
  }
112
114
 
113
115
  function executeRun(runName, runConfig) {
114
116
  // clone config
115
- let overriddenConfig = { ...config };
117
+ let overriddenConfig = { ...config }
116
118
 
117
119
  // get configuration
118
- const browserConfig = runConfig.browser;
119
- const browserName = browserConfig.browser;
120
+ const browserConfig = runConfig.browser
121
+ const browserName = browserConfig.browser
120
122
 
121
123
  for (const key in browserConfig) {
122
- overriddenConfig.helpers = replaceValueDeep(overriddenConfig.helpers, key, browserConfig[key]);
124
+ overriddenConfig.helpers = replaceValueDeep(overriddenConfig.helpers, key, browserConfig[key])
123
125
  }
124
126
 
125
- let outputDir = `${runName}_`;
127
+ let outputDir = `${runName}_`
126
128
  if (browserConfig.outputName) {
127
- outputDir += typeof browserConfig.outputName === 'function' ? browserConfig.outputName() : browserConfig.outputName;
129
+ outputDir += typeof browserConfig.outputName === 'function' ? browserConfig.outputName() : browserConfig.outputName
128
130
  } else {
129
- const hash = crypto.createHash('sha256');
130
- hash.update(JSON.stringify(browserConfig));
131
- outputDir += hash.digest('hex');
131
+ const hash = crypto.createHash('sha256')
132
+ hash.update(JSON.stringify(browserConfig))
133
+ outputDir += hash.digest('hex')
132
134
  }
133
- outputDir += `_${runId}`;
135
+ outputDir += `_${runId}`
134
136
 
135
- outputDir = clearString(outputDir);
137
+ outputDir = clearString(outputDir)
136
138
 
137
139
  // tweaking default output directories and for mochawesome
138
- overriddenConfig = replaceValueDeep(overriddenConfig, 'output', path.join(config.output, outputDir));
139
- overriddenConfig = replaceValueDeep(overriddenConfig, 'reportDir', path.join(config.output, outputDir));
140
- overriddenConfig = replaceValueDeep(overriddenConfig, 'mochaFile', path.join(config.output, outputDir, `${browserName}_report.xml`));
140
+ overriddenConfig = replaceValueDeep(overriddenConfig, 'output', path.join(config.output, outputDir))
141
+ overriddenConfig = replaceValueDeep(overriddenConfig, 'reportDir', path.join(config.output, outputDir))
142
+ overriddenConfig = replaceValueDeep(overriddenConfig, 'mochaFile', path.join(config.output, outputDir, `${browserName}_report.xml`))
141
143
 
142
144
  // override tests configuration
143
145
  if (overriddenConfig.tests) {
144
- overriddenConfig.tests = runConfig.tests;
146
+ overriddenConfig.tests = runConfig.tests
145
147
  }
146
148
 
147
149
  if (overriddenConfig.gherkin && runConfig.gherkin && runConfig.gherkin.features) {
148
- overriddenConfig.gherkin.features = runConfig.gherkin.features;
150
+ overriddenConfig.gherkin.features = runConfig.gherkin.features
149
151
  }
150
152
 
151
153
  // override grep param and collect all params
152
- const params = ['run',
153
- '--child', `${runId++}.${runName}:${browserName}`,
154
- '--override', JSON.stringify(overriddenConfig),
155
- ];
154
+ const params = ['run', '--child', `${runId++}.${runName}:${browserName}`, '--override', JSON.stringify(overriddenConfig)]
156
155
 
157
- Object.keys(childOpts).forEach((key) => {
158
- params.push(`--${key}`);
159
- if (childOpts[key] !== true) params.push(childOpts[key]);
160
- });
156
+ Object.keys(childOpts).forEach(key => {
157
+ params.push(`--${key}`)
158
+ if (childOpts[key] !== true) params.push(childOpts[key])
159
+ })
161
160
 
162
161
  if (runConfig.grep) {
163
- params.push('--grep');
164
- params.push(runConfig.grep);
162
+ params.push('--grep')
163
+ params.push(runConfig.grep)
165
164
  }
166
165
 
167
- const onProcessEnd = (errorCode) => {
166
+ const onProcessEnd = errorCode => {
168
167
  if (errorCode !== 0) {
169
- process.exitCode = errorCode;
168
+ process.exitCode = errorCode
170
169
  }
171
- subprocessCount += 1;
170
+ subprocessCount += 1
172
171
  if (subprocessCount === totalSubprocessCount) {
173
- processesDone();
172
+ processesDone()
174
173
  }
175
- return errorCode;
176
- };
174
+ return errorCode
175
+ }
177
176
 
178
177
  // Return function of fork for later execution
179
- return () => fork(runner, params, { stdio: [0, 1, 2, 'ipc'] })
180
- .on('exit', (code) => {
181
- return onProcessEnd(code);
182
- })
183
- .on('error', () => {
184
- return onProcessEnd(1);
185
- });
178
+ return () =>
179
+ fork(runner, params, { stdio: [0, 1, 2, 'ipc'] })
180
+ .on('exit', code => {
181
+ return onProcessEnd(code)
182
+ })
183
+ .on('error', () => {
184
+ return onProcessEnd(1)
185
+ })
186
186
  }