codeceptjs 4.0.0-beta.2 → 4.0.0-beta.20

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 (209) 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 +262 -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 +301 -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 +109 -50
  39. package/lib/container.js +641 -261
  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/loaderCheck.js +124 -0
  157. package/lib/utils/mask_data.js +47 -0
  158. package/lib/utils/typescript.js +237 -0
  159. package/lib/utils.js +411 -228
  160. package/lib/workerStorage.js +37 -34
  161. package/lib/workers.js +532 -296
  162. package/package.json +124 -95
  163. package/translations/de-DE.js +5 -3
  164. package/translations/fr-FR.js +5 -4
  165. package/translations/index.js +22 -12
  166. package/translations/it-IT.js +4 -3
  167. package/translations/ja-JP.js +4 -3
  168. package/translations/nl-NL.js +76 -0
  169. package/translations/pl-PL.js +4 -3
  170. package/translations/pt-BR.js +4 -3
  171. package/translations/ru-RU.js +4 -3
  172. package/translations/utils.js +10 -0
  173. package/translations/zh-CN.js +4 -3
  174. package/translations/zh-TW.js +4 -3
  175. package/typings/index.d.ts +546 -185
  176. package/typings/promiseBasedTypes.d.ts +150 -875
  177. package/typings/types.d.ts +547 -992
  178. package/lib/cli.js +0 -249
  179. package/lib/dirname.js +0 -5
  180. package/lib/helper/Expect.js +0 -425
  181. package/lib/helper/ExpectHelper.js +0 -399
  182. package/lib/helper/MockServer.js +0 -223
  183. package/lib/helper/Nightmare.js +0 -1411
  184. package/lib/helper/Protractor.js +0 -1835
  185. package/lib/helper/SoftExpectHelper.js +0 -381
  186. package/lib/helper/TestCafe.js +0 -1410
  187. package/lib/helper/clientscripts/nightmare.js +0 -213
  188. package/lib/helper/testcafe/testControllerHolder.js +0 -42
  189. package/lib/helper/testcafe/testcafe-utils.js +0 -63
  190. package/lib/interfaces/bdd.js +0 -98
  191. package/lib/interfaces/featureConfig.js +0 -69
  192. package/lib/interfaces/gherkin.js +0 -195
  193. package/lib/listener/artifacts.js +0 -19
  194. package/lib/listener/retry.js +0 -68
  195. package/lib/listener/timeout.js +0 -109
  196. package/lib/mochaFactory.js +0 -110
  197. package/lib/plugin/allure.js +0 -15
  198. package/lib/plugin/commentStep.js +0 -136
  199. package/lib/plugin/debugErrors.js +0 -67
  200. package/lib/plugin/eachElement.js +0 -127
  201. package/lib/plugin/fakerTransform.js +0 -49
  202. package/lib/plugin/retryTo.js +0 -121
  203. package/lib/plugin/selenoid.js +0 -371
  204. package/lib/plugin/standardActingHelpers.js +0 -9
  205. package/lib/plugin/tryTo.js +0 -105
  206. package/lib/plugin/wdio.js +0 -246
  207. package/lib/scenario.js +0 -222
  208. package/lib/ui.js +0 -238
  209. package/lib/within.js +0 -70
@@ -1,39 +1,33 @@
1
- import {
2
- getConfig, getTestRoot, printError, createOutputDir,
3
- } from './utils.js';
4
- import Config from '../config.js';
5
- import Codecept from '../rerun.js';
1
+ import { getConfig, getTestRoot, printError, createOutputDir } from './utils.js'
2
+ import Config from '../config.js'
3
+ import Codecept from '../rerun.js'
6
4
 
7
- export async function runRerun(test, options) {
5
+ export default async function (test, options) {
8
6
  // registering options globally to use in config
9
7
  // Backward compatibility for --profile
10
- process.profile = options.profile;
11
- process.env.profile = options.profile;
12
- const configFile = options.config;
8
+ process.profile = options.profile
9
+ process.env.profile = options.profile
10
+ const configFile = options.config
13
11
 
14
- let config = getConfig(configFile);
12
+ let config = await getConfig(configFile)
15
13
  if (options.override) {
16
- config = Config.append(JSON.parse(options.override));
14
+ config = Config.append(JSON.parse(options.override))
17
15
  }
18
- const testRoot = getTestRoot(configFile);
19
- createOutputDir(config, testRoot);
16
+ const testRoot = getTestRoot(configFile)
17
+ createOutputDir(config, testRoot)
20
18
 
21
- function processError(err) {
22
- printError(err);
23
- process.exit(1);
24
- }
25
- const codecept = new Codecept(config, options);
19
+ const codecept = new Codecept(config, options)
26
20
 
27
21
  try {
28
- codecept.init(testRoot);
22
+ await codecept.init(testRoot)
29
23
 
30
- await codecept.bootstrap();
31
- codecept.loadTests(test);
32
- await codecept.run();
24
+ await codecept.bootstrap()
25
+ codecept.loadTests(test)
26
+ await codecept.run()
33
27
  } catch (err) {
34
- printError(err);
35
- process.exitCode = 1;
28
+ printError(err)
29
+ process.exitCode = 1
36
30
  } finally {
37
- await codecept.teardown();
31
+ await codecept.teardown()
38
32
  }
39
33
  }
@@ -1,117 +1,93 @@
1
1
  // For Node version >=10.5.0, have to use experimental flag
2
- import { tryOrDefault } from '../utils.js';
3
- import { store } from '../store.js';
4
- import * as output from '../output.js';
5
- import * as event from '../event.js';
6
- import { Workers } from '../workers.js';
7
- import { getMachineInfo } from './info.js';
8
- import * as Codecept from '../codecept.js';
2
+ import { tryOrDefault } from '../utils.js'
3
+ import output from '../output.js'
4
+ import store from '../store.js'
5
+ import event from '../event.js'
6
+ import Workers from '../workers.js'
7
+ import Codecept from '../codecept.js'
8
+ import { getMachineInfo } from './info.js'
9
9
 
10
10
  export default async function (workerCount, selectedRuns, options) {
11
- process.env.profile = options.profile;
12
-
13
- const suiteArr = [];
14
- const passedTestArr = [];
15
- const failedTestArr = [];
16
- const skippedTestArr = [];
17
- const stepArr = [];
11
+ process.env.profile = options.profile
12
+
13
+ const { config: testConfig, override = '' } = options
14
+ const overrideConfigs = tryOrDefault(() => JSON.parse(override), {})
15
+
16
+ // Determine test split strategy
17
+ let by = 'test' // default
18
+ if (options.by) {
19
+ // Explicit --by option takes precedence
20
+ by = options.by
21
+ } else if (options.suites) {
22
+ // Legacy --suites option
23
+ by = 'suite'
24
+ }
18
25
 
19
- const { config: testConfig, override = '' } = options;
20
- const overrideConfigs = tryOrDefault(() => JSON.parse(override), {});
21
- const by = options.suites ? 'suite' : 'test';
22
- delete options.parent;
26
+ // Validate the by option
27
+ const validStrategies = ['test', 'suite', 'pool']
28
+ if (!validStrategies.includes(by)) {
29
+ throw new Error(`Invalid --by strategy: ${by}. Valid options are: ${validStrategies.join(', ')}`)
30
+ }
31
+ delete options.parent
23
32
  const config = {
24
33
  by,
25
34
  testConfig,
26
35
  options,
27
36
  selectedRuns,
28
- };
29
-
30
- const numberOfWorkers = parseInt(workerCount, 10);
31
-
32
- const version = Codecept.version();
33
- output.print(`CodeceptJS v${version} ${output.output.standWithUkraine()}`);
34
- output.print(`Running tests in ${output.output.styles.bold(numberOfWorkers)} workers...`);
35
- output.print();
36
-
37
- const workers = new Workers(numberOfWorkers, config);
38
- workers.overrideConfig(overrideConfigs);
39
-
40
- workers.on(event.suite.before, (suite) => {
41
- suiteArr.push(suite);
42
- });
43
-
44
- workers.on(event.step.passed, (step) => {
45
- stepArr.push(step);
46
- });
47
-
48
- workers.on(event.step.failed, (step) => {
49
- stepArr.push(step);
50
- });
37
+ }
51
38
 
52
- workers.on(event.test.failed, (test) => {
53
- failedTestArr.push(test);
54
- output.output.test.failed(test);
55
- });
39
+ const numberOfWorkers = parseInt(workerCount, 10)
56
40
 
57
- workers.on(event.test.passed, (test) => {
58
- passedTestArr.push(test);
59
- output.output.test.passed(test);
60
- });
41
+ output.print(`CodeceptJS v${Codecept.version()} ${output.standWithUkraine()}`)
42
+ output.print(`Running tests in ${output.styles.bold(numberOfWorkers)} workers...`)
43
+ output.print()
44
+ store.hasWorkers = true
61
45
 
62
- workers.on(event.test.skipped, (test) => {
63
- skippedTestArr.push(test);
64
- output.output.test.skipped(test);
65
- });
46
+ const workers = new Workers(numberOfWorkers, config)
47
+ workers.overrideConfig(overrideConfigs)
66
48
 
67
- workers.on(event.all.result, () => {
68
- // expose test stats after all workers finished their execution
69
- function addStepsToTest(test, stepArr) {
70
- stepArr.test.steps.forEach(step => {
71
- if (test.steps.length === 0) {
72
- test.steps.push(step);
73
- }
74
- });
75
- }
49
+ workers.on(event.test.failed, test => {
50
+ output.test.failed(test)
51
+ })
76
52
 
77
- stepArr.forEach(step => {
78
- passedTestArr.forEach(test => {
79
- if (step.test.title === test.title) {
80
- addStepsToTest(test, step);
81
- }
82
- });
53
+ workers.on(event.test.passed, test => {
54
+ output.test.passed(test)
55
+ })
83
56
 
84
- failedTestArr.forEach(test => {
85
- if (step.test.title === test.title) {
86
- addStepsToTest(test, step);
87
- }
88
- });
89
- });
57
+ workers.on(event.test.skipped, test => {
58
+ output.test.skipped(test)
59
+ })
90
60
 
91
- event.dispatcher.emit(event.workers.result, {
92
- suites: suiteArr,
93
- tests: {
94
- passed: passedTestArr,
95
- failed: failedTestArr,
96
- skipped: skippedTestArr,
97
- },
98
- });
99
- workers.printResults();
100
- });
61
+ workers.on(event.all.result, result => {
62
+ workers.printResults()
63
+ })
101
64
 
102
65
  try {
103
- if (options.verbose || options.debug) store.debugMode = true;
66
+ if (options.verbose || options.debug) store.debugMode = true
104
67
 
105
68
  if (options.verbose) {
106
- global.debugMode = true;
107
- await getMachineInfo();
69
+ await getMachineInfo()
108
70
  }
109
- await workers.bootstrapAll();
110
- await workers.run();
71
+ await workers.bootstrapAll()
72
+ await workers.run()
111
73
  } catch (err) {
112
- output.output.error(err);
113
- process.exit(1);
74
+ output.error(err)
75
+ process.exitCode = 1
114
76
  } finally {
115
- await workers.teardownAll();
77
+ await workers.teardownAll()
78
+
79
+ // Force exit if event loop doesn't clear naturally
80
+ // This is needed because worker threads may leave handles open
81
+ // even after proper cleanup, preventing natural process termination
82
+ if (!options.noExit) {
83
+ // Use beforeExit to ensure we run after all other exit handlers
84
+ // have set the correct exit code
85
+ process.once('beforeExit', (code) => {
86
+ // Give cleanup a moment to complete, then force exit with the correct code
87
+ setTimeout(() => {
88
+ process.exit(code || process.exitCode || 0)
89
+ }, 100)
90
+ })
91
+ }
116
92
  }
117
93
  }
@@ -1,49 +1,61 @@
1
- import importSync from 'import-sync';
2
- import {
3
- getConfig, printError, getTestRoot, createOutputDir,
4
- } from './utils.js';
5
- import Config from '../config.js';
6
- import Codecept from '../codecept.js';
7
- import { store } from '../store.js';
1
+ import { getConfig, printError, getTestRoot, createOutputDir } from './utils.js'
2
+ import Config from '../config.js'
3
+ import store from '../store.js'
4
+ import Codecept from '../codecept.js'
5
+ import container from '../container.js'
8
6
 
9
7
  export default async function (test, options) {
10
8
  // registering options globally to use in config
11
9
  // Backward compatibility for --profile
12
10
  // TODO: remove in CodeceptJS 4
13
- process.profile = options.profile;
11
+ process.profile = options.profile
14
12
 
15
13
  if (options.profile) {
16
- process.env.profile = options.profile;
14
+ process.env.profile = options.profile
17
15
  }
18
- if (options.verbose || options.debug) store.debugMode = true;
16
+ if (options.verbose || options.debug) store.debugMode = true
19
17
 
20
- const configFile = options.config;
21
-
22
- let config = getConfig(configFile);
18
+ const configFile = options.config
23
19
 
20
+ let config = await getConfig(configFile)
24
21
  if (options.override) {
25
- config = Config.append(JSON.parse(options.override));
22
+ config = Config.append(JSON.parse(options.override))
26
23
  }
27
- const testRoot = getTestRoot(configFile);
28
- createOutputDir(config, testRoot);
24
+ const testRoot = getTestRoot(configFile)
25
+ createOutputDir(config, testRoot)
26
+
27
+ const codecept = new Codecept(config, options)
29
28
 
30
- const codecept = new Codecept(config, options);
31
29
  try {
32
- codecept.init(testRoot);
33
- await codecept.bootstrap();
34
- codecept.loadTests(test);
30
+ await codecept.init(testRoot)
31
+ await codecept.bootstrap()
32
+ codecept.loadTests(test)
35
33
 
36
34
  if (options.verbose) {
37
- global.debugMode = true;
38
- const { getMachineInfo } = importSync('./info.js');
39
- await getMachineInfo();
35
+ global.debugMode = true
36
+ const { getMachineInfo } = await import('./info.js')
37
+ await getMachineInfo()
40
38
  }
41
39
 
42
- await codecept.run();
40
+ await codecept.run()
43
41
  } catch (err) {
44
- printError(err);
45
- process.exitCode = 1;
42
+ printError(err)
43
+ process.exitCode = 1
46
44
  } finally {
47
- await codecept.teardown();
45
+ await codecept.teardown()
46
+
47
+ // Schedule a delayed exit to prevent process hanging due to browser helper event loops
48
+ // Only needed for Playwright/Puppeteer which keep the event loop alive
49
+ // Wait 1 second to allow final cleanup and output to complete
50
+ if (!process.env.CODECEPT_DISABLE_AUTO_EXIT) {
51
+ const helpers = container.helpers()
52
+ const hasBrowserHelper = helpers && (helpers.Playwright || helpers.Puppeteer || helpers.WebDriver)
53
+
54
+ if (hasBrowserHelper) {
55
+ setTimeout(() => {
56
+ process.exit(process.exitCode || 0)
57
+ }, 1000).unref()
58
+ }
59
+ }
48
60
  }
49
61
  }
@@ -1,103 +1,119 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import util from 'util';
4
- import mkdirp from 'mkdirp';
5
- import * as output from '../output.js';
6
- import { fileExists, beautify } from '../utils.js';
7
- import * as config from '../config.js';
8
-
9
- export const getConfig = function (configFile) {
1
+ import fs from 'fs'
2
+ import path from 'path'
3
+ import util from 'util'
4
+ import { mkdirp } from 'mkdirp'
5
+
6
+ import output from '../output.js'
7
+ import { fileExists, beautify, deepMerge } from '../utils.js'
8
+
9
+ // alias to deep merge
10
+ export { deepMerge }
11
+
12
+ export async function getConfig(configFile) {
10
13
  try {
11
- return config.default.load(configFile);
14
+ const configModule = await import('../config.js')
15
+ const config = configModule.default || configModule
16
+ return await config.load(configFile)
12
17
  } catch (err) {
13
- fail(err.stack);
18
+ fail(err.stack)
14
19
  }
15
- };
20
+ }
16
21
 
17
- export const readConfig = function (configFile) {
22
+ export function readConfig(configFile) {
18
23
  try {
19
- const data = fs.readFileSync(configFile, 'utf8');
20
- return data;
24
+ const data = fs.readFileSync(configFile, 'utf8')
25
+ return data
21
26
  } catch (err) {
22
- output.output.error(err);
27
+ output.error(err)
23
28
  }
24
- };
29
+ }
25
30
 
26
31
  function getTestRoot(currentPath) {
27
- if (!currentPath) currentPath = '.';
28
- if (!path.isAbsolute(currentPath)) currentPath = path.join(process.cwd(), currentPath);
29
- currentPath = fs.lstatSync(currentPath).isDirectory() || !path.extname(currentPath) ? currentPath : path.dirname(currentPath);
30
- return currentPath;
32
+ if (!currentPath) currentPath = '.'
33
+ if (!path.isAbsolute(currentPath)) currentPath = path.join(process.cwd(), currentPath)
34
+ currentPath = fs.lstatSync(currentPath).isDirectory() || !path.extname(currentPath) ? currentPath : path.dirname(currentPath)
35
+ return currentPath
31
36
  }
32
- export { getTestRoot };
37
+ export { getTestRoot }
33
38
 
34
39
  function fail(msg) {
35
- output.output.error(msg);
36
- process.exit(1);
40
+ output.error(msg)
41
+ process.exit(1)
37
42
  }
38
43
 
39
- export { fail };
44
+ export { fail }
40
45
 
41
- function updateConfig(testsPath, config, key, extension = 'js') {
42
- const configFile = path.join(testsPath, `codecept.conf.${extension}`);
46
+ function updateConfig(testsPath, config, extension) {
47
+ const configFile = path.join(testsPath, `codecept.conf.${extension}`)
43
48
  if (!fileExists(configFile)) {
44
- console.log();
45
- const msg = `codecept.conf.${extension} config can\'t be updated automatically`;
46
- console.log(`${output.output.colors.bold.red(msg)}`);
47
- console.log('Please update it manually:');
48
- console.log();
49
- console.log(`${key}: ${config[key]}`);
50
- console.log();
51
- return;
49
+ const msg = `codecept.conf.${extension} config can\'t be updated automatically`
50
+ console.log()
51
+ console.log(`${output.colors.bold.red(msg)}`)
52
+ console.log(`${output.colors.bold.red('Please update it manually:')}`)
53
+ console.log()
54
+ console.log(config)
55
+ console.log()
56
+ return
52
57
  }
53
- console.log(`${output.output.colors.yellow('Updating configuration file...')}`);
54
- return fs.writeFileSync(configFile, beautify(`exports.config = ${util.inspect(config, false, 4, false)}`), 'utf-8');
58
+ console.log(`${output.colors.yellow('Updating configuration file...')}`)
59
+ return fs.writeFileSync(configFile, beautify(`exports.config = ${util.inspect(config, false, 4, false)}`), 'utf-8')
55
60
  }
56
61
 
57
- export { updateConfig };
62
+ export { updateConfig }
58
63
 
59
64
  function safeFileWrite(file, contents) {
60
65
  if (fileExists(file)) {
61
- output.output.error(`File ${file} already exist, skipping...`);
62
- return false;
66
+ output.error(`File ${file} already exist, skipping...`)
67
+ return false
63
68
  }
64
- fs.writeFileSync(file, contents);
65
- return true;
69
+ fs.writeFileSync(file, contents)
70
+ return true
66
71
  }
67
72
 
68
- export { safeFileWrite };
73
+ export { safeFileWrite }
69
74
 
70
- export const captureStream = (stream) => {
71
- let oldStream;
72
- let buffer = '';
75
+ export const captureStream = stream => {
76
+ let oldStream
77
+ let buffer = ''
73
78
 
74
79
  return {
75
80
  startCapture() {
76
- buffer = '';
77
- oldStream = stream.write.bind(stream);
78
- stream.write = chunk => (buffer += chunk);
81
+ buffer = ''
82
+ oldStream = stream.write.bind(stream)
83
+ stream.write = chunk => (buffer += chunk)
79
84
  },
80
85
  stopCapture() {
81
- if (oldStream !== undefined) stream.write = oldStream;
86
+ if (oldStream !== undefined) stream.write = oldStream
82
87
  },
83
88
  getData: () => buffer,
84
- };
85
- };
89
+ }
90
+ }
86
91
 
87
- export const printError = (err) => {
88
- output.print('');
89
- output.output.error(err.message);
90
- output.print('');
91
- output.print(output.output.colors.grey(err.stack.replace(err.message, '')));
92
- };
92
+ export const printError = err => {
93
+ output.print('')
94
+ output.error(err.message)
95
+ output.print('')
96
+ output.print(output.colors.grey(err.stack.replace(err.message, '')))
97
+ }
93
98
 
94
99
  export const createOutputDir = (config, testRoot) => {
95
- let outputDir;
96
- if (path.isAbsolute(config.output)) outputDir = config.output;
97
- else outputDir = path.join(testRoot, config.output);
100
+ let outputDir
101
+ if (path.isAbsolute(config.output)) outputDir = config.output
102
+ else outputDir = path.join(testRoot, config.output)
98
103
 
99
104
  if (!fileExists(outputDir)) {
100
- output.print(`creating output directory: ${outputDir}`);
101
- mkdirp.sync(outputDir);
105
+ output.print(`creating output directory: ${outputDir}`)
106
+ mkdirp.sync(outputDir)
107
+ }
108
+ }
109
+
110
+ export const findConfigFile = testsPath => {
111
+ const extensions = ['js', 'ts']
112
+ for (const ext of extensions) {
113
+ const configFile = path.join(testsPath, `codecept.conf.${ext}`)
114
+ if (fileExists(configFile)) {
115
+ return configFile
116
+ }
102
117
  }
103
- };
118
+ return null
119
+ }