codeceptjs 3.7.6-beta.4 → 4.0.0-beta.10.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 (191) hide show
  1. package/README.md +1 -3
  2. package/bin/codecept.js +51 -53
  3. package/bin/test-server.js +14 -3
  4. package/docs/webapi/click.mustache +5 -1
  5. package/lib/actor.js +15 -11
  6. package/lib/ai.js +72 -107
  7. package/lib/assert/empty.js +9 -8
  8. package/lib/assert/equal.js +15 -17
  9. package/lib/assert/error.js +2 -2
  10. package/lib/assert/include.js +9 -11
  11. package/lib/assert/throws.js +1 -1
  12. package/lib/assert/truth.js +8 -5
  13. package/lib/assert.js +18 -18
  14. package/lib/codecept.js +102 -75
  15. package/lib/colorUtils.js +48 -50
  16. package/lib/command/check.js +32 -27
  17. package/lib/command/configMigrate.js +11 -10
  18. package/lib/command/definitions.js +16 -10
  19. package/lib/command/dryRun.js +16 -16
  20. package/lib/command/generate.js +62 -27
  21. package/lib/command/gherkin/init.js +36 -38
  22. package/lib/command/gherkin/snippets.js +14 -14
  23. package/lib/command/gherkin/steps.js +21 -18
  24. package/lib/command/info.js +8 -8
  25. package/lib/command/init.js +36 -29
  26. package/lib/command/interactive.js +11 -10
  27. package/lib/command/list.js +10 -9
  28. package/lib/command/run-multiple/chunk.js +5 -5
  29. package/lib/command/run-multiple/collection.js +5 -5
  30. package/lib/command/run-multiple/run.js +3 -3
  31. package/lib/command/run-multiple.js +16 -13
  32. package/lib/command/run-rerun.js +6 -7
  33. package/lib/command/run-workers.js +24 -9
  34. package/lib/command/run.js +23 -8
  35. package/lib/command/utils.js +20 -18
  36. package/lib/command/workers/runTests.js +197 -114
  37. package/lib/config.js +124 -51
  38. package/lib/container.js +438 -87
  39. package/lib/data/context.js +6 -5
  40. package/lib/data/dataScenarioConfig.js +1 -1
  41. package/lib/data/dataTableArgument.js +1 -1
  42. package/lib/data/table.js +1 -1
  43. package/lib/effects.js +94 -10
  44. package/lib/element/WebElement.js +2 -2
  45. package/lib/els.js +11 -9
  46. package/lib/event.js +11 -10
  47. package/lib/globals.js +141 -0
  48. package/lib/heal.js +12 -12
  49. package/lib/helper/AI.js +11 -11
  50. package/lib/helper/ApiDataFactory.js +50 -19
  51. package/lib/helper/Appium.js +19 -27
  52. package/lib/helper/FileSystem.js +32 -12
  53. package/lib/helper/GraphQL.js +3 -3
  54. package/lib/helper/GraphQLDataFactory.js +4 -4
  55. package/lib/helper/JSONResponse.js +25 -29
  56. package/lib/helper/Mochawesome.js +7 -4
  57. package/lib/helper/Playwright.js +902 -164
  58. package/lib/helper/Puppeteer.js +383 -76
  59. package/lib/helper/REST.js +29 -12
  60. package/lib/helper/WebDriver.js +268 -61
  61. package/lib/helper/clientscripts/PollyWebDriverExt.js +1 -1
  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 +18 -9
  70. package/lib/helper/extras/PlaywrightRestartOpts.js +34 -23
  71. package/lib/helper/extras/Popup.js +1 -1
  72. package/lib/helper/extras/React.js +29 -30
  73. package/lib/helper/network/actions.js +29 -44
  74. package/lib/helper/network/utils.js +76 -83
  75. package/lib/helper/scripts/blurElement.js +6 -6
  76. package/lib/helper/scripts/focusElement.js +6 -6
  77. package/lib/helper/scripts/highlightElement.js +9 -9
  78. package/lib/helper/scripts/isElementClickable.js +34 -34
  79. package/lib/helper.js +2 -1
  80. package/lib/history.js +23 -20
  81. package/lib/hooks.js +10 -10
  82. package/lib/html.js +90 -100
  83. package/lib/index.js +48 -21
  84. package/lib/listener/config.js +19 -12
  85. package/lib/listener/emptyRun.js +6 -7
  86. package/lib/listener/enhancedGlobalRetry.js +6 -6
  87. package/lib/listener/exit.js +4 -3
  88. package/lib/listener/globalRetry.js +5 -5
  89. package/lib/listener/globalTimeout.js +30 -14
  90. package/lib/listener/helpers.js +39 -14
  91. package/lib/listener/mocha.js +3 -4
  92. package/lib/listener/result.js +4 -5
  93. package/lib/listener/retryEnhancer.js +3 -3
  94. package/lib/listener/steps.js +8 -7
  95. package/lib/listener/store.js +3 -3
  96. package/lib/locator.js +213 -192
  97. package/lib/mocha/asyncWrapper.js +105 -62
  98. package/lib/mocha/bdd.js +99 -13
  99. package/lib/mocha/cli.js +59 -26
  100. package/lib/mocha/factory.js +78 -19
  101. package/lib/mocha/featureConfig.js +1 -1
  102. package/lib/mocha/gherkin.js +56 -24
  103. package/lib/mocha/hooks.js +12 -3
  104. package/lib/mocha/index.js +13 -4
  105. package/lib/mocha/inject.js +22 -5
  106. package/lib/mocha/scenarioConfig.js +2 -2
  107. package/lib/mocha/suite.js +9 -2
  108. package/lib/mocha/test.js +10 -7
  109. package/lib/mocha/ui.js +28 -18
  110. package/lib/output.js +10 -8
  111. package/lib/parser.js +44 -44
  112. package/lib/pause.js +15 -16
  113. package/lib/plugin/analyze.js +19 -12
  114. package/lib/plugin/auth.js +20 -21
  115. package/lib/plugin/autoDelay.js +12 -8
  116. package/lib/plugin/coverage.js +28 -11
  117. package/lib/plugin/customLocator.js +3 -3
  118. package/lib/plugin/customReporter.js +3 -2
  119. package/lib/plugin/enhancedRetryFailedStep.js +6 -6
  120. package/lib/plugin/heal.js +14 -9
  121. package/lib/plugin/htmlReporter.js +724 -99
  122. package/lib/plugin/pageInfo.js +10 -10
  123. package/lib/plugin/pauseOnFail.js +4 -3
  124. package/lib/plugin/retryFailedStep.js +48 -5
  125. package/lib/plugin/screenshotOnFail.js +75 -37
  126. package/lib/plugin/stepByStepReport.js +14 -14
  127. package/lib/plugin/stepTimeout.js +4 -3
  128. package/lib/plugin/subtitles.js +6 -5
  129. package/lib/recorder.js +33 -14
  130. package/lib/rerun.js +69 -26
  131. package/lib/result.js +4 -4
  132. package/lib/retryCoordinator.js +2 -2
  133. package/lib/secret.js +18 -17
  134. package/lib/session.js +95 -89
  135. package/lib/step/base.js +7 -7
  136. package/lib/step/comment.js +2 -2
  137. package/lib/step/config.js +1 -1
  138. package/lib/step/func.js +3 -3
  139. package/lib/step/helper.js +3 -3
  140. package/lib/step/meta.js +5 -5
  141. package/lib/step/record.js +11 -11
  142. package/lib/step/retry.js +3 -3
  143. package/lib/step/section.js +3 -3
  144. package/lib/step.js +7 -10
  145. package/lib/steps.js +9 -5
  146. package/lib/store.js +1 -1
  147. package/lib/template/heal.js +1 -1
  148. package/lib/template/prompts/generatePageObject.js +31 -0
  149. package/lib/template/prompts/healStep.js +13 -0
  150. package/lib/template/prompts/writeStep.js +9 -0
  151. package/lib/test-server.js +17 -6
  152. package/lib/timeout.js +1 -7
  153. package/lib/transform.js +8 -8
  154. package/lib/translation.js +32 -18
  155. package/lib/utils/mask_data.js +4 -10
  156. package/lib/utils.js +66 -64
  157. package/lib/workerStorage.js +17 -17
  158. package/lib/workers.js +214 -84
  159. package/package.json +41 -37
  160. package/translations/de-DE.js +2 -2
  161. package/translations/fr-FR.js +2 -2
  162. package/translations/index.js +23 -10
  163. package/translations/it-IT.js +2 -2
  164. package/translations/ja-JP.js +2 -2
  165. package/translations/nl-NL.js +2 -2
  166. package/translations/pl-PL.js +2 -2
  167. package/translations/pt-BR.js +2 -2
  168. package/translations/ru-RU.js +2 -2
  169. package/translations/utils.js +4 -3
  170. package/translations/zh-CN.js +2 -2
  171. package/translations/zh-TW.js +2 -2
  172. package/typings/index.d.ts +5 -3
  173. package/typings/promiseBasedTypes.d.ts +4 -0
  174. package/typings/types.d.ts +4 -0
  175. package/lib/helper/Nightmare.js +0 -1486
  176. package/lib/helper/Protractor.js +0 -1840
  177. package/lib/helper/TestCafe.js +0 -1391
  178. package/lib/helper/clientscripts/nightmare.js +0 -213
  179. package/lib/helper/testcafe/testControllerHolder.js +0 -42
  180. package/lib/helper/testcafe/testcafe-utils.js +0 -61
  181. package/lib/plugin/allure.js +0 -15
  182. package/lib/plugin/autoLogin.js +0 -5
  183. package/lib/plugin/commentStep.js +0 -141
  184. package/lib/plugin/eachElement.js +0 -127
  185. package/lib/plugin/fakerTransform.js +0 -49
  186. package/lib/plugin/retryTo.js +0 -16
  187. package/lib/plugin/selenoid.js +0 -364
  188. package/lib/plugin/standardActingHelpers.js +0 -6
  189. package/lib/plugin/tryTo.js +0 -16
  190. package/lib/plugin/wdio.js +0 -247
  191. package/lib/within.js +0 -90
@@ -1,9 +1,9 @@
1
- const envinfo = require('envinfo')
1
+ import envinfo from 'envinfo'
2
2
 
3
- const { getConfig, getTestRoot } = require('./utils')
4
- const Codecept = require('../codecept')
5
- const output = require('../output')
6
- const { execSync } = require('child_process')
3
+ import { getConfig, getTestRoot } from './utils.js'
4
+ import Codecept from '../codecept.js'
5
+ import output from '../output.js'
6
+ import { execSync } from 'child_process'
7
7
 
8
8
  async function getPlaywrightBrowsers() {
9
9
  try {
@@ -40,9 +40,9 @@ async function getOsBrowsers() {
40
40
  ].join(', ')
41
41
  }
42
42
 
43
- module.exports = async function (path) {
43
+ export default async function (path) {
44
44
  const testsPath = getTestRoot(path)
45
- const config = getConfig(testsPath)
45
+ const config = await getConfig(testsPath)
46
46
  const codecept = new Codecept(config, {})
47
47
  codecept.init(testsPath)
48
48
 
@@ -73,7 +73,7 @@ module.exports = async function (path) {
73
73
  output.print('***************************************')
74
74
  }
75
75
 
76
- module.exports.getMachineInfo = async () => {
76
+ export const getMachineInfo = async () => {
77
77
  const info = {
78
78
  nodeInfo: await envinfo.helpers.getNodeInfo(),
79
79
  osInfo: await envinfo.helpers.getOSInfo(),
@@ -1,17 +1,18 @@
1
- const colors = require('chalk')
2
- const fs = require('fs')
3
- const inquirer = require('inquirer')
4
- const mkdirp = require('mkdirp')
5
- const path = require('path')
6
- const { inspect } = require('util')
7
- const spawn = require('cross-spawn')
8
-
9
- const { print, success, error } = require('../output')
10
- const { fileExists, beautify, installedLocally } = require('../utils')
11
- const { getTestRoot } = require('./utils')
12
- const generateDefinitions = require('./definitions')
13
- const { test: generateTest } = require('./generate')
14
- const isLocal = require('../utils').installedLocally()
1
+ import colors from 'chalk'
2
+ import fs from 'fs'
3
+ import inquirer from 'inquirer'
4
+ import { mkdirp } from 'mkdirp'
5
+ import path from 'path'
6
+ import { inspect } from 'util'
7
+ import spawn from 'cross-spawn'
8
+
9
+ import output from '../output.js'
10
+ const { print, success, error } = output
11
+ import { fileExists, beautify, installedLocally } from '../utils.js'
12
+ import { getTestRoot } from './utils.js'
13
+ import generateDefinitions from './definitions.js'
14
+ import { test as generateTest } from './generate.js'
15
+ const isLocal = installedLocally()
15
16
 
16
17
  const defaultConfig = {
17
18
  tests: './*_test.js',
@@ -25,17 +26,20 @@ const defaultConfig = {
25
26
  },
26
27
  }
27
28
 
28
- const helpers = ['Playwright', 'WebDriver', 'Puppeteer', 'REST', 'GraphQL', 'Appium', 'TestCafe']
29
- const translations = Object.keys(require('../../translations'))
30
-
29
+ const helpers = ['Playwright', 'WebDriver', 'Puppeteer', 'REST', 'GraphQL', 'Appium']
31
30
  const noTranslation = 'English (no localization)'
32
- translations.unshift(noTranslation)
31
+
32
+ async function getTranslations() {
33
+ const translationsModule = await import('../../translations/index.js')
34
+ const translations = Object.keys(translationsModule.default || translationsModule)
35
+ translations.unshift(noTranslation)
36
+ return translations
37
+ }
33
38
 
34
39
  const packages = []
35
40
  let isTypeScript = false
36
41
  let extension = 'js'
37
42
 
38
- const requireCodeceptConfigure = "const { setHeadlessWhen, setCommonPlugins } = require('@codeceptjs/configure');"
39
43
  const importCodeceptConfigure = "import { setHeadlessWhen, setCommonPlugins } from '@codeceptjs/configure';"
40
44
 
41
45
  const configHeader = `
@@ -50,7 +54,7 @@ setCommonPlugins();
50
54
 
51
55
  const defaultActor = `// in this file you can append custom step methods to 'I' object
52
56
 
53
- module.exports = function() {
57
+ export default function() {
54
58
  return actor({
55
59
 
56
60
  // Define custom steps here, use 'this' to access default methods of I.
@@ -72,8 +76,9 @@ export = function() {
72
76
  }
73
77
  `
74
78
 
75
- module.exports = function (initPath) {
79
+ export default async function (initPath) {
76
80
  const testsPath = getTestRoot(initPath)
81
+ const translations = await getTranslations()
77
82
 
78
83
  print()
79
84
  print(` Welcome to ${colors.magenta.bold('CodeceptJS')} initialization tool`)
@@ -151,7 +156,7 @@ module.exports = function (initPath) {
151
156
  choices: translations,
152
157
  },
153
158
  ])
154
- .then(result => {
159
+ .then(async result => {
155
160
  if (result.typescript === true) {
156
161
  isTypeScript = true
157
162
  extension = isTypeScript === true ? 'ts' : 'js'
@@ -187,7 +192,8 @@ module.exports = function (initPath) {
187
192
  let helperConfigs = []
188
193
 
189
194
  try {
190
- const Helper = require(`../helper/${helperName}`)
195
+ const HelperModule = await import(`../helper/${helperName}.js`)
196
+ const Helper = HelperModule.default || HelperModule
191
197
  if (Helper._checkRequirements) {
192
198
  packages.concat(Helper._checkRequirements())
193
199
  }
@@ -212,9 +218,9 @@ module.exports = function (initPath) {
212
218
  fs.writeFileSync(path.join(testsPath, stepFile), extension === 'ts' ? defaultActorTs : defaultActor)
213
219
 
214
220
  if (isTypeScript) {
215
- config.include = _actorTranslation('./steps_file', config.translation)
221
+ config.include = await _actorTranslation('./steps_file', config.translation, translations)
216
222
  } else {
217
- config.include = _actorTranslation(stepFile, config.translation)
223
+ config.include = await _actorTranslation(stepFile, config.translation, translations)
218
224
  }
219
225
 
220
226
  print(`Steps file created at ${stepFile}`)
@@ -230,9 +236,9 @@ module.exports = function (initPath) {
230
236
  fs.writeFileSync(typeScriptconfigFile, configSource, 'utf-8')
231
237
  print(`Config created at ${typeScriptconfigFile}`)
232
238
  } else {
233
- configSource = beautify(`/** @type {CodeceptJS.MainConfig} */\nexports.config = ${inspect(config, false, 4, false)}`)
239
+ configSource = beautify(`/** @type {CodeceptJS.MainConfig} */\nexport const config = ${inspect(config, false, 4, false)}`)
234
240
 
235
- if (hasConfigure) configSource = requireCodeceptConfigure + configHeader + configSource
241
+ if (hasConfigure) configSource = importCodeceptConfigure + configHeader + configSource
236
242
 
237
243
  fs.writeFileSync(configFile, configSource, 'utf-8')
238
244
  print(`Config created at ${configFile}`)
@@ -395,7 +401,7 @@ function install(dependencies) {
395
401
  return true
396
402
  }
397
403
 
398
- function _actorTranslation(stepFile, translationSelected) {
404
+ async function _actorTranslation(stepFile, translationSelected, translations) {
399
405
  let actor
400
406
 
401
407
  for (const translationAvailable of translations) {
@@ -404,7 +410,8 @@ function _actorTranslation(stepFile, translationSelected) {
404
410
  }
405
411
 
406
412
  if (translationSelected === translationAvailable) {
407
- const nameOfActor = require('../../translations')[translationAvailable].I
413
+ const translationsModule = await import('../../translations/index.js')
414
+ const nameOfActor = (translationsModule.default || translationsModule)[translationAvailable].I
408
415
 
409
416
  actor = {
410
417
  [nameOfActor]: stepFile,
@@ -1,18 +1,19 @@
1
- const { getConfig, getTestRoot } = require('./utils')
2
- const recorder = require('../recorder')
3
- const Codecept = require('../codecept')
4
- const Container = require('../container')
5
- const event = require('../event')
6
- const output = require('../output')
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'
7
8
  const webHelpers = Container.STANDARD_ACTING_HELPERS
8
9
 
9
- module.exports = async function (path, options) {
10
+ export default async function (path, options) {
10
11
  // Backward compatibility for --profile
11
12
  process.profile = options.profile
12
13
  process.env.profile = options.profile
13
14
  const configFile = options.config
14
15
 
15
- const config = getConfig(configFile)
16
+ const config = await getConfig(configFile)
16
17
  const testsPath = getTestRoot(configFile)
17
18
 
18
19
  const codecept = new Codecept(config, options)
@@ -20,6 +21,7 @@ module.exports = async function (path, options) {
20
21
 
21
22
  try {
22
23
  await codecept.bootstrap()
24
+ await Container.started()
23
25
 
24
26
  if (options.verbose) output.level(3)
25
27
 
@@ -51,8 +53,7 @@ module.exports = async function (path, options) {
51
53
  break
52
54
  }
53
55
  }
54
- require('../pause')()
55
- // recorder.catchWithoutStop((err) => console.log(err.stack));
56
+ pause()
56
57
  recorder.add(() => event.emit(event.test.after, {}))
57
58
  recorder.add(() => event.emit(event.suite.after, {}))
58
59
  recorder.add(() => event.emit(event.all.result, {}))
@@ -1,15 +1,16 @@
1
- const { getConfig, getTestRoot } = require('./utils')
2
- const Codecept = require('../codecept')
3
- const container = require('../container')
4
- const { getParamsToString } = require('../parser')
5
- const { methodsOfObject } = require('../utils')
6
- const output = require('../output')
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
- module.exports = function (path) {
8
+ export default async function (path) {
9
9
  const testsPath = getTestRoot(path)
10
- const config = getConfig(testsPath)
10
+ const config = await getConfig(testsPath)
11
11
  const codecept = new Codecept(config, {})
12
- codecept.init(testsPath)
12
+ await codecept.init(testsPath)
13
+ await container.started()
13
14
 
14
15
  output.print('List of test actions: -- ')
15
16
  const helpers = container.helpers()
@@ -1,6 +1,6 @@
1
- const { globSync } = require('glob')
2
- const path = require('path')
3
- const fs = require('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.
@@ -89,6 +89,6 @@ const createChunks = (config, patterns = []) => {
89
89
  })
90
90
  }
91
91
 
92
- module.exports = {
93
- createChunks,
92
+ export {
93
+ createChunks
94
94
  }
@@ -1,5 +1,5 @@
1
- const { createChunks } = require('./chunk');
2
- const { createRun } = require('./run');
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
- module.exports = {
194
- createRuns,
195
- };
193
+ export {
194
+ createRuns
195
+ }
@@ -25,6 +25,6 @@ const createRun = (name, config) => {
25
25
  return new Run(name, config);
26
26
  };
27
27
 
28
- module.exports = {
29
- createRun,
30
- };
28
+ export {
29
+ createRun
30
+ }
@@ -1,13 +1,16 @@
1
- const { fork } = require('child_process')
2
- const path = require('path')
3
- const crypto = require('crypto')
4
-
5
- const runHook = require('../hooks')
6
- const event = require('../event')
7
- const collection = require('./run-multiple/collection')
8
- const { clearString, replaceValueDeep } = require('../utils')
9
- const { getConfig, getTestRoot, fail } = require('./utils')
10
-
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)
11
14
  const runner = path.join(__dirname, '/../../bin/codecept')
12
15
  let config
13
16
  const childOpts = {}
@@ -24,7 +27,7 @@ let subprocessCount = 0
24
27
  let totalSubprocessCount = 0
25
28
  let processesDone
26
29
 
27
- module.exports = async function (selectedRuns, options) {
30
+ export default async function (selectedRuns, options) {
28
31
  // registering options globally to use in config
29
32
  if (options.profile) {
30
33
  process.env.profile = options.profile
@@ -49,7 +52,7 @@ module.exports = async function (selectedRuns, options) {
49
52
  }
50
53
 
51
54
  config = {
52
- ...getConfig(configFile),
55
+ ...(await getConfig(configFile)),
53
56
  ...overrides,
54
57
  }
55
58
 
@@ -88,7 +91,7 @@ module.exports = async function (selectedRuns, options) {
88
91
  })
89
92
 
90
93
  const runsToExecute = []
91
- collection.createRuns(selectedRuns, config).forEach(run => {
94
+ createRuns(selectedRuns, config).forEach(run => {
92
95
  const runName = run.getOriginalName() || run.getName()
93
96
  const runConfig = run.getConfig()
94
97
  runsToExecute.push(executeRun(runName, runConfig))
@@ -1,16 +1,15 @@
1
- const { getConfig, getTestRoot } = require('./utils')
2
- const { printError, createOutputDir } = require('./utils')
3
- const Config = require('../config')
4
- const Codecept = require('../rerun')
1
+ import { getConfig, getTestRoot, printError, createOutputDir } from './utils.js'
2
+ import Config from '../config.js'
3
+ import Codecept from '../rerun.js'
5
4
 
6
- module.exports = async function (test, options) {
5
+ export default async function (test, options) {
7
6
  // registering options globally to use in config
8
7
  // Backward compatibility for --profile
9
8
  process.profile = options.profile
10
9
  process.env.profile = options.profile
11
10
  const configFile = options.config
12
11
 
13
- let config = getConfig(configFile)
12
+ let config = await getConfig(configFile)
14
13
  if (options.override) {
15
14
  config = Config.append(JSON.parse(options.override))
16
15
  }
@@ -20,7 +19,7 @@ module.exports = async function (test, options) {
20
19
  const codecept = new Codecept(config, options)
21
20
 
22
21
  try {
23
- codecept.init(testRoot)
22
+ await codecept.init(testRoot)
24
23
 
25
24
  await codecept.bootstrap()
26
25
  codecept.loadTests(test)
@@ -1,11 +1,13 @@
1
1
  // For Node version >=10.5.0, have to use experimental flag
2
- const { tryOrDefault } = require('../utils')
3
- const output = require('../output')
4
- const store = require('../store')
5
- const event = require('../event')
6
- const Workers = require('../workers')
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'
7
9
 
8
- module.exports = async function (workerCount, selectedRuns, options) {
10
+ export default async function (workerCount, selectedRuns, options) {
9
11
  process.env.profile = options.profile
10
12
 
11
13
  const { config: testConfig, override = '' } = options
@@ -36,7 +38,7 @@ module.exports = async function (workerCount, selectedRuns, options) {
36
38
 
37
39
  const numberOfWorkers = parseInt(workerCount, 10)
38
40
 
39
- output.print(`CodeceptJS v${require('../codecept').version()} ${output.standWithUkraine()}`)
41
+ output.print(`CodeceptJS v${Codecept.version()} ${output.standWithUkraine()}`)
40
42
  output.print(`Running tests in ${output.styles.bold(numberOfWorkers)} workers...`)
41
43
  output.print()
42
44
  store.hasWorkers = true
@@ -64,15 +66,28 @@ module.exports = async function (workerCount, selectedRuns, options) {
64
66
  if (options.verbose || options.debug) store.debugMode = true
65
67
 
66
68
  if (options.verbose) {
67
- const { getMachineInfo } = require('./info')
68
69
  await getMachineInfo()
69
70
  }
70
71
  await workers.bootstrapAll()
71
72
  await workers.run()
72
73
  } catch (err) {
73
74
  output.error(err)
74
- process.exit(1)
75
+ process.exitCode = 1
75
76
  } finally {
76
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
+ }
77
92
  }
78
93
  }
@@ -1,9 +1,10 @@
1
- const { getConfig, printError, getTestRoot, createOutputDir } = require('./utils')
2
- const Config = require('../config')
3
- const store = require('../store')
4
- const Codecept = require('../codecept')
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'
5
6
 
6
- module.exports = async function (test, options) {
7
+ export default async function (test, options) {
7
8
  // registering options globally to use in config
8
9
  // Backward compatibility for --profile
9
10
  // TODO: remove in CodeceptJS 4
@@ -16,7 +17,7 @@ module.exports = async function (test, options) {
16
17
 
17
18
  const configFile = options.config
18
19
 
19
- let config = getConfig(configFile)
20
+ let config = await getConfig(configFile)
20
21
  if (options.override) {
21
22
  config = Config.append(JSON.parse(options.override))
22
23
  }
@@ -26,13 +27,13 @@ module.exports = async function (test, options) {
26
27
  const codecept = new Codecept(config, options)
27
28
 
28
29
  try {
29
- codecept.init(testRoot)
30
+ await codecept.init(testRoot)
30
31
  await codecept.bootstrap()
31
32
  codecept.loadTests(test)
32
33
 
33
34
  if (options.verbose) {
34
35
  global.debugMode = true
35
- const { getMachineInfo } = require('./info')
36
+ const { getMachineInfo } = await import('./info.js')
36
37
  await getMachineInfo()
37
38
  }
38
39
 
@@ -42,5 +43,19 @@ module.exports = async function (test, options) {
42
43
  process.exitCode = 1
43
44
  } finally {
44
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
+ }
45
60
  }
46
61
  }
@@ -1,23 +1,25 @@
1
- const fs = require('fs')
2
- const path = require('path')
3
- const util = require('util')
4
- const mkdirp = require('mkdirp')
1
+ import fs from 'fs'
2
+ import path from 'path'
3
+ import util from 'util'
4
+ import { mkdirp } from 'mkdirp'
5
5
 
6
- const output = require('../output')
7
- const { fileExists, beautify } = require('../utils')
6
+ import output from '../output.js'
7
+ import { fileExists, beautify, deepMerge } from '../utils.js'
8
8
 
9
9
  // alias to deep merge
10
- module.exports.deepMerge = require('../utils').deepMerge
10
+ export { deepMerge }
11
11
 
12
- module.exports.getConfig = function (configFile) {
12
+ export async function getConfig(configFile) {
13
13
  try {
14
- return require('../config').load(configFile)
14
+ const configModule = await import('../config.js')
15
+ const config = configModule.default || configModule
16
+ return await config.load(configFile)
15
17
  } catch (err) {
16
18
  fail(err.stack)
17
19
  }
18
20
  }
19
21
 
20
- module.exports.readConfig = function (configFile) {
22
+ export function readConfig(configFile) {
21
23
  try {
22
24
  const data = fs.readFileSync(configFile, 'utf8')
23
25
  return data
@@ -32,14 +34,14 @@ function getTestRoot(currentPath) {
32
34
  currentPath = fs.lstatSync(currentPath).isDirectory() || !path.extname(currentPath) ? currentPath : path.dirname(currentPath)
33
35
  return currentPath
34
36
  }
35
- module.exports.getTestRoot = getTestRoot
37
+ export { getTestRoot }
36
38
 
37
39
  function fail(msg) {
38
40
  output.error(msg)
39
41
  process.exit(1)
40
42
  }
41
43
 
42
- module.exports.fail = fail
44
+ export { fail }
43
45
 
44
46
  function updateConfig(testsPath, config, extension) {
45
47
  const configFile = path.join(testsPath, `codecept.conf.${extension}`)
@@ -57,7 +59,7 @@ function updateConfig(testsPath, config, extension) {
57
59
  return fs.writeFileSync(configFile, beautify(`exports.config = ${util.inspect(config, false, 4, false)}`), 'utf-8')
58
60
  }
59
61
 
60
- module.exports.updateConfig = updateConfig
62
+ export { updateConfig }
61
63
 
62
64
  function safeFileWrite(file, contents) {
63
65
  if (fileExists(file)) {
@@ -68,9 +70,9 @@ function safeFileWrite(file, contents) {
68
70
  return true
69
71
  }
70
72
 
71
- module.exports.safeFileWrite = safeFileWrite
73
+ export { safeFileWrite }
72
74
 
73
- module.exports.captureStream = stream => {
75
+ export const captureStream = stream => {
74
76
  let oldStream
75
77
  let buffer = ''
76
78
 
@@ -87,14 +89,14 @@ module.exports.captureStream = stream => {
87
89
  }
88
90
  }
89
91
 
90
- module.exports.printError = err => {
92
+ export const printError = err => {
91
93
  output.print('')
92
94
  output.error(err.message)
93
95
  output.print('')
94
96
  output.print(output.colors.grey(err.stack.replace(err.message, '')))
95
97
  }
96
98
 
97
- module.exports.createOutputDir = (config, testRoot) => {
99
+ export const createOutputDir = (config, testRoot) => {
98
100
  let outputDir
99
101
  if (path.isAbsolute(config.output)) outputDir = config.output
100
102
  else outputDir = path.join(testRoot, config.output)
@@ -105,7 +107,7 @@ module.exports.createOutputDir = (config, testRoot) => {
105
107
  }
106
108
  }
107
109
 
108
- module.exports.findConfigFile = testsPath => {
110
+ export const findConfigFile = testsPath => {
109
111
  const extensions = ['js', 'ts']
110
112
  for (const ext of extensions) {
111
113
  const configFile = path.join(testsPath, `codecept.conf.${ext}`)