codeceptjs 4.0.0-beta.3 → 4.0.0-beta.5

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 (155) hide show
  1. package/README.md +134 -119
  2. package/bin/codecept.js +12 -2
  3. package/bin/test-server.js +53 -0
  4. package/docs/webapi/clearCookie.mustache +1 -1
  5. package/lib/actor.js +66 -102
  6. package/lib/ai.js +130 -121
  7. package/lib/assert/empty.js +3 -5
  8. package/lib/assert/equal.js +4 -7
  9. package/lib/assert/include.js +4 -6
  10. package/lib/assert/throws.js +2 -4
  11. package/lib/assert/truth.js +2 -2
  12. package/lib/codecept.js +141 -86
  13. package/lib/command/check.js +201 -0
  14. package/lib/command/configMigrate.js +2 -4
  15. package/lib/command/definitions.js +8 -26
  16. package/lib/command/dryRun.js +30 -35
  17. package/lib/command/generate.js +10 -14
  18. package/lib/command/gherkin/snippets.js +75 -73
  19. package/lib/command/gherkin/steps.js +1 -1
  20. package/lib/command/info.js +42 -8
  21. package/lib/command/init.js +13 -12
  22. package/lib/command/interactive.js +10 -2
  23. package/lib/command/list.js +1 -1
  24. package/lib/command/run-multiple/chunk.js +48 -45
  25. package/lib/command/run-multiple.js +12 -35
  26. package/lib/command/run-workers.js +21 -58
  27. package/lib/command/utils.js +5 -6
  28. package/lib/command/workers/runTests.js +263 -222
  29. package/lib/container.js +386 -238
  30. package/lib/data/context.js +10 -13
  31. package/lib/data/dataScenarioConfig.js +8 -8
  32. package/lib/data/dataTableArgument.js +6 -6
  33. package/lib/data/table.js +5 -11
  34. package/lib/effects.js +223 -0
  35. package/lib/element/WebElement.js +327 -0
  36. package/lib/els.js +158 -0
  37. package/lib/event.js +21 -17
  38. package/lib/heal.js +88 -80
  39. package/lib/helper/AI.js +2 -1
  40. package/lib/helper/ApiDataFactory.js +4 -7
  41. package/lib/helper/Appium.js +50 -57
  42. package/lib/helper/FileSystem.js +3 -3
  43. package/lib/helper/GraphQLDataFactory.js +4 -4
  44. package/lib/helper/JSONResponse.js +75 -37
  45. package/lib/helper/Mochawesome.js +31 -9
  46. package/lib/helper/Nightmare.js +37 -58
  47. package/lib/helper/Playwright.js +267 -272
  48. package/lib/helper/Protractor.js +56 -87
  49. package/lib/helper/Puppeteer.js +247 -264
  50. package/lib/helper/REST.js +29 -17
  51. package/lib/helper/TestCafe.js +22 -47
  52. package/lib/helper/WebDriver.js +157 -368
  53. package/lib/helper/extras/PlaywrightPropEngine.js +2 -2
  54. package/lib/helper/extras/Popup.js +22 -22
  55. package/lib/helper/network/utils.js +1 -1
  56. package/lib/helper/testcafe/testcafe-utils.js +27 -28
  57. package/lib/listener/emptyRun.js +55 -0
  58. package/lib/listener/exit.js +7 -10
  59. package/lib/listener/{retry.js → globalRetry.js} +5 -5
  60. package/lib/listener/globalTimeout.js +165 -0
  61. package/lib/listener/helpers.js +15 -15
  62. package/lib/listener/mocha.js +1 -1
  63. package/lib/listener/result.js +12 -0
  64. package/lib/listener/retryEnhancer.js +85 -0
  65. package/lib/listener/steps.js +32 -18
  66. package/lib/listener/store.js +20 -0
  67. package/lib/locator.js +1 -1
  68. package/lib/mocha/asyncWrapper.js +231 -0
  69. package/lib/{interfaces → mocha}/bdd.js +3 -3
  70. package/lib/mocha/cli.js +308 -0
  71. package/lib/mocha/factory.js +104 -0
  72. package/lib/{interfaces → mocha}/featureConfig.js +32 -12
  73. package/lib/{interfaces → mocha}/gherkin.js +26 -28
  74. package/lib/mocha/hooks.js +112 -0
  75. package/lib/mocha/index.js +12 -0
  76. package/lib/mocha/inject.js +29 -0
  77. package/lib/{interfaces → mocha}/scenarioConfig.js +31 -7
  78. package/lib/mocha/suite.js +82 -0
  79. package/lib/mocha/test.js +181 -0
  80. package/lib/mocha/types.d.ts +42 -0
  81. package/lib/mocha/ui.js +232 -0
  82. package/lib/output.js +93 -65
  83. package/lib/pause.js +160 -138
  84. package/lib/plugin/analyze.js +396 -0
  85. package/lib/plugin/auth.js +435 -0
  86. package/lib/plugin/autoDelay.js +8 -8
  87. package/lib/plugin/autoLogin.js +3 -338
  88. package/lib/plugin/commentStep.js +6 -1
  89. package/lib/plugin/coverage.js +10 -22
  90. package/lib/plugin/customLocator.js +3 -3
  91. package/lib/plugin/customReporter.js +52 -0
  92. package/lib/plugin/eachElement.js +1 -1
  93. package/lib/plugin/fakerTransform.js +1 -1
  94. package/lib/plugin/heal.js +36 -9
  95. package/lib/plugin/htmlReporter.js +1947 -0
  96. package/lib/plugin/pageInfo.js +140 -0
  97. package/lib/plugin/retryFailedStep.js +17 -18
  98. package/lib/plugin/retryTo.js +2 -113
  99. package/lib/plugin/screenshotOnFail.js +17 -58
  100. package/lib/plugin/selenoid.js +15 -35
  101. package/lib/plugin/standardActingHelpers.js +4 -1
  102. package/lib/plugin/stepByStepReport.js +56 -17
  103. package/lib/plugin/stepTimeout.js +5 -12
  104. package/lib/plugin/subtitles.js +4 -4
  105. package/lib/plugin/tryTo.js +3 -102
  106. package/lib/plugin/wdio.js +8 -10
  107. package/lib/recorder.js +155 -124
  108. package/lib/rerun.js +43 -42
  109. package/lib/result.js +161 -0
  110. package/lib/secret.js +1 -2
  111. package/lib/step/base.js +239 -0
  112. package/lib/step/comment.js +10 -0
  113. package/lib/step/config.js +50 -0
  114. package/lib/step/func.js +46 -0
  115. package/lib/step/helper.js +50 -0
  116. package/lib/step/meta.js +99 -0
  117. package/lib/step/record.js +74 -0
  118. package/lib/step/retry.js +11 -0
  119. package/lib/step/section.js +55 -0
  120. package/lib/step.js +21 -332
  121. package/lib/steps.js +50 -0
  122. package/lib/store.js +37 -5
  123. package/lib/template/heal.js +2 -11
  124. package/lib/test-server.js +323 -0
  125. package/lib/timeout.js +66 -0
  126. package/lib/utils.js +351 -218
  127. package/lib/within.js +75 -55
  128. package/lib/workerStorage.js +2 -1
  129. package/lib/workers.js +386 -277
  130. package/package.json +81 -75
  131. package/translations/de-DE.js +5 -3
  132. package/translations/fr-FR.js +5 -4
  133. package/translations/index.js +1 -0
  134. package/translations/it-IT.js +4 -3
  135. package/translations/ja-JP.js +4 -3
  136. package/translations/nl-NL.js +76 -0
  137. package/translations/pl-PL.js +4 -3
  138. package/translations/pt-BR.js +4 -3
  139. package/translations/ru-RU.js +4 -3
  140. package/translations/utils.js +9 -0
  141. package/translations/zh-CN.js +4 -3
  142. package/translations/zh-TW.js +4 -3
  143. package/typings/index.d.ts +197 -187
  144. package/typings/promiseBasedTypes.d.ts +53 -903
  145. package/typings/types.d.ts +372 -1042
  146. package/lib/cli.js +0 -257
  147. package/lib/helper/ExpectHelper.js +0 -391
  148. package/lib/helper/MockServer.js +0 -221
  149. package/lib/helper/SoftExpectHelper.js +0 -381
  150. package/lib/listener/artifacts.js +0 -19
  151. package/lib/listener/timeout.js +0 -109
  152. package/lib/mochaFactory.js +0 -113
  153. package/lib/plugin/debugErrors.js +0 -67
  154. package/lib/scenario.js +0 -224
  155. package/lib/ui.js +0 -236
package/lib/pause.js CHANGED
@@ -1,59 +1,69 @@
1
- const colors = require('chalk');
2
- const readline = require('readline');
3
- const ora = require('ora-classic');
4
- const debug = require('debug')('codeceptjs:pause');
5
-
6
- const container = require('./container');
7
- const history = require('./history');
8
- const store = require('./store');
9
- const aiAssistant = require('./ai');
10
- const recorder = require('./recorder');
11
- const event = require('./event');
12
- const output = require('./output');
13
- const { methodsOfObject } = require('./utils');
1
+ const colors = require('chalk')
2
+ const readline = require('readline')
3
+ const ora = require('ora-classic')
4
+ const debug = require('debug')('codeceptjs:pause')
5
+
6
+ const container = require('./container')
7
+ const history = require('./history')
8
+ const store = require('./store')
9
+ const aiAssistant = require('./ai')
10
+ const recorder = require('./recorder')
11
+ const event = require('./event')
12
+ const output = require('./output')
13
+ const { methodsOfObject, searchWithFusejs } = require('./utils')
14
14
 
15
15
  // npm install colors
16
- let rl;
17
- let nextStep;
18
- let finish;
19
- let next;
20
- let registeredVariables = {};
16
+ let rl
17
+ let nextStep
18
+ let finish
19
+ let next
20
+ let registeredVariables = {}
21
21
  /**
22
22
  * Pauses test execution and starts interactive shell
23
23
  * @param {Object<string, *>} [passedObject]
24
24
  */
25
25
  const pause = function (passedObject = {}) {
26
- if (store.dryRun) return;
26
+ if (store.dryRun) return
27
27
 
28
- next = false;
28
+ next = false
29
29
  // add listener to all next steps to provide next() functionality
30
30
  event.dispatcher.on(event.step.after, () => {
31
31
  recorder.add('Start next pause session', () => {
32
- if (!next) return;
33
- return pauseSession();
34
- });
35
- });
36
- recorder.add('Start new session', () => pauseSession(passedObject));
37
- };
32
+ // test already finished, nothing to pause
33
+ if (!store.currentTest) return
34
+ if (!next) return
35
+ return pauseSession()
36
+ })
37
+ })
38
+
39
+ event.dispatcher.on(event.test.finished, () => {
40
+ finish()
41
+ recorder.session.restore('pause')
42
+ rl.close()
43
+ history.save()
44
+ })
45
+
46
+ recorder.add('Start new session', () => pauseSession(passedObject))
47
+ }
38
48
 
39
49
  function pauseSession(passedObject = {}) {
40
- registeredVariables = passedObject;
41
- recorder.session.start('pause');
50
+ registeredVariables = passedObject
51
+ recorder.session.start('pause')
42
52
  if (!next) {
43
- let vars = Object.keys(registeredVariables).join(', ');
44
- if (vars) vars = `(vars: ${vars})`;
53
+ let vars = Object.keys(registeredVariables).join(', ')
54
+ if (vars) vars = `(vars: ${vars})`
45
55
 
46
- output.print(colors.yellow(' Interactive shell started'));
47
- output.print(colors.yellow(' Use JavaScript syntax to try steps in action'));
48
- output.print(colors.yellow(` - Press ${colors.bold('ENTER')} to run the next step`));
49
- output.print(colors.yellow(` - Press ${colors.bold('TAB')} twice to see all available commands`));
50
- output.print(colors.yellow(` - Type ${colors.bold('exit')} + Enter to exit the interactive shell`));
51
- output.print(colors.yellow(` - Prefix ${colors.bold('=>')} to run js commands ${colors.bold(vars)}`));
56
+ output.print(colors.yellow(' Interactive shell started'))
57
+ output.print(colors.yellow(' Use JavaScript syntax to try steps in action'))
58
+ output.print(colors.yellow(` - Press ${colors.bold('ENTER')} to run the next step`))
59
+ output.print(colors.yellow(` - Press ${colors.bold('TAB')} twice to see all available commands`))
60
+ output.print(colors.yellow(` - Type ${colors.bold('exit')} + Enter to exit the interactive shell`))
61
+ output.print(colors.yellow(` - Prefix ${colors.bold('=>')} to run js commands ${colors.bold(vars)}`))
52
62
 
53
63
  if (aiAssistant.isEnabled) {
54
- output.print(colors.blue(` ${colors.bold('AI is enabled! (experimental)')} Write what you want and make AI run it`));
55
- output.print(colors.blue(' Please note, only HTML fragments with interactive elements are sent to AI provider'));
56
- output.print(colors.blue(' Ideas: ask it to fill forms for you or to click'));
64
+ output.print(colors.blue(` ${colors.bold('AI is enabled! (experimental)')} Write what you want and make AI run it`))
65
+ output.print(colors.blue(' Please note, only HTML fragments with interactive elements are sent to AI provider'))
66
+ output.print(colors.blue(' Ideas: ask it to fill forms for you or to click'))
57
67
  }
58
68
  }
59
69
 
@@ -64,154 +74,166 @@ function pauseSession(passedObject = {}) {
64
74
  completer,
65
75
  history: history.load(),
66
76
  historySize: 50, // Adjust the history size as needed
67
- });
77
+ })
68
78
 
69
- rl.on('line', parseInput);
79
+ store.onPause = true
80
+ rl.on('line', parseInput)
70
81
  rl.on('close', () => {
71
- if (!next) console.log('Exiting interactive shell....');
72
- });
73
- return new Promise(((resolve) => {
74
- finish = resolve;
75
- // eslint-disable-next-line
76
- return askForStep();
77
- }));
82
+ if (!next) console.log('Exiting interactive shell....')
83
+ store.onPause = false
84
+ })
85
+ return new Promise(resolve => {
86
+ finish = resolve
87
+ return askForStep()
88
+ })
78
89
  }
79
90
 
80
- /* eslint-disable */
81
91
  async function parseInput(cmd) {
82
- rl.pause();
83
- next = false;
84
- recorder.session.start('pause');
85
- if (cmd === '') next = true;
92
+ rl.pause()
93
+ next = false
94
+ recorder.session.start('pause')
95
+ if (cmd === '') next = true
86
96
  if (!cmd || cmd === 'resume' || cmd === 'exit') {
87
- finish();
88
- recorder.session.restore();
89
- rl.close();
90
- history.save();
91
- return nextStep();
97
+ finish()
98
+ recorder.session.restore('pause')
99
+ rl.close()
100
+ history.save()
101
+ return nextStep()
92
102
  }
93
103
  for (const k of Object.keys(registeredVariables)) {
94
- eval(`var ${k} = registeredVariables['${k}'];`); // eslint-disable-line no-eval
104
+ eval(`var ${k} = registeredVariables['${k}'];`)
95
105
  }
96
106
 
97
- let executeCommand = Promise.resolve();
107
+ let executeCommand = Promise.resolve()
98
108
 
99
109
  const getCmd = () => {
100
110
  debug('Command:', cmd)
101
- return cmd;
102
- };
111
+ return cmd
112
+ }
103
113
 
104
- let isCustomCommand = false;
105
- let lastError = null;
106
- let isAiCommand = false;
107
- let $res;
114
+ let isCustomCommand = false
115
+ let lastError = null
116
+ let isAiCommand = false
117
+ let $res
108
118
  try {
109
- // eslint-disable-next-line
110
- const locate = global.locate; // enable locate in this context
111
- // eslint-disable-next-line
112
- const I = container.support('I');
119
+ const locate = global.locate // enable locate in this context
120
+
121
+ const I = container.support('I')
113
122
  if (cmd.trim().startsWith('=>')) {
114
- isCustomCommand = true;
115
- cmd = cmd.trim().substring(2, cmd.length);
123
+ isCustomCommand = true
124
+ cmd = cmd.trim().substring(2, cmd.length)
116
125
  } else if (aiAssistant.isEnabled && cmd.trim() && !cmd.match(/^\w+\(/) && cmd.includes(' ')) {
117
- const currentOutputLevel = output.level();
118
- output.level(0);
119
- const res = I.grabSource();
120
- isAiCommand = true;
126
+ const currentOutputLevel = output.level()
127
+ output.level(0)
128
+ const res = I.grabSource()
129
+ isAiCommand = true
121
130
  executeCommand = executeCommand.then(async () => {
122
131
  try {
123
- const html = await res;
124
- await aiAssistant.setHtmlContext(html);
132
+ const html = await res
133
+ await aiAssistant.setHtmlContext(html)
125
134
  } catch (err) {
126
- output.print(output.styles.error(' ERROR '), 'Can\'t get HTML context', err.stack);
127
- return;
135
+ output.print(output.styles.error(' ERROR '), "Can't get HTML context", err.stack)
136
+ return
128
137
  } finally {
129
- output.level(currentOutputLevel);
138
+ output.level(currentOutputLevel)
130
139
  }
131
140
 
132
- const spinner = ora("Processing AI request...").start();
133
- cmd = await aiAssistant.writeSteps(cmd);
134
- spinner.stop();
135
- output.print('');
136
- output.print(colors.blue(aiAssistant.getResponse()));
137
- output.print('');
138
- return cmd;
141
+ const spinner = ora('Processing AI request...').start()
142
+ cmd = await aiAssistant.writeSteps(cmd)
143
+ spinner.stop()
144
+ output.print('')
145
+ output.print(colors.blue(aiAssistant.getResponse()))
146
+ output.print('')
147
+ return cmd
139
148
  })
140
149
  } else {
141
- cmd = `I.${cmd}`;
150
+ cmd = `I.${cmd}`
142
151
  }
143
- executeCommand = executeCommand.then(async () => {
144
- const cmd = getCmd();
145
- if (!cmd) return;
146
- return eval(cmd); // eslint-disable-line no-eval
147
- }).catch((err) => {
148
- debug(err);
149
- if (isAiCommand) return;
150
- if (!lastError) output.print(output.styles.error(' ERROR '), err.message);
151
- debug(err.stack)
152
-
153
- lastError = err.message;
154
- })
152
+ executeCommand = executeCommand
153
+ .then(async () => {
154
+ const cmd = getCmd()
155
+ if (!cmd) return
156
+ return eval(cmd)
157
+ })
158
+ .catch(err => {
159
+ debug(err)
160
+ if (isAiCommand) return
161
+ if (!lastError) output.print(output.styles.error(' ERROR '), err.message)
162
+ debug(err.stack)
163
+
164
+ lastError = err.message
165
+ })
155
166
 
156
- const val = await executeCommand;
167
+ const val = await executeCommand
157
168
 
158
169
  if (isCustomCommand) {
159
- if (val !== undefined) console.log('Result', '$res=', val); // eslint-disable-line
160
- $res = val;
170
+ if (val !== undefined) console.log('Result', '$res=', val)
171
+ $res = val
161
172
  }
162
173
 
163
174
  if (cmd?.startsWith('I.see') || cmd?.startsWith('I.dontSee')) {
164
- output.print(output.styles.success(' OK '), cmd);
175
+ output.print(output.styles.success(' OK '), cmd)
165
176
  }
166
177
  if (cmd?.startsWith('I.grab')) {
167
- output.print(output.styles.debug(val));
178
+ try {
179
+ output.print(output.styles.debug(JSON.stringify(val, null, 2)))
180
+ } catch (err) {
181
+ output.print(output.styles.error(' ERROR '), 'Failed to stringify result:', err.message)
182
+ output.print(output.styles.error(' RAW VALUE '), String(val))
183
+ }
168
184
  }
169
185
 
170
- history.push(cmd); // add command to history when successful
186
+ history.push(cmd) // add command to history when successful
171
187
  } catch (err) {
172
- if (!lastError) output.print(output.styles.error(' ERROR '), err.message);
173
- lastError = err.message;
188
+ if (!lastError) output.print(output.styles.error(' ERROR '), err.message)
189
+ lastError = err.message
174
190
  }
175
- recorder.session.catch((err) => {
176
- const msg = err.cliMessage ? err.cliMessage() : err.message;
191
+ recorder.session.catch(err => {
192
+ const msg = err.cliMessage ? err.cliMessage() : err.message
177
193
 
178
194
  // pop latest command from history because it failed
179
- history.pop();
180
-
181
- if (isAiCommand) return;
182
- if (!lastError) output.print(output.styles.error(' FAIL '), msg);
183
- lastError = err.message;
184
- });
185
- recorder.add('ask for next step', askForStep);
186
- nextStep();
195
+ history.pop()
196
+
197
+ if (isAiCommand) return
198
+ if (!lastError) output.print(output.styles.error(' FAIL '), msg)
199
+ lastError = err.message
200
+ })
201
+ recorder.add('ask for next step', askForStep)
202
+ nextStep()
187
203
  }
188
- /* eslint-enable */
189
204
 
190
205
  function askForStep() {
191
- return new Promise(((resolve) => {
192
- nextStep = resolve;
193
- rl.setPrompt(' I.', 3);
194
- rl.resume();
195
- rl.prompt([false]);
196
- }));
206
+ return new Promise(resolve => {
207
+ nextStep = resolve
208
+ rl.setPrompt(' I.', 3)
209
+ rl.resume()
210
+ rl.prompt([false])
211
+ })
197
212
  }
198
213
 
199
214
  function completer(line) {
200
- const I = container.support('I');
201
- const completions = methodsOfObject(I);
202
- const hits = completions.filter((c) => {
203
- if (c.indexOf(line) === 0) {
204
- return c;
205
- }
206
- return null;
207
- });
208
- return [hits && hits.length ? hits : completions, line];
215
+ const I = container.support('I')
216
+ const completions = methodsOfObject(I)
217
+ // If no input, return all completions
218
+ if (!line) {
219
+ return [completions, line]
220
+ }
221
+
222
+ // Search using Fuse.js
223
+ const searchResults = searchWithFusejs(completions, line, {
224
+ threshold: 0.3,
225
+ distance: 100,
226
+ minMatchCharLength: 1,
227
+ })
228
+ const hits = searchResults.map(result => result.item)
229
+
230
+ return [hits, line]
209
231
  }
210
232
 
211
233
  function registerVariable(name, value) {
212
- registeredVariables[name] = value;
234
+ registeredVariables[name] = value
213
235
  }
214
236
 
215
- module.exports = pause;
237
+ module.exports = pause
216
238
 
217
- module.exports.registerVariable = registerVariable;
239
+ module.exports.registerVariable = registerVariable