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,7 +1,7 @@
1
- const Assertion = require('../assert')
2
- const AssertionFailedError = require('./error')
3
- const { template } = require('../utils')
4
- const output = require('../output')
1
+ import Assertion from '../assert.js'
2
+ import AssertionFailedError from './error.js'
3
+ import { template } from '../utils.js'
4
+ import output from '../output.js'
5
5
 
6
6
  class EqualityAssertion extends Assertion {
7
7
  constructor(params) {
@@ -37,18 +37,16 @@ class EqualityAssertion extends Assertion {
37
37
  }
38
38
  }
39
39
 
40
- module.exports = {
41
- Assertion: EqualityAssertion,
42
- equals: jar => new EqualityAssertion({ jar }),
43
- urlEquals: baseUrl => {
44
- const assert = new EqualityAssertion({ jar: 'url of current page' })
45
- assert.comparator = function (expected, actual) {
46
- if (expected.indexOf('http') !== 0) {
47
- actual = actual.slice(actual.indexOf(baseUrl) + baseUrl.length)
48
- }
49
- return actual === expected
40
+ export { EqualityAssertion as Assertion }
41
+ export const equals = jar => new EqualityAssertion({ jar })
42
+ export const urlEquals = baseUrl => {
43
+ const assert = new EqualityAssertion({ jar: 'url of current page' })
44
+ assert.comparator = function (expected, actual) {
45
+ if (expected.indexOf('http') !== 0) {
46
+ actual = actual.slice(actual.indexOf(baseUrl) + baseUrl.length)
50
47
  }
51
- return assert
52
- },
53
- fileEquals: file => new EqualityAssertion({ file, jar: 'contents of {{file}}' }),
48
+ return actual === expected
49
+ }
50
+ return assert
54
51
  }
52
+ export const fileEquals = file => new EqualityAssertion({ file, jar: 'contents of {{file}}' })
@@ -1,4 +1,4 @@
1
- const subs = require('../utils').template
1
+ import { template as subs } from '../utils.js'
2
2
 
3
3
  /**
4
4
  * Assertion errors, can provide a detailed error messages.
@@ -29,4 +29,4 @@ function AssertionFailedError(params, template) {
29
29
  AssertionFailedError.prototype = Object.create(Error.prototype)
30
30
  AssertionFailedError.constructor = AssertionFailedError
31
31
 
32
- module.exports = AssertionFailedError
32
+ export default AssertionFailedError
@@ -1,7 +1,7 @@
1
- const Assertion = require('../assert')
2
- const AssertionFailedError = require('./error')
3
- const { template } = require('../utils')
4
- const output = require('../output')
1
+ import Assertion from '../assert.js'
2
+ import AssertionFailedError from './error.js'
3
+ import { template } from '../utils.js'
4
+ import output from '../output.js'
5
5
 
6
6
  const MAX_LINES = 10
7
7
 
@@ -62,14 +62,12 @@ class InclusionAssertion extends Assertion {
62
62
  }
63
63
  }
64
64
 
65
- module.exports = {
66
- Assertion: InclusionAssertion,
67
- includes: needleType => {
68
- needleType = needleType || 'string'
69
- return new InclusionAssertion({ jar: needleType })
70
- },
71
- fileIncludes: file => new InclusionAssertion({ file, jar: 'file {{file}}' }),
65
+ export { InclusionAssertion as Assertion }
66
+ export const includes = needleType => {
67
+ needleType = needleType || 'string'
68
+ return new InclusionAssertion({ jar: needleType })
72
69
  }
70
+ export const fileIncludes = file => new InclusionAssertion({ file, jar: 'file {{file}}' })
73
71
 
74
72
  function escapeRegExp(str) {
75
73
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&')
@@ -17,4 +17,4 @@ function errorThrown(actual, expected) {
17
17
  return null
18
18
  }
19
19
 
20
- module.exports = errorThrown
20
+ export default errorThrown
@@ -1,7 +1,7 @@
1
- const Assertion = require('../assert')
2
- const AssertionFailedError = require('./error')
3
- const { template } = require('../utils')
4
- const output = require('../output')
1
+ import Assertion from '../assert.js'
2
+ import AssertionFailedError from './error.js'
3
+ import { template } from '../utils.js'
4
+ import output from '../output.js'
5
5
 
6
6
  class TruthAssertion extends Assertion {
7
7
  constructor(params) {
@@ -30,7 +30,10 @@ class TruthAssertion extends Assertion {
30
30
  }
31
31
  }
32
32
 
33
- module.exports = {
33
+ export { TruthAssertion as Assertion }
34
+ export const truth = (subject, type) => new TruthAssertion({ subject, type })
35
+
36
+ export default {
34
37
  Assertion: TruthAssertion,
35
38
  truth: (subject, type) => new TruthAssertion({ subject, type }),
36
39
  }
package/lib/assert.js CHANGED
@@ -1,4 +1,4 @@
1
- const AssertionFailedError = require('./assert/error');
1
+ import AssertionFailedError from './assert/error.js'
2
2
 
3
3
  /**
4
4
  * Abstract assertion class introduced for more verbose and customizable messages.
@@ -22,9 +22,9 @@ const AssertionFailedError = require('./assert/error');
22
22
  */
23
23
  class Assertion {
24
24
  constructor(comparator, params) {
25
- this.comparator = comparator;
26
- this.params = params || {};
27
- this.params.customMessage = '';
25
+ this.comparator = comparator
26
+ this.params = params || {}
27
+ this.params.customMessage = ''
28
28
  }
29
29
 
30
30
  /**
@@ -32,10 +32,10 @@ class Assertion {
32
32
  * Fails if comparator function with provided arguments returns false
33
33
  */
34
34
  assert() {
35
- this.addAssertParams.apply(this, arguments);
36
- const result = this.comparator.apply(this.params, arguments);
37
- if (result) return; // should increase global assertion counter
38
- throw this.getFailedAssertion();
35
+ this.addAssertParams.apply(this, arguments)
36
+ const result = this.comparator.apply(this.params, arguments)
37
+ if (result) return // should increase global assertion counter
38
+ throw this.getFailedAssertion()
39
39
  }
40
40
 
41
41
  /**
@@ -43,10 +43,10 @@ class Assertion {
43
43
  * Fails if comparator function with provided arguments returns true
44
44
  */
45
45
  negate() {
46
- this.addAssertParams.apply(this, arguments);
47
- const result = this.comparator.apply(this.params, arguments);
48
- if (!result) return; // should increase global assertion counter
49
- throw this.getFailedNegation();
46
+ this.addAssertParams.apply(this, arguments)
47
+ const result = this.comparator.apply(this.params, arguments)
48
+ if (!result) return // should increase global assertion counter
49
+ throw this.getFailedNegation()
50
50
  }
51
51
 
52
52
  /**
@@ -55,18 +55,18 @@ class Assertion {
55
55
  addAssertParams() {}
56
56
 
57
57
  getException() {
58
- return new AssertionFailedError(this.params, '');
58
+ return new AssertionFailedError(this.params, '')
59
59
  }
60
60
 
61
61
  getFailedNegation() {
62
- const err = this.getException();
63
- err.params.type = `not ${err.params.type}`;
64
- return err;
62
+ const err = this.getException()
63
+ err.params.type = `not ${err.params.type}`
64
+ return err
65
65
  }
66
66
 
67
67
  getFailedAssertion() {
68
- return this.getException();
68
+ return this.getException()
69
69
  }
70
70
  }
71
71
 
72
- module.exports = Assertion;
72
+ export default Assertion
package/lib/codecept.js CHANGED
@@ -1,15 +1,34 @@
1
- const { existsSync, readFileSync } = require('fs')
2
- const { globSync } = require('glob')
3
- const shuffle = require('lodash.shuffle')
4
- const fsPath = require('path')
5
- const { resolve } = require('path')
6
-
7
- const container = require('./container')
8
- const Config = require('./config')
9
- const event = require('./event')
10
- const runHook = require('./hooks')
11
- const output = require('./output')
12
- const { emptyFolder } = require('./utils')
1
+ import { existsSync, readFileSync } from 'fs'
2
+ import { globSync } from 'glob'
3
+ import shuffle from 'lodash.shuffle'
4
+ import fsPath from 'path'
5
+ import { resolve } from 'path'
6
+ import { fileURLToPath } from 'url'
7
+ import { dirname } from 'path'
8
+
9
+ const __filename = fileURLToPath(import.meta.url)
10
+ const __dirname = dirname(__filename)
11
+
12
+ import Helper from '@codeceptjs/helper'
13
+ import container from './container.js'
14
+ import Config from './config.js'
15
+ import event from './event.js'
16
+ import runHook from './hooks.js'
17
+ import ActorFactory from './actor.js'
18
+ import output from './output.js'
19
+ import { emptyFolder } from './utils.js'
20
+ import { initCodeceptGlobals } from './globals.js'
21
+ import recorder from './recorder.js'
22
+
23
+ import storeListener from './listener/store.js'
24
+ import stepsListener from './listener/steps.js'
25
+ import configListener from './listener/config.js'
26
+ import resultListener from './listener/result.js'
27
+ import helpersListener from './listener/helpers.js'
28
+ import globalTimeoutListener from './listener/globalTimeout.js'
29
+ import globalRetryListener from './listener/globalRetry.js'
30
+ import exitListener from './listener/exit.js'
31
+ import emptyRunListener from './listener/emptyRun.js'
13
32
 
14
33
  /**
15
34
  * CodeceptJS runner
@@ -26,7 +45,7 @@ class Codecept {
26
45
  this.config = Config.create(config)
27
46
  this.opts = opts
28
47
  this.testFiles = new Array(0)
29
- this.requireModules(config.require)
48
+ this.requiringModules = config.require
30
49
  }
31
50
 
32
51
  /**
@@ -34,29 +53,41 @@ class Codecept {
34
53
  *
35
54
  * @param {string[]} requiringModules
36
55
  */
37
- requireModules(requiringModules) {
56
+ async requireModules(requiringModules) {
38
57
  if (requiringModules) {
39
- requiringModules.forEach(requiredModule => {
40
- const isLocalFile = existsSync(requiredModule) || existsSync(`${requiredModule}.js`)
58
+ for (const requiredModule of requiringModules) {
59
+ let modulePath = requiredModule
60
+ const isLocalFile = existsSync(modulePath) || existsSync(`${modulePath}.js`)
41
61
  if (isLocalFile) {
42
- requiredModule = resolve(requiredModule)
62
+ modulePath = resolve(modulePath)
63
+ // For ESM, ensure .js extension for local files
64
+ if (!modulePath.endsWith('.js') && !modulePath.endsWith('.mjs') && !modulePath.endsWith('.cjs')) {
65
+ if (existsSync(`${modulePath}.js`)) {
66
+ modulePath = `${modulePath}.js`
67
+ }
68
+ }
43
69
  }
44
- require(requiredModule)
45
- })
70
+ // Use dynamic import for ESM
71
+ await import(modulePath)
72
+ }
46
73
  }
47
74
  }
48
75
 
49
76
  /**
50
- * Initialize CodeceptJS at specific directory.
51
- * If async initialization is required, pass callback as second parameter.
77
+ * Initialize CodeceptJS at specific dir.
78
+ * Loads config, requires factory methods
52
79
  *
53
80
  * @param {string} dir
54
81
  */
55
- init(dir) {
56
- this.initGlobals(dir)
82
+ async init(dir) {
83
+ await this.initGlobals(dir)
84
+ // Require modules before initializing
85
+ await this.requireModules(this.requiringModules)
57
86
  // initializing listeners
58
- container.create(this.config, this.opts)
59
- this.runHooks()
87
+ await container.create(this.config, this.opts)
88
+ // Store container globally for easy access
89
+ global.container = container
90
+ await this.runHooks()
60
91
  }
61
92
 
62
93
  /**
@@ -64,56 +95,32 @@ class Codecept {
64
95
  *
65
96
  * @param {string} dir
66
97
  */
67
- initGlobals(dir) {
68
- global.codecept_dir = dir
69
- global.output_dir = fsPath.resolve(dir, this.config.output)
70
-
71
- if (this.config.emptyOutputFolder) emptyFolder(global.output_dir)
72
-
73
- if (!this.config.noGlobals) {
74
- global.Helper = global.codecept_helper = require('@codeceptjs/helper')
75
- global.actor = global.codecept_actor = require('./actor')
76
- global.pause = require('./pause')
77
- global.within = require('./within')
78
- global.session = require('./session')
79
- global.DataTable = require('./data/table')
80
- global.locate = locator => require('./locator').build(locator)
81
- global.inject = container.support
82
- global.share = container.share
83
- global.secret = require('./secret').secret
84
- global.codecept_debug = output.debug
85
- global.codeceptjs = require('./index') // load all objects
86
-
87
- // BDD
88
- const stepDefinitions = require('./mocha/bdd')
89
- global.Given = stepDefinitions.Given
90
- global.When = stepDefinitions.When
91
- global.Then = stepDefinitions.Then
92
- global.DefineParameterType = stepDefinitions.defineParameterType
93
-
94
- // debug mode
95
- global.debugMode = false
96
-
97
- // mask sensitive data
98
- global.maskSensitiveData = this.config.maskSensitiveData || false
99
- }
98
+ async initGlobals(dir) {
99
+ await initCodeceptGlobals(dir, this.config, container)
100
100
  }
101
101
 
102
102
  /**
103
103
  * Executes hooks.
104
104
  */
105
- runHooks() {
106
- // default hooks
107
- runHook(require('./listener/store'))
108
- runHook(require('./listener/steps'))
109
- runHook(require('./listener/config'))
110
- runHook(require('./listener/result'))
111
- runHook(require('./listener/helpers'))
112
- runHook(require('./listener/globalTimeout'))
113
- runHook(require('./listener/globalRetry'))
114
- runHook(require('./listener/retryEnhancer'))
115
- runHook(require('./listener/exit'))
116
- runHook(require('./listener/emptyRun'))
105
+ async runHooks() {
106
+ // default hooks - dynamic imports for ESM
107
+ const listenerModules = [
108
+ './listener/store.js',
109
+ './listener/steps.js',
110
+ './listener/config.js',
111
+ './listener/result.js',
112
+ './listener/helpers.js',
113
+ './listener/globalTimeout.js',
114
+ './listener/globalRetry.js',
115
+ './listener/retryEnhancer.js',
116
+ './listener/exit.js',
117
+ './listener/emptyRun.js',
118
+ ]
119
+
120
+ for (const modulePath of listenerModules) {
121
+ const module = await import(modulePath)
122
+ runHook(module.default || module)
123
+ }
117
124
 
118
125
  // custom hooks (previous iteration of plugins)
119
126
  this.config.hooks.forEach(hook => runHook(hook))
@@ -160,7 +167,7 @@ class Codecept {
160
167
  }
161
168
  }
162
169
 
163
- if (this.config.gherkin.features && !this.opts.tests) {
170
+ if (this.config.gherkin && this.config.gherkin.features && !this.opts.tests) {
164
171
  if (Array.isArray(this.config.gherkin.features)) {
165
172
  this.config.gherkin.features.forEach(feature => {
166
173
  patterns.push(feature)
@@ -239,24 +246,44 @@ class Codecept {
239
246
  async run(test) {
240
247
  await container.started()
241
248
 
249
+ // Ensure translations are loaded for Gherkin features
250
+ try {
251
+ const { loadTranslations } = await import('./mocha/gherkin.js')
252
+ await loadTranslations()
253
+ } catch (e) {
254
+ // Ignore if gherkin module not available
255
+ }
256
+
242
257
  return new Promise((resolve, reject) => {
243
258
  const mocha = container.mocha()
244
259
  mocha.files = this.testFiles
260
+
245
261
  if (test) {
246
262
  if (!fsPath.isAbsolute(test)) {
247
263
  test = fsPath.join(global.codecept_dir, test)
248
264
  }
249
- mocha.files = mocha.files.filter(t => fsPath.basename(t, '.js') === test || t === test)
265
+ const testBasename = fsPath.basename(test, '.js')
266
+ const testFeatureBasename = fsPath.basename(test, '.feature')
267
+ mocha.files = mocha.files.filter(t => {
268
+ return fsPath.basename(t, '.js') === testBasename || fsPath.basename(t, '.feature') === testFeatureBasename || t === test
269
+ })
250
270
  }
251
- const done = () => {
271
+
272
+ const done = async (failures) => {
252
273
  event.emit(event.all.result, container.result())
253
274
  event.emit(event.all.after, this)
275
+ // Wait for any recorder tasks added by event.all.after handlers
276
+ await recorder.promise()
277
+ // Set exit code based on test failures
278
+ if (failures) {
279
+ process.exitCode = 1
280
+ }
254
281
  resolve()
255
282
  }
256
283
 
257
284
  try {
258
285
  event.emit(event.all.before, this)
259
- mocha.run(() => done())
286
+ mocha.run(async (failures) => await done(failures))
260
287
  } catch (e) {
261
288
  output.error(e.stack)
262
289
  reject(e)
@@ -274,4 +301,4 @@ class Codecept {
274
301
  }
275
302
  }
276
303
 
277
- module.exports = Codecept
304
+ export default Codecept
package/lib/colorUtils.js CHANGED
@@ -144,14 +144,14 @@ function convertColorNameToHex(color) {
144
144
  whitesmoke: '#f5f5f5',
145
145
  yellow: '#ffff00',
146
146
  yellowgreen: '#9acd32',
147
- };
147
+ }
148
148
 
149
- const cColor = `${color}`.toLowerCase();
149
+ const cColor = `${color}`.toLowerCase()
150
150
  if (typeof colors[cColor] !== 'undefined') {
151
- return colors[cColor];
151
+ return colors[cColor]
152
152
  }
153
153
 
154
- return color;
154
+ return color
155
155
  }
156
156
 
157
157
  /**
@@ -160,23 +160,23 @@ function convertColorNameToHex(color) {
160
160
  */
161
161
  function convertHexColorToRgba(hex) {
162
162
  // Expand shorthand form (e.g. "#03F") to full form (e.g. "#0033FF")
163
- const shorthandRegex = /^#([a-f\d])([a-f\d])([a-f\d])$/i;
163
+ const shorthandRegex = /^#([a-f\d])([a-f\d])([a-f\d])$/i
164
164
  const hexFull = `${hex}`.replace(shorthandRegex, (m, r, g, b) => {
165
- return r + r + g + g + b + b;
166
- });
165
+ return r + r + g + g + b + b
166
+ })
167
167
 
168
- const result = /^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hexFull);
168
+ const result = /^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hexFull)
169
169
  if (!result) {
170
170
  // Return untouched if not a hex code
171
- return hex;
171
+ return hex
172
172
  }
173
173
 
174
- const r = parseInt(result[1], 16);
175
- const g = parseInt(result[2], 16);
176
- const b = parseInt(result[3], 16);
177
- const a = 1;
174
+ const r = parseInt(result[1], 16)
175
+ const g = parseInt(result[2], 16)
176
+ const b = parseInt(result[3], 16)
177
+ const a = 1
178
178
 
179
- return `rgba(${r}, ${g}, ${b}, ${a})`;
179
+ return `rgba(${r}, ${g}, ${b}, ${a})`
180
180
  }
181
181
 
182
182
  /**
@@ -190,29 +190,29 @@ function convertHexColorToRgba(hex) {
190
190
  * @param {string} color Color as a string, i.e. rgb(85,0,0)
191
191
  */
192
192
  function convertColorToRGBA(color) {
193
- const cstr = `${color}`.toLowerCase().trim() || '';
193
+ const cstr = `${color}`.toLowerCase().trim() || ''
194
194
 
195
195
  if (!/^rgba?\(.+?\)$/.test(cstr)) {
196
196
  // Convert both color names and hex colors to rgba
197
- const hexColor = convertColorNameToHex(color);
198
- return convertHexColorToRgba(hexColor);
197
+ const hexColor = convertColorNameToHex(color)
198
+ return convertHexColorToRgba(hexColor)
199
199
  }
200
200
 
201
201
  // Convert rgb to rgba
202
- const channels = cstr.match(/([\-0-9.]+)/g) || [];
202
+ const channels = cstr.match(/([\-0-9.]+)/g) || []
203
203
 
204
204
  switch (channels.length) {
205
205
  case 3:
206
206
  // Convert rgb to rgba
207
- return `rgba(${channels.join(', ')}, 1)`;
207
+ return `rgba(${channels.join(', ')}, 1)`
208
208
 
209
209
  case 4:
210
210
  // Format rgba
211
- return `rgba(${channels.join(', ')})`;
211
+ return `rgba(${channels.join(', ')})`
212
212
 
213
213
  default:
214
214
  // Unexpected color format. Leave it untouched (let the user handle it)
215
- return color;
215
+ return color
216
216
  }
217
217
  }
218
218
 
@@ -222,34 +222,32 @@ function convertColorToRGBA(color) {
222
222
  * @param {string} prop CSS Property name
223
223
  */
224
224
  function isColorProperty(prop) {
225
- return [
226
- 'color',
227
- 'background',
228
- 'backgroundColor',
229
- 'background-color',
230
- 'borderColor',
231
- 'border-color',
232
- 'borderBottomColor',
233
- 'border-bottom-color',
234
- 'borderLeftColor',
235
- 'border-left-color',
236
- 'borderRightColor',
237
- 'borderTopColor',
238
- 'caretColor',
239
- 'columnRuleColor',
240
- 'outlineColor',
241
- 'textDecorationColor',
242
- 'border-right-color',
243
- 'border-top-color',
244
- 'caret-color',
245
- 'column-rule-color',
246
- 'outline-color',
247
- 'text-decoration-color',
248
- ].indexOf(prop) > -1;
225
+ return (
226
+ [
227
+ 'color',
228
+ 'background',
229
+ 'backgroundColor',
230
+ 'background-color',
231
+ 'borderColor',
232
+ 'border-color',
233
+ 'borderBottomColor',
234
+ 'border-bottom-color',
235
+ 'borderLeftColor',
236
+ 'border-left-color',
237
+ 'borderRightColor',
238
+ 'borderTopColor',
239
+ 'caretColor',
240
+ 'columnRuleColor',
241
+ 'outlineColor',
242
+ 'textDecorationColor',
243
+ 'border-right-color',
244
+ 'border-top-color',
245
+ 'caret-color',
246
+ 'column-rule-color',
247
+ 'outline-color',
248
+ 'text-decoration-color',
249
+ ].indexOf(prop) > -1
250
+ )
249
251
  }
250
252
 
251
- module.exports = {
252
- isColorProperty,
253
- convertColorToRGBA,
254
- convertColorNameToHex,
255
- };
253
+ export { isColorProperty, convertColorToRGBA, convertColorNameToHex }