codeceptjs 3.6.10 → 3.7.0-beta.10

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 (127) hide show
  1. package/README.md +89 -119
  2. package/bin/codecept.js +9 -2
  3. package/docs/webapi/clearCookie.mustache +1 -1
  4. package/lib/actor.js +66 -102
  5. package/lib/ai.js +130 -121
  6. package/lib/assert/empty.js +3 -5
  7. package/lib/assert/equal.js +4 -7
  8. package/lib/assert/include.js +4 -6
  9. package/lib/assert/throws.js +2 -4
  10. package/lib/assert/truth.js +2 -2
  11. package/lib/codecept.js +87 -83
  12. package/lib/command/check.js +186 -0
  13. package/lib/command/configMigrate.js +2 -4
  14. package/lib/command/definitions.js +8 -26
  15. package/lib/command/generate.js +10 -14
  16. package/lib/command/gherkin/snippets.js +10 -8
  17. package/lib/command/gherkin/steps.js +1 -1
  18. package/lib/command/info.js +1 -3
  19. package/lib/command/init.js +8 -12
  20. package/lib/command/interactive.js +2 -2
  21. package/lib/command/list.js +1 -1
  22. package/lib/command/run-multiple.js +12 -35
  23. package/lib/command/run-workers.js +5 -57
  24. package/lib/command/utils.js +5 -6
  25. package/lib/command/workers/runTests.js +68 -232
  26. package/lib/container.js +354 -237
  27. package/lib/data/context.js +10 -13
  28. package/lib/data/dataScenarioConfig.js +8 -8
  29. package/lib/data/dataTableArgument.js +6 -6
  30. package/lib/data/table.js +5 -11
  31. package/lib/effects.js +218 -0
  32. package/lib/els.js +158 -0
  33. package/lib/event.js +19 -17
  34. package/lib/heal.js +88 -80
  35. package/lib/helper/AI.js +2 -1
  36. package/lib/helper/ApiDataFactory.js +3 -6
  37. package/lib/helper/Appium.js +45 -51
  38. package/lib/helper/FileSystem.js +3 -3
  39. package/lib/helper/GraphQLDataFactory.js +3 -3
  40. package/lib/helper/JSONResponse.js +57 -37
  41. package/lib/helper/Nightmare.js +35 -53
  42. package/lib/helper/Playwright.js +211 -252
  43. package/lib/helper/Protractor.js +54 -77
  44. package/lib/helper/Puppeteer.js +139 -232
  45. package/lib/helper/REST.js +5 -17
  46. package/lib/helper/TestCafe.js +21 -44
  47. package/lib/helper/WebDriver.js +131 -169
  48. package/lib/helper/testcafe/testcafe-utils.js +26 -27
  49. package/lib/listener/emptyRun.js +55 -0
  50. package/lib/listener/exit.js +7 -10
  51. package/lib/listener/{retry.js → globalRetry.js} +5 -5
  52. package/lib/listener/globalTimeout.js +165 -0
  53. package/lib/listener/helpers.js +15 -15
  54. package/lib/listener/mocha.js +1 -1
  55. package/lib/listener/result.js +12 -0
  56. package/lib/listener/steps.js +20 -18
  57. package/lib/listener/store.js +20 -0
  58. package/lib/mocha/asyncWrapper.js +216 -0
  59. package/lib/{interfaces → mocha}/bdd.js +3 -3
  60. package/lib/mocha/cli.js +308 -0
  61. package/lib/mocha/factory.js +104 -0
  62. package/lib/{interfaces → mocha}/featureConfig.js +24 -12
  63. package/lib/{interfaces → mocha}/gherkin.js +26 -28
  64. package/lib/mocha/hooks.js +112 -0
  65. package/lib/mocha/index.js +12 -0
  66. package/lib/mocha/inject.js +29 -0
  67. package/lib/{interfaces → mocha}/scenarioConfig.js +21 -6
  68. package/lib/mocha/suite.js +81 -0
  69. package/lib/mocha/test.js +159 -0
  70. package/lib/mocha/types.d.ts +42 -0
  71. package/lib/mocha/ui.js +219 -0
  72. package/lib/output.js +82 -62
  73. package/lib/pause.js +155 -138
  74. package/lib/plugin/analyze.js +349 -0
  75. package/lib/plugin/autoDelay.js +6 -6
  76. package/lib/plugin/autoLogin.js +6 -7
  77. package/lib/plugin/commentStep.js +6 -1
  78. package/lib/plugin/coverage.js +10 -19
  79. package/lib/plugin/customLocator.js +3 -3
  80. package/lib/plugin/customReporter.js +52 -0
  81. package/lib/plugin/eachElement.js +1 -1
  82. package/lib/plugin/fakerTransform.js +1 -1
  83. package/lib/plugin/heal.js +36 -9
  84. package/lib/plugin/pageInfo.js +140 -0
  85. package/lib/plugin/retryFailedStep.js +4 -4
  86. package/lib/plugin/retryTo.js +18 -118
  87. package/lib/plugin/screenshotOnFail.js +17 -49
  88. package/lib/plugin/selenoid.js +15 -35
  89. package/lib/plugin/standardActingHelpers.js +4 -1
  90. package/lib/plugin/stepByStepReport.js +56 -17
  91. package/lib/plugin/stepTimeout.js +5 -12
  92. package/lib/plugin/subtitles.js +4 -4
  93. package/lib/plugin/tryTo.js +17 -107
  94. package/lib/plugin/wdio.js +8 -10
  95. package/lib/recorder.js +146 -125
  96. package/lib/rerun.js +43 -42
  97. package/lib/result.js +161 -0
  98. package/lib/secret.js +1 -1
  99. package/lib/step/base.js +228 -0
  100. package/lib/step/config.js +50 -0
  101. package/lib/step/func.js +46 -0
  102. package/lib/step/helper.js +50 -0
  103. package/lib/step/meta.js +99 -0
  104. package/lib/step/record.js +74 -0
  105. package/lib/step/retry.js +11 -0
  106. package/lib/step/section.js +55 -0
  107. package/lib/step.js +21 -332
  108. package/lib/steps.js +50 -0
  109. package/lib/store.js +10 -2
  110. package/lib/template/heal.js +2 -11
  111. package/lib/timeout.js +66 -0
  112. package/lib/utils.js +317 -216
  113. package/lib/within.js +73 -55
  114. package/lib/workers.js +259 -275
  115. package/package.json +56 -54
  116. package/typings/index.d.ts +175 -186
  117. package/typings/promiseBasedTypes.d.ts +164 -17
  118. package/typings/types.d.ts +284 -115
  119. package/lib/cli.js +0 -256
  120. package/lib/helper/ExpectHelper.js +0 -391
  121. package/lib/helper/SoftExpectHelper.js +0 -381
  122. package/lib/listener/artifacts.js +0 -19
  123. package/lib/listener/timeout.js +0 -109
  124. package/lib/mochaFactory.js +0 -113
  125. package/lib/plugin/debugErrors.js +0 -67
  126. package/lib/scenario.js +0 -224
  127. 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,161 @@ 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}'];`);
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
-
110
- const locate = global.locate; // enable locate in this context
111
-
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);
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);
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
+ output.print(output.styles.debug(val))
168
179
  }
169
180
 
170
- history.push(cmd); // add command to history when successful
181
+ history.push(cmd) // add command to history when successful
171
182
  } catch (err) {
172
- if (!lastError) output.print(output.styles.error(' ERROR '), err.message);
173
- lastError = err.message;
183
+ if (!lastError) output.print(output.styles.error(' ERROR '), err.message)
184
+ lastError = err.message
174
185
  }
175
- recorder.session.catch((err) => {
176
- const msg = err.cliMessage ? err.cliMessage() : err.message;
186
+ recorder.session.catch(err => {
187
+ const msg = err.cliMessage ? err.cliMessage() : err.message
177
188
 
178
189
  // 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();
190
+ history.pop()
191
+
192
+ if (isAiCommand) return
193
+ if (!lastError) output.print(output.styles.error(' FAIL '), msg)
194
+ lastError = err.message
195
+ })
196
+ recorder.add('ask for next step', askForStep)
197
+ nextStep()
187
198
  }
188
- /* eslint-enable */
189
199
 
190
200
  function askForStep() {
191
- return new Promise(((resolve) => {
192
- nextStep = resolve;
193
- rl.setPrompt(' I.', 3);
194
- rl.resume();
195
- rl.prompt([false]);
196
- }));
201
+ return new Promise(resolve => {
202
+ nextStep = resolve
203
+ rl.setPrompt(' I.', 3)
204
+ rl.resume()
205
+ rl.prompt([false])
206
+ })
197
207
  }
198
208
 
199
209
  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];
210
+ const I = container.support('I')
211
+ const completions = methodsOfObject(I)
212
+ // If no input, return all completions
213
+ if (!line) {
214
+ return [completions, line]
215
+ }
216
+
217
+ // Search using Fuse.js
218
+ const searchResults = searchWithFusejs(completions, line, {
219
+ threshold: 0.3,
220
+ distance: 100,
221
+ minMatchCharLength: 1,
222
+ })
223
+ const hits = searchResults.map(result => result.item)
224
+
225
+ return [hits, line]
209
226
  }
210
227
 
211
228
  function registerVariable(name, value) {
212
- registeredVariables[name] = value;
229
+ registeredVariables[name] = value
213
230
  }
214
231
 
215
- module.exports = pause;
232
+ module.exports = pause
216
233
 
217
- module.exports.registerVariable = registerVariable;
234
+ module.exports.registerVariable = registerVariable