codeceptjs 4.0.0-beta.4 → 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 (150) 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 +139 -87
  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/generate.js +10 -14
  17. package/lib/command/gherkin/snippets.js +75 -73
  18. package/lib/command/gherkin/steps.js +1 -1
  19. package/lib/command/info.js +42 -8
  20. package/lib/command/init.js +13 -12
  21. package/lib/command/interactive.js +10 -2
  22. package/lib/command/list.js +1 -1
  23. package/lib/command/run-multiple/chunk.js +48 -45
  24. package/lib/command/run-multiple.js +12 -35
  25. package/lib/command/run-workers.js +21 -58
  26. package/lib/command/utils.js +5 -6
  27. package/lib/command/workers/runTests.js +262 -220
  28. package/lib/container.js +386 -238
  29. package/lib/data/context.js +10 -13
  30. package/lib/data/dataScenarioConfig.js +8 -8
  31. package/lib/data/dataTableArgument.js +6 -6
  32. package/lib/data/table.js +5 -11
  33. package/lib/effects.js +223 -0
  34. package/lib/element/WebElement.js +327 -0
  35. package/lib/els.js +158 -0
  36. package/lib/event.js +21 -17
  37. package/lib/heal.js +88 -80
  38. package/lib/helper/AI.js +2 -1
  39. package/lib/helper/ApiDataFactory.js +3 -6
  40. package/lib/helper/Appium.js +47 -51
  41. package/lib/helper/FileSystem.js +3 -3
  42. package/lib/helper/GraphQLDataFactory.js +3 -3
  43. package/lib/helper/JSONResponse.js +75 -37
  44. package/lib/helper/Mochawesome.js +31 -9
  45. package/lib/helper/Nightmare.js +35 -53
  46. package/lib/helper/Playwright.js +262 -267
  47. package/lib/helper/Protractor.js +54 -77
  48. package/lib/helper/Puppeteer.js +246 -260
  49. package/lib/helper/REST.js +5 -17
  50. package/lib/helper/TestCafe.js +21 -44
  51. package/lib/helper/WebDriver.js +151 -170
  52. package/lib/helper/extras/Popup.js +22 -22
  53. package/lib/helper/testcafe/testcafe-utils.js +26 -27
  54. package/lib/listener/emptyRun.js +55 -0
  55. package/lib/listener/exit.js +7 -10
  56. package/lib/listener/{retry.js → globalRetry.js} +5 -5
  57. package/lib/listener/globalTimeout.js +165 -0
  58. package/lib/listener/helpers.js +15 -15
  59. package/lib/listener/mocha.js +1 -1
  60. package/lib/listener/result.js +12 -0
  61. package/lib/listener/retryEnhancer.js +85 -0
  62. package/lib/listener/steps.js +32 -18
  63. package/lib/listener/store.js +20 -0
  64. package/lib/mocha/asyncWrapper.js +231 -0
  65. package/lib/{interfaces → mocha}/bdd.js +3 -3
  66. package/lib/mocha/cli.js +308 -0
  67. package/lib/mocha/factory.js +104 -0
  68. package/lib/{interfaces → mocha}/featureConfig.js +32 -12
  69. package/lib/{interfaces → mocha}/gherkin.js +26 -28
  70. package/lib/mocha/hooks.js +112 -0
  71. package/lib/mocha/index.js +12 -0
  72. package/lib/mocha/inject.js +29 -0
  73. package/lib/{interfaces → mocha}/scenarioConfig.js +31 -7
  74. package/lib/mocha/suite.js +82 -0
  75. package/lib/mocha/test.js +181 -0
  76. package/lib/mocha/types.d.ts +42 -0
  77. package/lib/mocha/ui.js +232 -0
  78. package/lib/output.js +82 -62
  79. package/lib/pause.js +160 -138
  80. package/lib/plugin/analyze.js +396 -0
  81. package/lib/plugin/auth.js +435 -0
  82. package/lib/plugin/autoDelay.js +8 -8
  83. package/lib/plugin/autoLogin.js +3 -338
  84. package/lib/plugin/commentStep.js +6 -1
  85. package/lib/plugin/coverage.js +10 -19
  86. package/lib/plugin/customLocator.js +3 -3
  87. package/lib/plugin/customReporter.js +52 -0
  88. package/lib/plugin/eachElement.js +1 -1
  89. package/lib/plugin/fakerTransform.js +1 -1
  90. package/lib/plugin/heal.js +36 -9
  91. package/lib/plugin/htmlReporter.js +1947 -0
  92. package/lib/plugin/pageInfo.js +140 -0
  93. package/lib/plugin/retryFailedStep.js +17 -18
  94. package/lib/plugin/retryTo.js +2 -113
  95. package/lib/plugin/screenshotOnFail.js +17 -58
  96. package/lib/plugin/selenoid.js +15 -35
  97. package/lib/plugin/standardActingHelpers.js +4 -1
  98. package/lib/plugin/stepByStepReport.js +56 -17
  99. package/lib/plugin/stepTimeout.js +5 -12
  100. package/lib/plugin/subtitles.js +4 -4
  101. package/lib/plugin/tryTo.js +3 -102
  102. package/lib/plugin/wdio.js +8 -10
  103. package/lib/recorder.js +155 -124
  104. package/lib/rerun.js +43 -42
  105. package/lib/result.js +161 -0
  106. package/lib/secret.js +1 -1
  107. package/lib/step/base.js +239 -0
  108. package/lib/step/comment.js +10 -0
  109. package/lib/step/config.js +50 -0
  110. package/lib/step/func.js +46 -0
  111. package/lib/step/helper.js +50 -0
  112. package/lib/step/meta.js +99 -0
  113. package/lib/step/record.js +74 -0
  114. package/lib/step/retry.js +11 -0
  115. package/lib/step/section.js +55 -0
  116. package/lib/step.js +21 -332
  117. package/lib/steps.js +50 -0
  118. package/lib/store.js +37 -5
  119. package/lib/template/heal.js +2 -11
  120. package/lib/test-server.js +323 -0
  121. package/lib/timeout.js +66 -0
  122. package/lib/utils.js +351 -218
  123. package/lib/within.js +75 -55
  124. package/lib/workerStorage.js +2 -1
  125. package/lib/workers.js +386 -276
  126. package/package.json +76 -70
  127. package/translations/de-DE.js +4 -3
  128. package/translations/fr-FR.js +4 -3
  129. package/translations/index.js +1 -0
  130. package/translations/it-IT.js +4 -3
  131. package/translations/ja-JP.js +4 -3
  132. package/translations/nl-NL.js +76 -0
  133. package/translations/pl-PL.js +4 -3
  134. package/translations/pt-BR.js +4 -3
  135. package/translations/ru-RU.js +4 -3
  136. package/translations/utils.js +9 -0
  137. package/translations/zh-CN.js +4 -3
  138. package/translations/zh-TW.js +4 -3
  139. package/typings/index.d.ts +188 -186
  140. package/typings/promiseBasedTypes.d.ts +18 -705
  141. package/typings/types.d.ts +301 -804
  142. package/lib/cli.js +0 -256
  143. package/lib/helper/ExpectHelper.js +0 -391
  144. package/lib/helper/SoftExpectHelper.js +0 -381
  145. package/lib/listener/artifacts.js +0 -19
  146. package/lib/listener/timeout.js +0 -109
  147. package/lib/mochaFactory.js +0 -113
  148. package/lib/plugin/debugErrors.js +0 -67
  149. package/lib/scenario.js +0 -224
  150. package/lib/ui.js +0 -236
package/lib/output.js CHANGED
@@ -1,5 +1,5 @@
1
- const colors = require('chalk');
2
- const figures = require('figures');
1
+ const colors = require('chalk')
2
+ const figures = require('figures')
3
3
  const { maskSensitiveData } = require('invisi-data')
4
4
 
5
5
  const styles = {
@@ -10,11 +10,12 @@ const styles = {
10
10
  debug: colors.cyan,
11
11
  log: colors.grey,
12
12
  bold: colors.bold,
13
- };
13
+ section: colors.white.dim.bold,
14
+ }
14
15
 
15
- let outputLevel = 0;
16
- let outputProcess = '';
17
- let newline = true;
16
+ let outputLevel = 0
17
+ let outputProcess = ''
18
+ let newline = true
18
19
 
19
20
  /**
20
21
  * @alias output
@@ -28,7 +29,7 @@ module.exports = {
28
29
  stepShift: 0,
29
30
 
30
31
  standWithUkraine() {
31
- return `#${colors.bold.yellow('StandWith')}${colors.bold.cyan('Ukraine')}`;
32
+ return `#${colors.bold.yellow('StandWith')}${colors.bold.cyan('Ukraine')}`
32
33
  },
33
34
 
34
35
  /**
@@ -37,8 +38,8 @@ module.exports = {
37
38
  * @returns {number}
38
39
  */
39
40
  level(level) {
40
- if (level !== undefined) outputLevel = level;
41
- return outputLevel;
41
+ if (level !== undefined) outputLevel = level
42
+ return outputLevel
42
43
  },
43
44
 
44
45
  /**
@@ -48,9 +49,9 @@ module.exports = {
48
49
  * @returns {string}
49
50
  */
50
51
  process(process) {
51
- if (process === null) return outputProcess = '';
52
- if (process) outputProcess = String(process).length === 1 ? `[0${process}]` : `[${process}]`;
53
- return outputProcess;
52
+ if (process === null) return (outputProcess = '')
53
+ if (process) outputProcess = String(process).length === 1 ? `[0${process}]` : `[${process}]`
54
+ return outputProcess
54
55
  },
55
56
 
56
57
  /**
@@ -60,7 +61,7 @@ module.exports = {
60
61
  debug(msg) {
61
62
  const _msg = isMaskedData() ? maskSensitiveData(msg) : msg
62
63
  if (outputLevel >= 2) {
63
- print(' '.repeat(this.stepShift), styles.debug(`${figures.pointerSmall} ${_msg}`));
64
+ print(' '.repeat(this.stepShift), styles.debug(`${figures.pointerSmall} ${_msg}`))
64
65
  }
65
66
  },
66
67
 
@@ -71,7 +72,7 @@ module.exports = {
71
72
  log(msg) {
72
73
  const _msg = isMaskedData() ? maskSensitiveData(msg) : msg
73
74
  if (outputLevel >= 3) {
74
- print(' '.repeat(this.stepShift), styles.log(truncate(` ${_msg}`, this.spaceShift)));
75
+ print(' '.repeat(this.stepShift), styles.log(truncate(` ${_msg}`, this.spaceShift)))
75
76
  }
76
77
  },
77
78
 
@@ -80,7 +81,7 @@ module.exports = {
80
81
  * @param {string} msg
81
82
  */
82
83
  error(msg) {
83
- print(styles.error(msg));
84
+ print(styles.error(msg))
84
85
  },
85
86
 
86
87
  /**
@@ -88,7 +89,7 @@ module.exports = {
88
89
  * @param {string} msg
89
90
  */
90
91
  success(msg) {
91
- print(styles.success(msg));
92
+ print(styles.success(msg))
92
93
  },
93
94
 
94
95
  /**
@@ -97,7 +98,7 @@ module.exports = {
97
98
  * @param {string} msg
98
99
  */
99
100
  plugin(pluginName, msg = '') {
100
- this.debug(`<${pluginName}> ${msg}`);
101
+ this.debug(`<${pluginName}> ${msg}`)
101
102
  },
102
103
 
103
104
  /**
@@ -105,26 +106,26 @@ module.exports = {
105
106
  * @param {CodeceptJS.Step} step
106
107
  */
107
108
  step(step) {
108
- if (outputLevel === 0) return;
109
- if (!step) return;
109
+ if (outputLevel === 0) return
110
+ if (!step) return
110
111
  // Avoid to print non-gherkin steps, when gherkin is running for --steps mode
111
112
  if (outputLevel === 1) {
112
113
  if (typeof step === 'object' && step.hasBDDAncestor()) {
113
- return;
114
+ return
114
115
  }
115
116
  }
116
117
 
117
- let stepLine = step.toString();
118
+ let stepLine = step.toCliStyled ? step.toCliStyled() : step.toString()
118
119
  if (step.metaStep && outputLevel >= 1) {
119
120
  // this.stepShift += 2;
120
- stepLine = colors.green(truncate(stepLine, this.spaceShift));
121
+ stepLine = colors.dim(truncate(stepLine, this.spaceShift))
121
122
  }
122
123
  if (step.comment) {
123
- stepLine += colors.grey(step.comment.split('\n').join('\n' + ' '.repeat(4)));
124
+ stepLine += colors.grey(step.comment.split('\n').join('\n' + ' '.repeat(4)))
124
125
  }
125
126
 
126
127
  const _stepLine = isMaskedData() ? maskSensitiveData(stepLine) : stepLine
127
- print(' '.repeat(this.stepShift), truncate(_stepLine, this.spaceShift));
128
+ print(' '.repeat(this.stepShift), truncate(_stepLine, this.spaceShift))
128
129
  },
129
130
 
130
131
  /** @namespace */
@@ -132,10 +133,11 @@ module.exports = {
132
133
  /**
133
134
  * @param {Mocha.Suite} suite
134
135
  */
135
- started: (suite) => {
136
- if (!suite.title) return;
137
- print(`${colors.bold(suite.title)} --`);
138
- if (suite.comment) print(suite.comment);
136
+ started: suite => {
137
+ if (!suite.title) return
138
+ print(`${colors.bold(suite.title)} --`)
139
+ if (suite.file && outputLevel >= 1) print(colors.underline.grey(suite.file))
140
+ if (suite.comment) print(suite.comment)
139
141
  },
140
142
  },
141
143
 
@@ -145,25 +147,25 @@ module.exports = {
145
147
  * @param {Mocha.Test} test
146
148
  */
147
149
  started(test) {
148
- print(` ${colors.magenta.bold(test.title)}`);
150
+ print(` ${colors.magenta.bold(test.title)}`)
149
151
  },
150
152
  /**
151
153
  * @param {Mocha.Test} test
152
154
  */
153
155
  passed(test) {
154
- print(` ${colors.green.bold(figures.tick)} ${test.title} ${colors.grey(`in ${test.duration}ms`)}`);
156
+ print(` ${colors.green.bold(figures.tick)} ${test.title} ${colors.grey(`in ${test.duration}ms`)}`)
155
157
  },
156
158
  /**
157
159
  * @param {Mocha.Test} test
158
160
  */
159
161
  failed(test) {
160
- print(` ${colors.red.bold(figures.cross)} ${test.title} ${colors.grey(`in ${test.duration}ms`)}`);
162
+ print(` ${colors.red.bold(figures.cross)} ${test.title} ${colors.grey(`in ${test.duration}ms`)}`)
161
163
  },
162
164
  /**
163
165
  * @param {Mocha.Test} test
164
166
  */
165
167
  skipped(test) {
166
- print(` ${colors.yellow.bold('S')} ${test.title}`);
168
+ print(` ${colors.yellow.bold('S')} ${test.title}`)
167
169
  },
168
170
  },
169
171
 
@@ -173,21 +175,39 @@ module.exports = {
173
175
  * @param {Mocha.Test} test
174
176
  */
175
177
 
176
- started(test) {},
178
+ started(test) {
179
+ if (outputLevel < 1) return
180
+ print(` ${colors.dim.bold('Scenario()')}`)
181
+ },
177
182
 
178
183
  /**
179
184
  * @param {Mocha.Test} test
180
185
  */
181
186
  passed(test) {
182
- print(` ${colors.green.bold(`${figures.tick} OK`)} ${colors.grey(`in ${test.duration}ms`)}`);
183
- print();
187
+ print(` ${colors.green.bold(`${figures.tick} OK`)} ${colors.grey(`in ${test.duration}ms`)}`)
188
+ print()
184
189
  },
185
190
  /**
186
191
  * @param {Mocha.Test} test
187
192
  */
188
193
  failed(test) {
189
- print(` ${colors.red.bold(`${figures.cross} FAILED`)} ${colors.grey(`in ${test.duration}ms`)}`);
190
- print();
194
+ print(` ${colors.red.bold(`${figures.cross} FAILED`)} ${colors.grey(`in ${test.duration}ms`)}`)
195
+ print()
196
+ },
197
+ },
198
+
199
+ hook: {
200
+ started(hook) {
201
+ if (outputLevel < 1) return
202
+ print(` ${colors.dim.bold(hook.toCode())}`)
203
+ },
204
+ passed(hook) {
205
+ if (outputLevel < 1) return
206
+ print()
207
+ },
208
+ failed(hook) {
209
+ if (outputLevel < 1) return
210
+ print(` ${colors.red.bold(hook.toCode())}`)
191
211
  },
192
212
  },
193
213
 
@@ -199,9 +219,9 @@ module.exports = {
199
219
  */
200
220
  say(message, color = 'cyan') {
201
221
  if (colors[color] === undefined) {
202
- color = 'cyan';
222
+ color = 'cyan'
203
223
  }
204
- if (outputLevel >= 1) print(` ${colors[color].bold(message)}`);
224
+ if (outputLevel >= 1) print(` ${colors[color].bold(message)}`)
205
225
  },
206
226
 
207
227
  /**
@@ -211,52 +231,52 @@ module.exports = {
211
231
  * @param {number|string} duration
212
232
  */
213
233
  result(passed, failed, skipped, duration, failedHooks = 0) {
214
- let style = colors.bgGreen;
215
- let msg = ` ${passed || 0} passed`;
216
- let status = style.bold(' OK ');
234
+ let style = colors.bgGreen
235
+ let msg = ` ${passed || 0} passed`
236
+ let status = style.bold(' OK ')
217
237
  if (failed) {
218
- style = style.bgRed;
219
- status = style.bold(' FAIL ');
220
- msg += `, ${failed} failed`;
238
+ style = style.bgRed
239
+ status = style.bold(' FAIL ')
240
+ msg += `, ${failed} failed`
221
241
  }
222
242
 
223
243
  if (failedHooks > 0) {
224
- style = style.bgRed;
225
- status = style.bold(' FAIL ');
226
- msg += `, ${failedHooks} failedHooks`;
244
+ style = style.bgRed
245
+ status = style.bold(' FAIL ')
246
+ msg += `, ${failedHooks} failedHooks`
227
247
  }
228
- status += style.grey(' |');
248
+ status += style.grey(' |')
229
249
 
230
250
  if (skipped) {
231
- if (!failed) style = style.bgYellow;
232
- msg += `, ${skipped} skipped`;
251
+ if (!failed) style = style.bgYellow
252
+ msg += `, ${skipped} skipped`
233
253
  }
234
- msg += ' ';
235
- print(status + style(msg) + colors.grey(` // ${duration}`));
254
+ msg += ' '
255
+ print(status + style(msg) + colors.grey(` // ${duration}`))
236
256
  },
237
- };
257
+ }
238
258
 
239
259
  function print(...msg) {
240
260
  if (outputProcess) {
241
- msg.unshift(outputProcess);
261
+ msg.unshift(outputProcess)
242
262
  }
243
263
  if (!newline) {
244
- console.log();
245
- newline = true;
264
+ console.log()
265
+ newline = true
246
266
  }
247
267
 
248
- console.log.apply(this, msg);
268
+ console.log.apply(this, msg)
249
269
  }
250
270
 
251
271
  function truncate(msg, gap = 0) {
252
272
  if (msg.indexOf('\n') > 0 || outputLevel >= 3) {
253
- return msg; // don't cut multi line steps or on verbose log level
273
+ return msg // don't cut multi line steps or on verbose log level
254
274
  }
255
- const width = (process.stdout.columns || 200) - gap - 4;
275
+ const width = (process.stdout.columns || 200) - gap - 4
256
276
  if (msg.length > width) {
257
- msg = msg.substr(0, width - 1) + figures.ellipsis;
277
+ msg = msg.substr(0, width - 1) + figures.ellipsis
258
278
  }
259
- return msg;
279
+ return msg
260
280
  }
261
281
 
262
282
  function isMaskedData() {
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}'];`);
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
+ 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