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
package/lib/secret.js CHANGED
@@ -1,20 +1,20 @@
1
- const { deepClone } = require('./utils');
1
+ import { deepClone } from './utils.js'
2
2
 
3
- const maskedString = '*****';
3
+ const maskedString = '*****'
4
4
 
5
5
  /** @param {string} secret */
6
6
  class Secret {
7
7
  constructor(secret) {
8
- this._secret = secret;
8
+ this._secret = secret
9
9
  }
10
10
 
11
11
  /** @returns {string} */
12
12
  toString() {
13
- return this._secret;
13
+ return this._secret
14
14
  }
15
15
 
16
16
  getMasked() {
17
- return maskedString;
17
+ return maskedString
18
18
  }
19
19
 
20
20
  /**
@@ -23,11 +23,11 @@ class Secret {
23
23
  */
24
24
  static secret(secret) {
25
25
  if (typeof secret === 'object') {
26
- const fields = Array.from(arguments);
27
- fields.shift();
28
- return secretObject(secret, fields);
26
+ const fields = Array.from(arguments)
27
+ fields.shift()
28
+ return secretObject(secret, fields)
29
29
  }
30
- return new Secret(secret);
30
+ return new Secret(secret)
31
31
  }
32
32
  }
33
33
 
@@ -36,16 +36,17 @@ function secretObject(obj, fieldsToHide = []) {
36
36
  get(obj, prop) {
37
37
  if (prop === 'toString') {
38
38
  return function () {
39
- const maskedObject = deepClone(obj);
40
- fieldsToHide.forEach(f => (maskedObject[f] = maskedString));
41
- return JSON.stringify(maskedObject);
42
- };
39
+ const maskedObject = deepClone(obj)
40
+ fieldsToHide.forEach(f => (maskedObject[f] = maskedString))
41
+ return JSON.stringify(maskedObject)
42
+ }
43
43
  }
44
- return fieldsToHide.includes(prop) ? new Secret(obj[prop]) : obj[prop];
44
+ return fieldsToHide.includes(prop) ? new Secret(obj[prop]) : obj[prop]
45
45
  },
46
- };
46
+ }
47
47
 
48
- return new Proxy(obj, handler);
48
+ return new Proxy(obj, handler)
49
49
  }
50
50
 
51
- module.exports = Secret;
51
+ export default Secret
52
+ export const secret = Secret.secret
package/lib/session.js CHANGED
@@ -1,19 +1,13 @@
1
- const recorder = require('./recorder');
2
- const container = require('./container');
3
- const event = require('./event');
4
- const output = require('./output');
5
- const store = require('./store');
6
- const { isAsyncFunction } = require('./utils');
7
-
8
- const sessionColors = [
9
- 'cyan',
10
- 'blue',
11
- 'red',
12
- 'magenta',
13
- 'yellow',
14
- ];
15
-
16
- const savedSessions = {};
1
+ import recorder from './recorder.js'
2
+ import container from './container.js'
3
+ import event from './event.js'
4
+ import output from './output.js'
5
+ import store from './store.js'
6
+ import { isAsyncFunction } from './utils.js'
7
+
8
+ const sessionColors = ['cyan', 'blue', 'red', 'magenta', 'yellow']
9
+
10
+ const savedSessions = {}
17
11
 
18
12
  /**
19
13
  * @param {CodeceptJS.LocatorOrString} sessionName
@@ -24,109 +18,121 @@ const savedSessions = {};
24
18
  function session(sessionName, config, fn) {
25
19
  if (typeof config === 'function') {
26
20
  if (typeof fn === 'function') {
27
- config = config();
21
+ config = config()
28
22
  } else {
29
23
  // no config but with function
30
- fn = config;
31
- config = {};
24
+ fn = config
25
+ config = {}
32
26
  }
33
27
  }
34
28
  // session helpers won't use beforeSuite and afterSuite hooks...
35
29
  // restart: false options are not allowed as well
36
30
  // but those helpers should be already started so inside listener/helpers.js the `_init` method should already be called
37
31
 
38
- const helpers = container.helpers();
32
+ const helpers = container.helpers()
39
33
 
40
34
  if (!savedSessions[sessionName]) {
41
35
  for (const helper in helpers) {
42
- if (!helpers[helper]._session) continue;
36
+ if (!helpers[helper]._session) continue
43
37
  savedSessions[sessionName] = {
44
38
  start: () => null,
45
39
  stop: () => null,
46
40
  loadVars: () => null,
47
41
  restoreVars: () => null,
48
42
  ...(store.dryRun ? {} : helpers[helper]._session()),
49
- };
50
- break;
43
+ }
44
+ break
51
45
  }
52
46
 
53
47
  const closeBrowsers = () => {
54
- const session = savedSessions[sessionName];
55
- if (!session) return;
56
- session.stop(session.vars);
57
- delete savedSessions[sessionName];
58
- };
48
+ const session = savedSessions[sessionName]
49
+ if (!session) return
50
+ session.stop(session.vars)
51
+ delete savedSessions[sessionName]
52
+ }
59
53
 
60
54
  event.dispatcher.once(event.test.after, () => {
61
- recorder.add('close session browsers', closeBrowsers);
62
- });
55
+ recorder.add('close session browsers', closeBrowsers)
56
+ })
63
57
 
64
58
  if (!savedSessions[sessionName]) {
65
- throw new Error('Configured helpers do not support starting sessions. Please use a helper with session support.');
59
+ throw new Error('Configured helpers do not support starting sessions. Please use a helper with session support.')
66
60
  }
67
61
 
68
62
  recorder.add('save vars', async () => {
69
- savedSessions[sessionName].vars = await savedSessions[sessionName].start(sessionName, config);
70
- });
63
+ savedSessions[sessionName].vars = await savedSessions[sessionName].start(sessionName, config)
64
+ })
71
65
  }
72
66
 
73
67
  // pick random color
74
- const color = sessionColors[Object.keys(savedSessions).indexOf(sessionName) % sessionColors.length];
75
-
76
- const addContextToStep = (step) => {
77
- step.actor = `${output.colors[color](sessionName)}: I`;
78
- };
79
-
80
- if (!fn) return; // no current session steps
81
-
82
- return recorder.add('register session wrapper', async () => {
83
- const session = savedSessions[sessionName];
84
- recorder.session.start(`session:${sessionName}`);
85
- event.dispatcher.on(event.step.after, addContextToStep);
86
- recorder.add('switch to browser', () => {
87
- const session = savedSessions[sessionName];
88
- return session.loadVars(session.vars);
89
- });
90
-
91
- const finalize = () => {
92
- recorder.add('Finalize session', async () => {
93
- output.stepShift = 0;
94
- event.dispatcher.removeListener(event.step.after, addContextToStep);
95
- await session.restoreVars();
96
- recorder.session.restore(`session:${sessionName}`);
97
- });
98
- };
99
-
100
- // Indicate when executing this function that we are in a session
101
- if (isAsyncFunction(fn)) {
102
- return fn.apply(null).then((res) => {
103
- finalize();
104
- return recorder.promise().then(() => res);
105
- }).catch((e) => {
106
- output.stepShift = 0;
107
- session.restoreVars(sessionName);
108
- event.dispatcher.removeListener(event.step.after, addContextToStep);
109
- recorder.throw(e);
110
- return recorder.promise();
111
- });
112
- }
68
+ const color = sessionColors[Object.keys(savedSessions).indexOf(sessionName) % sessionColors.length]
113
69
 
114
- let res;
115
- try {
116
- res = fn.apply(null);
117
- } catch (err) {
118
- recorder.throw(err);
119
- } finally {
120
- recorder.catch((e) => {
121
- session.restoreVars(sessionName);
122
- output.stepShift = 0;
123
- event.dispatcher.removeListener(event.step.after, addContextToStep);
124
- throw e;
125
- });
126
- }
127
- finalize();
128
- return recorder.promise().then(() => res);
129
- }, false, false);
70
+ const addContextToStep = step => {
71
+ step.actor = `${output.colors[color](sessionName)}: I`
72
+ }
73
+
74
+ if (!fn) return // no current session steps
75
+
76
+ return recorder.add(
77
+ 'register session wrapper',
78
+ async () => {
79
+ const session = savedSessions[sessionName]
80
+ if (!session) {
81
+ throw new Error(`Session "${sessionName}" not found. It may have been closed already.`)
82
+ }
83
+ recorder.session.start(`session:${sessionName}`)
84
+ event.dispatcher.on(event.step.after, addContextToStep)
85
+ recorder.add('switch to browser', () => {
86
+ const session = savedSessions[sessionName]
87
+ return session.loadVars(session.vars)
88
+ })
89
+
90
+ const finalize = () => {
91
+ recorder.add('Finalize session', async () => {
92
+ output.stepShift = 0
93
+ event.dispatcher.removeListener(event.step.after, addContextToStep)
94
+ await session.restoreVars()
95
+ recorder.session.restore(`session:${sessionName}`)
96
+ })
97
+ }
98
+
99
+ // Indicate when executing this function that we are in a session
100
+ if (isAsyncFunction(fn)) {
101
+ return fn
102
+ .apply(null)
103
+ .then(async res => {
104
+ finalize()
105
+ await recorder.promise()
106
+ return res
107
+ })
108
+ .catch(e => {
109
+ output.stepShift = 0
110
+ session.restoreVars(sessionName)
111
+ event.dispatcher.removeListener(event.step.after, addContextToStep)
112
+ recorder.throw(e)
113
+ return recorder.promise()
114
+ })
115
+ }
116
+
117
+ let res
118
+ try {
119
+ res = fn.apply(null)
120
+ } catch (err) {
121
+ recorder.throw(err)
122
+ } finally {
123
+ recorder.catch(e => {
124
+ session.restoreVars(sessionName)
125
+ output.stepShift = 0
126
+ event.dispatcher.removeListener(event.step.after, addContextToStep)
127
+ throw e
128
+ })
129
+ }
130
+ finalize()
131
+ return recorder.promise().then(() => res)
132
+ },
133
+ false,
134
+ false,
135
+ )
130
136
  }
131
137
 
132
- module.exports = session;
138
+ export default session
package/lib/step/base.js CHANGED
@@ -1,8 +1,8 @@
1
- const color = require('chalk')
2
- const Secret = require('../secret')
3
- const { getCurrentTimeout } = require('../timeout')
4
- const { ucfirst, humanizeString, serializeError } = require('../utils')
5
- const recordStep = require('./record')
1
+ import color from 'chalk'
2
+ import Secret from '../secret.js'
3
+ import { getCurrentTimeout } from '../timeout.js'
4
+ import { ucfirst, humanizeString, serializeError } from '../utils.js'
5
+ import recordStep from './record.js'
6
6
 
7
7
  const STACK_LINE = 5
8
8
 
@@ -225,7 +225,7 @@ class Step {
225
225
  processingStep = this
226
226
 
227
227
  while (processingStep.metaStep) {
228
- if (processingStep.metaStep.actor?.match(/^(Given|When|Then|And)/)) {
228
+ if (processingStep.metaStep.actor?.match(/^(Given|When|Then|And|But)/)) {
229
229
  hasBDD = true
230
230
  break
231
231
  } else {
@@ -236,4 +236,4 @@ class Step {
236
236
  }
237
237
  }
238
238
 
239
- module.exports = Step
239
+ export default Step
@@ -1,4 +1,4 @@
1
- const FuncStep = require('./func')
1
+ import FuncStep from './func.js'
2
2
 
3
3
  class CommentStep extends FuncStep {
4
4
  constructor(name, comment) {
@@ -7,4 +7,4 @@ class CommentStep extends FuncStep {
7
7
  }
8
8
  }
9
9
 
10
- module.exports = CommentStep
10
+ export default CommentStep
@@ -47,4 +47,4 @@ class StepConfig {
47
47
  }
48
48
  }
49
49
 
50
- module.exports = StepConfig
50
+ export default StepConfig
package/lib/step/func.js CHANGED
@@ -1,5 +1,5 @@
1
- const BaseStep = require('./base')
2
- const store = require('../store')
1
+ import BaseStep from './base.js'
2
+ import store from '../store.js'
3
3
 
4
4
  /**
5
5
  * Function executed as a step
@@ -43,4 +43,4 @@ class FuncStep extends BaseStep {
43
43
  }
44
44
  }
45
45
 
46
- module.exports = FuncStep
46
+ export default FuncStep
@@ -1,5 +1,5 @@
1
- const Step = require('./base')
2
- const store = require('../store')
1
+ import Step from './base.js'
2
+ import store from '../store.js'
3
3
 
4
4
  class HelperStep extends Step {
5
5
  constructor(helper, name) {
@@ -38,7 +38,7 @@ class HelperStep extends Step {
38
38
  }
39
39
  }
40
40
 
41
- module.exports = HelperStep
41
+ export default HelperStep
42
42
 
43
43
  function dryRunResolver() {
44
44
  return {
package/lib/step/meta.js CHANGED
@@ -1,6 +1,6 @@
1
- const Step = require('./base')
2
- const event = require('../event')
3
- const { humanizeString } = require('../utils')
1
+ import Step from './base.js'
2
+ import event from '../event.js'
3
+ import { humanizeString } from '../utils.js'
4
4
 
5
5
  class MetaStep extends Step {
6
6
  constructor(actor, method) {
@@ -15,7 +15,7 @@ class MetaStep extends Step {
15
15
 
16
16
  /** @return {boolean} */
17
17
  isBDD() {
18
- if (this.actor && this.actor.match && this.actor.match(/^(Given|When|Then|And)/)) {
18
+ if (this.actor && this.actor.match && this.actor.match(/^(Given|When|Then|And|But)/)) {
19
19
  return true
20
20
  }
21
21
  return false
@@ -96,4 +96,4 @@ class MetaStep extends Step {
96
96
  }
97
97
  }
98
98
 
99
- module.exports = MetaStep
99
+ export default MetaStep
@@ -1,10 +1,10 @@
1
- const event = require('../event')
2
- const recorder = require('../recorder')
3
- const StepConfig = require('./config')
4
- const { debug } = require('../output')
5
- const store = require('../store')
6
- const { TIMEOUT_ORDER } = require('../timeout')
7
- const retryStep = require('./retry')
1
+ import event from '../event.js'
2
+ import recorder from '../recorder.js'
3
+ import StepConfig from './config.js'
4
+ import output from '../output.js'
5
+ import store from '../store.js'
6
+ import { TIMEOUT_ORDER } from '../timeout.js'
7
+ import retryStep from './retry.js'
8
8
  function recordStep(step, args) {
9
9
  step.status = 'queued'
10
10
 
@@ -15,12 +15,12 @@ function recordStep(step, args) {
15
15
  const { opts, timeout, retry } = stepConfig.getConfig()
16
16
 
17
17
  if (opts) {
18
- debug(`Step ${step.name}: options applied ${JSON.stringify(opts)}`)
18
+ output.debug(`Step ${step.name}: options applied ${JSON.stringify(opts)}`)
19
19
  store.stepOptions = opts
20
20
  step.opts = opts
21
21
  }
22
22
  if (timeout) {
23
- debug(`Step ${step.name} timeout ${timeout}s`)
23
+ output.debug(`Step ${step.name} timeout ${timeout}s`)
24
24
  step.setTimeout(timeout * 1000, TIMEOUT_ORDER.codeLimitTime)
25
25
  }
26
26
  if (retry) retryStep(retry)
@@ -57,7 +57,7 @@ function recordStep(step, args) {
57
57
  event.emit(event.step.finished, step)
58
58
  })
59
59
 
60
- recorder.catchWithoutStop(err => {
60
+ recorder.catch(err => {
61
61
  step.status = 'failed'
62
62
  step.endTime = +Date.now()
63
63
  event.emit(event.step.failed, step, err)
@@ -71,4 +71,4 @@ function recordStep(step, args) {
71
71
  return recorder.promise()
72
72
  }
73
73
 
74
- module.exports = recordStep
74
+ export default recordStep
package/lib/step/retry.js CHANGED
@@ -1,5 +1,5 @@
1
- const recorder = require('../recorder')
2
- const event = require('../event')
1
+ import recorder from '../recorder.js'
2
+ import event from '../event.js'
3
3
 
4
4
  function retryStep(opts) {
5
5
  if (opts === undefined) opts = 1
@@ -8,4 +8,4 @@ function retryStep(opts) {
8
8
  recorder.add(() => event.dispatcher.once(event.step.finished, () => recorder.retries.pop()))
9
9
  }
10
10
 
11
- module.exports = retryStep
11
+ export default retryStep
@@ -1,5 +1,5 @@
1
- const MetaStep = require('./meta')
2
- const event = require('../event')
1
+ import MetaStep from './meta.js'
2
+ import event from '../event.js'
3
3
 
4
4
  let currentSection
5
5
 
@@ -52,4 +52,4 @@ function getRootMetaStep(step) {
52
52
  return step
53
53
  }
54
54
 
55
- module.exports = Section
55
+ export default Section
package/lib/step.js CHANGED
@@ -3,24 +3,21 @@
3
3
  * Step is wrapper around a helper method.
4
4
  * It is used to create a new step that is a combination of other steps.
5
5
  */
6
- const BaseStep = require('./step/base')
7
- const StepConfig = require('./step/config')
8
- const Step = require('./step/helper')
6
+ import BaseStep from './step/base.js'
7
+ import StepConfig from './step/config.js'
8
+ import Step from './step/helper.js'
9
9
 
10
10
  /**
11
11
  * MetaStep is a step that is used to wrap other steps.
12
12
  * It is used to create a new step that is a combination of other steps.
13
13
  * It is used to create a new step that is a combination of other steps.
14
14
  */
15
- const MetaStep = require('./step/meta')
15
+ import MetaStep from './step/meta.js'
16
16
 
17
17
  /**
18
18
  * Step used to execute a single function
19
19
  */
20
- const FuncStep = require('./step/func')
20
+ import FuncStep from './step/func.js'
21
21
 
22
- module.exports = Step
23
- module.exports.MetaStep = MetaStep
24
- module.exports.BaseStep = BaseStep
25
- module.exports.StepConfig = StepConfig
26
- module.exports.FuncStep = FuncStep
22
+ export default Step
23
+ export { MetaStep, BaseStep, StepConfig, FuncStep }
package/lib/steps.js CHANGED
@@ -1,5 +1,5 @@
1
- const StepConfig = require('./step/config')
2
- const Section = require('./step/section')
1
+ import StepConfig from './step/config.js'
2
+ import SectionClass from './step/section.js'
3
3
  function stepOpts(opts = {}) {
4
4
  return new StepConfig(opts)
5
5
  }
@@ -14,11 +14,11 @@ function stepRetry(retry) {
14
14
 
15
15
  function section(name) {
16
16
  if (!name) return endSection()
17
- return new Section(name).start()
17
+ return new SectionClass(name).start()
18
18
  }
19
19
 
20
20
  function endSection() {
21
- return Section.current().end()
21
+ return SectionClass.current().end()
22
22
  }
23
23
 
24
24
  // Section function to be added here
@@ -47,4 +47,8 @@ const step = {
47
47
  Then: () => section('Then'),
48
48
  }
49
49
 
50
- module.exports = step
50
+ export default step
51
+
52
+ // Named exports for ESM compatibility
53
+ export const Section = step.Section
54
+ export const EndSection = step.EndSection
package/lib/store.js CHANGED
@@ -43,4 +43,4 @@ const store = {
43
43
  currentSuite: null,
44
44
  }
45
45
 
46
- module.exports = store
46
+ export default store
@@ -1,4 +1,4 @@
1
- const { heal, ai } = require('codeceptjs')
1
+ import { heal, ai } from 'codeceptjs'
2
2
 
3
3
  heal.addRecipe('ai', {
4
4
  priority: 10,
@@ -0,0 +1,31 @@
1
+ export default (html, extraPrompt = '', rootLocator = null) => [
2
+ {
3
+ role: 'user',
4
+ content: `As a test automation engineer I am creating a Page Object for a web application using CodeceptJS.
5
+ Here is an sample page object:
6
+
7
+ const { I } = inject();
8
+
9
+ export default {
10
+
11
+ // setting locators
12
+ element1: '#selector',
13
+ element2: '.selector',
14
+ element3: locate().withText('text'),
15
+
16
+ // setting methods
17
+ doSomethingOnPage(params) {
18
+ // ...
19
+ },
20
+ }
21
+
22
+ I want to generate a Page Object for the page I provide.
23
+ Write JavaScript code in similar manner to list all locators on the page.
24
+ Use locators in order of preference: by text (use locate().withText()), label, CSS, XPath.
25
+ Avoid TailwindCSS, Bootstrap or React style formatting classes in locators.
26
+ Add methods to interact with page when needed.
27
+ ${extraPrompt}
28
+ ${rootLocator ? `All provided elements are inside '${rootLocator}'. Declare it as root variable and for every locator use locate(...).inside(root)` : ''}
29
+ Add only locators from this HTML: \n\n${html}`,
30
+ },
31
+ ]
@@ -0,0 +1,13 @@
1
+ export default (html, { step, error, prevSteps }) => {
2
+ return [
3
+ {
4
+ role: 'user',
5
+ content: `As a test automation engineer I am testing web application using CodeceptJS.
6
+ I want to heal a test that fails. Here is the list of executed steps: ${prevSteps.map(s => s.toString()).join(', ')}
7
+ Propose how to adjust ${step.toCode()} step to fix the test.
8
+ Use locators in order of preference: semantic locator by text, CSS, XPath. Use codeblocks marked with \`\`\`
9
+ Here is the error message: ${error.message}
10
+ Here is HTML code of a page where the failure has happened: \n\n${html}`,
11
+ },
12
+ ]
13
+ }
@@ -0,0 +1,9 @@
1
+ export default (html, input) => [
2
+ {
3
+ role: 'user',
4
+ content: `I am test engineer writing test in CodeceptJS
5
+ I have opened web page and I want to use CodeceptJS to ${input} on this page
6
+ Provide me valid CodeceptJS code to accomplish it
7
+ Use only locators from this HTML: \n\n${html}`,
8
+ },
9
+ ]
@@ -1,6 +1,6 @@
1
- const express = require('express')
2
- const fs = require('fs')
3
- const path = require('path')
1
+ import express from 'express'
2
+ import fs from 'fs'
3
+ import path from 'path'
4
4
 
5
5
  /**
6
6
  * Internal API test server to replace json-server dependency
@@ -13,6 +13,7 @@ class TestServer {
13
13
  this.port = config.port || 8010
14
14
  this.host = config.host || 'localhost'
15
15
  this.dbFile = config.dbFile || path.join(__dirname, '../test/data/rest/db.json')
16
+ this.readOnly = config.readOnly || false
16
17
  this.lastModified = null
17
18
  this.data = this.loadData()
18
19
 
@@ -49,6 +50,10 @@ class TestServer {
49
50
  }
50
51
 
51
52
  saveData() {
53
+ if (this.readOnly) {
54
+ console.log('[Save] Skipping save - running in read-only mode')
55
+ return
56
+ }
52
57
  try {
53
58
  fs.writeFileSync(this.dbFile, JSON.stringify(this.data, null, 2))
54
59
  console.log('[Save] Data saved to file')
@@ -297,10 +302,16 @@ class TestServer {
297
302
  }
298
303
  }
299
304
 
300
- module.exports = TestServer
305
+ export default TestServer
306
+
307
+ // CLI usage - Import meta for ESM
308
+ import { fileURLToPath } from 'url'
309
+ import { dirname } from 'path'
310
+
311
+ const __filename = fileURLToPath(import.meta.url)
312
+ const __dirname = dirname(__filename)
301
313
 
302
- // CLI usage
303
- if (require.main === module) {
314
+ if (import.meta.url === `file://${process.argv[1]}`) {
304
315
  const config = {
305
316
  port: process.env.PORT || 8010,
306
317
  host: process.env.HOST || '0.0.0.0',