codeceptjs 3.5.14 → 3.6.0-beta.1.ai-healers

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 (137) hide show
  1. package/README.md +2 -2
  2. package/bin/codecept.js +66 -30
  3. package/docs/advanced.md +351 -0
  4. package/docs/ai.md +365 -0
  5. package/docs/api.md +323 -0
  6. package/docs/basics.md +979 -0
  7. package/docs/bdd.md +539 -0
  8. package/docs/best.md +237 -0
  9. package/docs/books.md +37 -0
  10. package/docs/bootstrap.md +135 -0
  11. package/docs/build/AI.js +124 -0
  12. package/docs/build/ApiDataFactory.js +410 -0
  13. package/docs/build/Appium.js +2027 -0
  14. package/docs/build/Expect.js +422 -0
  15. package/docs/build/FileSystem.js +228 -0
  16. package/docs/build/GraphQL.js +229 -0
  17. package/docs/build/GraphQLDataFactory.js +309 -0
  18. package/docs/build/JSONResponse.js +338 -0
  19. package/docs/build/Mochawesome.js +71 -0
  20. package/docs/build/Nightmare.js +2152 -0
  21. package/docs/build/Playwright.js +5110 -0
  22. package/docs/build/Protractor.js +2706 -0
  23. package/docs/build/Puppeteer.js +3905 -0
  24. package/docs/build/REST.js +344 -0
  25. package/docs/build/TestCafe.js +2125 -0
  26. package/docs/build/WebDriver.js +4240 -0
  27. package/docs/changelog.md +2572 -0
  28. package/docs/commands.md +266 -0
  29. package/docs/community-helpers.md +58 -0
  30. package/docs/configuration.md +157 -0
  31. package/docs/continuous-integration.md +22 -0
  32. package/docs/custom-helpers.md +306 -0
  33. package/docs/data.md +379 -0
  34. package/docs/detox.md +235 -0
  35. package/docs/docker.md +136 -0
  36. package/docs/email.md +183 -0
  37. package/docs/examples.md +149 -0
  38. package/docs/heal.md +186 -0
  39. package/docs/helpers/ApiDataFactory.md +266 -0
  40. package/docs/helpers/Appium.md +1374 -0
  41. package/docs/helpers/Detox.md +586 -0
  42. package/docs/helpers/Expect.md +275 -0
  43. package/docs/helpers/FileSystem.md +152 -0
  44. package/docs/helpers/GraphQL.md +151 -0
  45. package/docs/helpers/GraphQLDataFactory.md +226 -0
  46. package/docs/helpers/JSONResponse.md +254 -0
  47. package/docs/helpers/Mochawesome.md +8 -0
  48. package/docs/helpers/MockRequest.md +377 -0
  49. package/docs/helpers/Nightmare.md +1305 -0
  50. package/docs/helpers/OpenAI.md +70 -0
  51. package/docs/helpers/Playwright.md +2759 -0
  52. package/docs/helpers/Polly.md +44 -0
  53. package/docs/helpers/Protractor.md +1769 -0
  54. package/docs/helpers/Puppeteer-firefox.md +86 -0
  55. package/docs/helpers/Puppeteer.md +2317 -0
  56. package/docs/helpers/REST.md +218 -0
  57. package/docs/helpers/TestCafe.md +1321 -0
  58. package/docs/helpers/WebDriver.md +2547 -0
  59. package/docs/hooks.md +340 -0
  60. package/docs/index.md +111 -0
  61. package/docs/installation.md +75 -0
  62. package/docs/internal-api.md +266 -0
  63. package/docs/locators.md +339 -0
  64. package/docs/mobile-react-native-locators.md +67 -0
  65. package/docs/mobile.md +338 -0
  66. package/docs/pageobjects.md +291 -0
  67. package/docs/parallel.md +400 -0
  68. package/docs/playwright.md +632 -0
  69. package/docs/plugins.md +1247 -0
  70. package/docs/puppeteer.md +316 -0
  71. package/docs/quickstart.md +162 -0
  72. package/docs/react.md +70 -0
  73. package/docs/reports.md +392 -0
  74. package/docs/secrets.md +36 -0
  75. package/docs/shadow.md +68 -0
  76. package/docs/shared/keys.mustache +31 -0
  77. package/docs/shared/react.mustache +1 -0
  78. package/docs/testcafe.md +174 -0
  79. package/docs/translation.md +247 -0
  80. package/docs/tutorial.md +271 -0
  81. package/docs/typescript.md +180 -0
  82. package/docs/ui.md +59 -0
  83. package/docs/videos.md +28 -0
  84. package/docs/visual.md +202 -0
  85. package/docs/vue.md +143 -0
  86. package/docs/webdriver.md +701 -0
  87. package/docs/wiki/Books-&-Posts.md +27 -0
  88. package/docs/wiki/Community-Helpers-&-Plugins.md +53 -0
  89. package/docs/wiki/Converting-Playwright-to-Istanbul-Coverage.md +61 -0
  90. package/docs/wiki/Examples.md +145 -0
  91. package/docs/wiki/Google-Summer-of-Code-(GSoC)-2020.md +68 -0
  92. package/docs/wiki/Home.md +16 -0
  93. package/docs/wiki/Migration-to-Appium-v2---CodeceptJS.md +83 -0
  94. package/docs/wiki/Release-Process.md +24 -0
  95. package/docs/wiki/Roadmap.md +23 -0
  96. package/docs/wiki/Tests.md +1393 -0
  97. package/docs/wiki/Upgrading-to-CodeceptJS-3.md +153 -0
  98. package/docs/wiki/Videos.md +19 -0
  99. package/lib/actor.js +3 -6
  100. package/lib/ai.js +152 -80
  101. package/lib/cli.js +1 -0
  102. package/lib/command/generate.js +34 -0
  103. package/lib/command/run-workers.js +3 -0
  104. package/lib/command/run.js +3 -0
  105. package/lib/container.js +2 -0
  106. package/lib/heal.js +172 -0
  107. package/lib/helper/AI.js +124 -0
  108. package/lib/helper/Appium.js +12 -36
  109. package/lib/helper/Expect.js +7 -10
  110. package/lib/helper/JSONResponse.js +8 -8
  111. package/lib/helper/Playwright.js +240 -100
  112. package/lib/helper/Puppeteer.js +9 -61
  113. package/lib/helper/REST.js +1 -4
  114. package/lib/helper/WebDriver.js +10 -324
  115. package/lib/index.js +3 -0
  116. package/lib/listener/steps.js +0 -2
  117. package/lib/locator.js +4 -13
  118. package/lib/plugin/heal.js +26 -117
  119. package/lib/recorder.js +11 -5
  120. package/lib/step.js +1 -3
  121. package/lib/store.js +2 -0
  122. package/lib/template/heal.js +39 -0
  123. package/package.json +23 -27
  124. package/typings/index.d.ts +0 -16
  125. package/typings/promiseBasedTypes.d.ts +55 -338
  126. package/typings/types.d.ts +58 -353
  127. package/docs/webapi/dontSeeTraffic.mustache +0 -13
  128. package/docs/webapi/flushNetworkTraffics.mustache +0 -5
  129. package/docs/webapi/grabRecordedNetworkTraffics.mustache +0 -10
  130. package/docs/webapi/seeTraffic.mustache +0 -36
  131. package/docs/webapi/startRecordingTraffic.mustache +0 -8
  132. package/docs/webapi/stopRecordingTraffic.mustache +0 -5
  133. package/docs/webapi/waitForCookie.mustache +0 -9
  134. package/lib/helper/MockServer.js +0 -221
  135. package/lib/helper/errors/ElementAssertion.js +0 -38
  136. package/lib/helper/networkTraffics/utils.js +0 -137
  137. /package/{lib/helper → docs/build}/OpenAI.js +0 -0
@@ -1,33 +1,19 @@
1
1
  const debug = require('debug')('codeceptjs:heal');
2
2
  const colors = require('chalk');
3
- const Container = require('../container');
4
- const AiAssistant = require('../ai');
5
3
  const recorder = require('../recorder');
6
4
  const event = require('../event');
7
5
  const output = require('../output');
8
- const supportedHelpers = require('./standardActingHelpers');
6
+ const heal = require('../heal');
7
+ const store = require('../store');
9
8
 
10
9
  const defaultConfig = {
11
- healTries: 1,
12
10
  healLimit: 2,
13
- healSteps: [
14
- 'click',
15
- 'fillField',
16
- 'appendField',
17
- 'selectOption',
18
- 'attachFile',
19
- 'checkOption',
20
- 'uncheckOption',
21
- 'doubleClick',
22
- ],
23
11
  };
24
12
 
25
13
  /**
26
- * Self-healing tests with OpenAI.
14
+ * Self-healing tests with AI.
27
15
  *
28
- * This plugin is experimental and requires OpenAI API key.
29
- *
30
- * To use it you need to set OPENAI_API_KEY env variable and enable plugin inside the config.
16
+ * Read more about heaking in [Self-Healing Tests](https://codecept.io/heal/)
31
17
  *
32
18
  * ```js
33
19
  * plugins: {
@@ -40,22 +26,15 @@ const defaultConfig = {
40
26
  * More config options are available:
41
27
  *
42
28
  * * `healLimit` - how many steps can be healed in a single test (default: 2)
43
- * * `healSteps` - which steps can be healed (default: all steps that interact with UI, see list below)
44
- *
45
- * Steps to heal:
46
- *
47
- * * `click`
48
- * * `fillField`
49
- * * `appendField`
50
- * * `selectOption`
51
- * * `attachFile`
52
- * * `checkOption`
53
- * * `uncheckOption`
54
- * * `doubleClick`
55
29
  *
56
30
  */
57
31
  module.exports = function (config = {}) {
58
- const aiAssistant = AiAssistant.getInstance();
32
+ if (store.debugMode && !process.env.DEBUG) {
33
+ event.dispatcher.on(event.test.failed, () => {
34
+ output.plugin('heal', 'Healing is disabled in --debug mode, use DEBUG="codeceptjs:heal" to enable it in debug mode');
35
+ });
36
+ return;
37
+ }
59
38
 
60
39
  let currentTest = null;
61
40
  let currentStep = null;
@@ -64,8 +43,6 @@ module.exports = function (config = {}) {
64
43
  let healTries = 0;
65
44
  let isHealing = false;
66
45
 
67
- const healSuggestions = [];
68
-
69
46
  config = Object.assign(defaultConfig, config);
70
47
 
71
48
  event.dispatcher.on(event.test.before, (test) => {
@@ -78,63 +55,27 @@ module.exports = function (config = {}) {
78
55
 
79
56
  event.dispatcher.on(event.step.after, (step) => {
80
57
  if (isHealing) return;
81
- const store = require('../store');
82
- if (store.debugMode) return;
58
+ if (healTries >= config.healLimit) return; // out of limit
59
+
60
+ if (!heal.hasCorrespondingRecipes(step)) return;
61
+
83
62
  recorder.catchWithoutStop(async (err) => {
84
63
  isHealing = true;
85
64
  if (caughtError === err) throw err; // avoid double handling
86
65
  caughtError = err;
87
- if (!aiAssistant.isEnabled) {
88
- output.print(colors.yellow('Heal plugin can\'t operate, AI assistant is disabled. Please set OPENAI_API_KEY env variable to enable it.'));
89
- throw err;
90
- }
91
- if (!currentStep) throw err;
92
- if (!config.healSteps.includes(currentStep.name)) throw err;
93
- const test = currentTest;
94
-
95
- if (healTries >= config.healTries) {
96
- output.print(colors.bold.red(`Healing failed for ${config.healTries} time(s)`));
97
- output.print('AI couldn\'t identify the correct solution');
98
- output.print('Probably the entire flow has changed and the test should be updated');
99
-
100
- throw err;
101
- }
102
66
 
103
- if (healedSteps >= config.healLimit) {
104
- output.print(colors.bold.red(`Can't heal more than ${config.healLimit} step(s) in a test`));
105
- output.print('Entire flow can be broken, please check it manually');
106
- output.print('or increase healing limit in heal plugin config');
107
-
108
- throw err;
109
- }
67
+ const test = currentTest;
110
68
 
111
69
  recorder.session.start('heal');
112
- const helpers = Container.helpers();
113
- let helper;
114
-
115
- for (const helperName of supportedHelpers) {
116
- if (Object.keys(helpers).indexOf(helperName) > -1) {
117
- helper = helpers[helperName];
118
- }
119
- }
120
70
 
121
- if (!helper) throw err; // no helpers for html
122
-
123
- const step = test.steps[test.steps.length - 1];
124
71
  debug('Self-healing started', step.toCode());
125
72
 
126
- const currentOutputLevel = output.level();
127
- output.level(0);
128
- const html = await helper.grabHTMLFrom('body');
129
- output.level(currentOutputLevel);
130
-
131
- if (!html) throw err;
73
+ await heal.healStep(step, err, { test });
132
74
 
133
75
  healTries++;
134
- await aiAssistant.setHtmlContext(html);
135
- await tryToHeal(step, err);
136
76
 
137
77
  recorder.add('close healing session', () => {
78
+ recorder.reset();
138
79
  recorder.session.restore('heal');
139
80
  recorder.ignoreErr(err);
140
81
  });
@@ -145,7 +86,7 @@ module.exports = function (config = {}) {
145
86
  });
146
87
 
147
88
  event.dispatcher.on(event.all.result, () => {
148
- if (!healSuggestions.length) return;
89
+ if (!heal.fixes?.length) return;
149
90
 
150
91
  const { print } = output;
151
92
 
@@ -153,16 +94,20 @@ module.exports = function (config = {}) {
153
94
  print('===================');
154
95
  print(colors.bold.green('Self-Healing Report:'));
155
96
 
156
- print(`${colors.bold(healSuggestions.length)} step(s) were healed by AI`);
97
+ print(`${colors.bold(heal.fixes.length)} ${heal.fixes.length === 1 ? 'step was' : 'steps were'} healed`);
98
+
99
+ const suggestions = heal.fixes.filter(fix => fix.recipe && heal.recipes[fix.recipe].suggest);
100
+
101
+ if (!suggestions.length) return;
157
102
 
158
103
  let i = 1;
159
104
  print('');
160
105
  print('Suggested changes:');
161
106
  print('');
162
107
 
163
- for (const suggestion of healSuggestions) {
164
- print(`${i}. To fix ${colors.bold.blue(suggestion.test.title)}`);
165
- print('Replace the failed code with:');
108
+ for (const suggestion of suggestions) {
109
+ print(`${i}. To fix ${colors.bold.magenta(suggestion.test?.title)}`);
110
+ print(' Replace the failed code:', colors.gray(`(suggested by ${colors.bold(suggestion.recipe)})`));
166
111
  print(colors.red(`- ${suggestion.step.toCode()}`));
167
112
  print(colors.green(`+ ${suggestion.snippet}`));
168
113
  print(suggestion.step.line());
@@ -170,40 +115,4 @@ module.exports = function (config = {}) {
170
115
  i++;
171
116
  }
172
117
  });
173
-
174
- async function tryToHeal(failedStep, err) {
175
- output.debug(`Running OpenAI to heal ${failedStep.toCode()} step`);
176
-
177
- const codeSnippets = await aiAssistant.healFailedStep(failedStep, err, currentTest);
178
-
179
- output.debug(`Received ${codeSnippets.length} suggestions from OpenAI`);
180
- const I = Container.support('I'); // eslint-disable-line
181
-
182
- for (const codeSnippet of codeSnippets) {
183
- try {
184
- debug('Executing', codeSnippet);
185
- recorder.catch((e) => {
186
- console.log(e);
187
- });
188
- await eval(codeSnippet); // eslint-disable-line
189
-
190
- healSuggestions.push({
191
- test: currentTest,
192
- step: failedStep,
193
- snippet: codeSnippet,
194
- });
195
-
196
- recorder.add('healed', () => output.print(colors.bold.green(' Code healed successfully')));
197
- healedSteps++;
198
- return;
199
- } catch (err) {
200
- debug('Failed to execute code', err);
201
- recorder.ignoreErr(err); // healing ded not help
202
- // recorder.catch(() => output.print(colors.bold.red(' Failed healing code')));
203
- }
204
- }
205
-
206
- output.debug(`Couldn't heal the code for ${failedStep.toCode()}`);
207
- }
208
- return recorder.promise();
209
118
  };
package/lib/recorder.js CHANGED
@@ -1,5 +1,6 @@
1
1
  const debug = require('debug')('codeceptjs:recorder');
2
2
  const promiseRetry = require('promise-retry');
3
+ const chalk = require('chalk');
3
4
  const { printObjectProperties } = require('./utils');
4
5
  const { log } = require('./output');
5
6
 
@@ -179,7 +180,7 @@ module.exports = {
179
180
  return;
180
181
  }
181
182
  tasks.push(taskName);
182
- debug(`${currentQueue()}Queued | ${taskName}`);
183
+ debug(chalk.gray(`${currentQueue()} Queued | ${taskName}`));
183
184
 
184
185
  return promise = Promise.resolve(promise).then((res) => {
185
186
  // prefer options for non-conditional retries
@@ -190,11 +191,14 @@ module.exports = {
190
191
  return Promise.race([promise, Promise.resolve(res).then(fn)]).finally(() => clearTimeout(timer));
191
192
  }
192
193
 
194
+ debug(`${currentQueue()} Running | ${taskName}`);
195
+
193
196
  const retryRules = this.retries.slice().reverse();
194
197
  return promiseRetry(Object.assign(defaultRetryOptions, retryOpts), (retry, number) => {
195
198
  if (number > 1) log(`${currentQueue()}Retrying... Attempt #${number}`);
196
199
  const [promise, timer] = getTimeoutPromise(timeout, taskName);
197
200
  return Promise.race([promise, Promise.resolve(res).then(fn)]).finally(() => clearTimeout(timer)).catch((err) => {
201
+ if (ignoredErrs.includes(err)) return;
198
202
  for (const retryObj of retryRules) {
199
203
  if (!retryObj.when) return retry(err);
200
204
  if (retryObj.when && retryObj.when(err)) return retry(err);
@@ -229,7 +233,7 @@ module.exports = {
229
233
  */
230
234
  catch(customErrFn) {
231
235
  const fnDescription = customErrFn?.toString()?.replace(/\s{2,}/g, ' ').replace(/\n/g, ' ')?.slice(0, 50);
232
- debug(`${currentQueue()}Queued | catch with error handler ${fnDescription || ''}`);
236
+ debug(chalk.gray(`${currentQueue()} Queued | catch with error handler ${fnDescription || ''}`));
233
237
  return promise = promise.catch((err) => {
234
238
  log(`${currentQueue()}Error | ${err} ${fnDescription}...`);
235
239
  if (!(err instanceof Error)) { // strange things may happen
@@ -253,7 +257,7 @@ module.exports = {
253
257
  const fnDescription = customErrFn?.toString()?.replace(/\s{2,}/g, ' ').replace(/\n/g, ' ')?.slice(0, 50);
254
258
  return promise = promise.catch((err) => {
255
259
  if (ignoredErrs.includes(err)) return; // already caught
256
- log(`${currentQueue()}Error (Non-Terminated) | ${err} | ${fnDescription || ''}...`);
260
+ log(`${currentQueue()} Error (Non-Terminated) | ${err} | ${fnDescription || ''}...`);
257
261
  if (!(err instanceof Error)) { // strange things may happen
258
262
  err = new Error(`[Wrapped Error] ${JSON.stringify(err)}`); // we should be prepared for them
259
263
  }
@@ -272,7 +276,9 @@ module.exports = {
272
276
  */
273
277
 
274
278
  throw(err) {
279
+ if (ignoredErrs.includes(err)) return promise; // already caught
275
280
  return this.add(`throw error: ${err.message}`, () => {
281
+ if (ignoredErrs.includes(err)) return; // already caught
276
282
  throw err;
277
283
  });
278
284
  },
@@ -313,8 +319,8 @@ module.exports = {
313
319
  * @inner
314
320
  */
315
321
  stop() {
316
- if (process.env.DEBUG) debug(this.toString());
317
- log(`${currentQueue()}Stopping recording promises`);
322
+ debug(this.toString());
323
+ log(`${currentQueue()} Stopping recording promises`);
318
324
  running = false;
319
325
  },
320
326
 
package/lib/step.js CHANGED
@@ -119,9 +119,7 @@ class Step {
119
119
  }
120
120
  let result;
121
121
  try {
122
- if (this.helperMethod !== 'say') {
123
- result = this.helper[this.helperMethod].apply(this.helper, this.args);
124
- }
122
+ result = this.helper[this.helperMethod].apply(this.helper, this.args);
125
123
  this.setStatus('success');
126
124
  } catch (err) {
127
125
  this.setStatus('failed');
package/lib/store.js CHANGED
@@ -7,6 +7,8 @@ const store = {
7
7
  debugMode: false,
8
8
  /** @type {boolean} */
9
9
  timeouts: true,
10
+ /** @type {boolean} */
11
+ dryRun: false,
10
12
  };
11
13
 
12
14
  module.exports = store;
@@ -0,0 +1,39 @@
1
+ const { heal, ai } = require('codeceptjs');
2
+
3
+ heal.addRecipe('ai', {
4
+ priority: 10,
5
+ prepare: {
6
+ html: ({ I }) => I.grabHTMLFrom('body'),
7
+ },
8
+ steps: [
9
+ 'click',
10
+ 'fillField',
11
+ 'appendField',
12
+ 'selectOption',
13
+ 'attachFile',
14
+ 'checkOption',
15
+ 'uncheckOption',
16
+ 'doubleClick',
17
+ ],
18
+ fn: async (args) => {
19
+ return ai.healFailedStep(args);
20
+ },
21
+ });
22
+
23
+ heal.addRecipe('clickAndType', {
24
+ priority: 1,
25
+ steps: [
26
+ 'fillField',
27
+ 'appendField',
28
+ ],
29
+ fn: async ({ step }) => {
30
+ const locator = step.args[0];
31
+ const text = step.args[1];
32
+
33
+ return ({ I }) => {
34
+ I.click(locator);
35
+ I.wait(1); // to open modal or something
36
+ I.type(text);
37
+ };
38
+ },
39
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeceptjs",
3
- "version": "3.5.14",
3
+ "version": "3.6.0-beta.1.ai-healers",
4
4
  "description": "Supercharged End 2 End Testing Framework for NodeJS",
5
5
  "keywords": [
6
6
  "acceptance",
@@ -23,10 +23,10 @@
23
23
  },
24
24
  "files": [
25
25
  "bin",
26
+ "docs",
26
27
  "lib",
27
28
  "translations",
28
- "typings/**/*.d.ts",
29
- "docs/webapi/**"
29
+ "typings/**/*.d.ts"
30
30
  ],
31
31
  "main": "lib/index.js",
32
32
  "typings": "typings/index.d.ts",
@@ -56,7 +56,6 @@
56
56
  "test:unit:webbapi:webDriver:devtools": "mocha test/helper/WebDriver_devtools_test.js --exit",
57
57
  "test:unit:webbapi:testCafe": "mocha test/helper/TestCafe_test.js",
58
58
  "test:unit:expect": "mocha test/helper/Expect_test.js",
59
- "test:unit:mockServer": "mocha test/helper/MockServer_test.js",
60
59
  "test:plugin": "mocha test/plugin/plugin_test.js",
61
60
  "def": "./runok.js def",
62
61
  "dev:graphql": "node test/data/graphql/index.js",
@@ -73,41 +72,38 @@
73
72
  "@cucumber/gherkin": "26",
74
73
  "@cucumber/messages": "24.0.1",
75
74
  "@xmldom/xmldom": "0.8.10",
76
- "acorn": "8.11.3",
75
+ "acorn": "8.11.2",
77
76
  "arrify": "2.0.1",
78
- "axios": "1.6.7",
79
- "chai": "5.0.3",
77
+ "axios": "1.6.3",
78
+ "chai": "4.3.8",
80
79
  "chai-deep-match": "1.2.1",
81
- "chai-exclude": "2.1.0",
82
- "chai-json-schema": "1.5.1",
83
- "chai-json-schema-ajv": "5.2.4",
84
- "chai-match-pattern": "1.3.0",
85
- "chai-string": "1.5.0",
80
+ "chai-exclude": "^2.1.0",
81
+ "chai-json-schema": "^1.5.1",
82
+ "chai-json-schema-ajv": "^5.2.4",
83
+ "chai-match-pattern": "^1.3.0",
84
+ "chai-string": "^1.5.0",
86
85
  "chalk": "4.1.2",
87
86
  "commander": "11.1.0",
88
87
  "cross-spawn": "7.0.3",
89
- "css-to-xpath": "0.1.0",
90
88
  "csstoxpath": "1.6.0",
91
- "devtools": "8.29.1",
89
+ "devtools": "8.27.2",
92
90
  "envinfo": "7.11.0",
93
91
  "escape-string-regexp": "4.0.0",
94
92
  "figures": "3.2.0",
95
93
  "fn-args": "4.0.0",
96
94
  "fs-extra": "11.2.0",
97
95
  "glob": "6.0.1",
98
- "html-minifier-terser": "7.2.0",
96
+ "html-minifier-terser": "^7.2.0",
99
97
  "inquirer": "6.5.2",
100
- "joi": "17.12.1",
98
+ "joi": "17.11.0",
101
99
  "js-beautify": "1.14.11",
102
100
  "lodash.clonedeep": "4.5.0",
103
101
  "lodash.merge": "4.6.2",
104
102
  "mkdirp": "1.0.4",
105
103
  "mocha": "10.2.0",
106
104
  "ms": "2.1.3",
107
- "openai": "3.2.1",
108
105
  "ora-classic": "5.4.2",
109
- "pactum": "3.6.0",
110
- "parse-function": "5.6.10",
106
+ "parse-function": "5.6.4",
111
107
  "parse5": "7.1.2",
112
108
  "promise-retry": "1.1.1",
113
109
  "resq": "1.11.0",
@@ -122,12 +118,12 @@
122
118
  "@faker-js/faker": "7.6.0",
123
119
  "@pollyjs/adapter-puppeteer": "6.0.6",
124
120
  "@pollyjs/core": "5.1.0",
125
- "@types/chai": "4.3.11",
121
+ "@types/chai": "^4.3.7",
126
122
  "@types/inquirer": "9.0.3",
127
- "@types/node": "20.11.16",
128
- "@wdio/sauce-service": "8.29.1",
123
+ "@types/node": "20.10.7",
124
+ "@wdio/sauce-service": "8.27.0",
129
125
  "@wdio/selenium-standalone-service": "8.3.2",
130
- "@wdio/utils": "8.28.8",
126
+ "@wdio/utils": "8.27.2",
131
127
  "@xmldom/xmldom": "0.8.10",
132
128
  "apollo-server-express": "2.25.3",
133
129
  "chai-as-promised": "7.1.1",
@@ -135,7 +131,7 @@
135
131
  "contributor-faces": "1.1.0",
136
132
  "documentation": "12.3.0",
137
133
  "dtslint": "4.2.1",
138
- "electron": "28.2.1",
134
+ "electron": "28.0.0",
139
135
  "eslint": "8.56.0",
140
136
  "eslint-config-airbnb-base": "15.0.0",
141
137
  "eslint-plugin-import": "2.29.1",
@@ -148,14 +144,14 @@
148
144
  "jsdoc": "3.6.11",
149
145
  "jsdoc-typeof-plugin": "1.0.0",
150
146
  "json-server": "0.10.1",
151
- "playwright": "1.41.1",
147
+ "playwright": "1.40.1",
152
148
  "puppeteer": "21.1.1",
153
149
  "qrcode-terminal": "0.12.0",
154
150
  "rosie": "2.1.1",
155
151
  "runok": "0.9.3",
156
152
  "sinon": "17.0.1",
157
153
  "sinon-chai": "3.7.0",
158
- "testcafe": "3.5.0",
154
+ "testcafe": "3.3.0",
159
155
  "ts-morph": "21.0.1",
160
156
  "ts-node": "10.9.2",
161
157
  "tsd-jsdoc": "2.5.0",
@@ -163,7 +159,7 @@
163
159
  "typedoc-plugin-markdown": "3.17.1",
164
160
  "typescript": "5.3.3",
165
161
  "wdio-docker-service": "1.5.0",
166
- "webdriverio": "8.31.1",
162
+ "webdriverio": "8.27.2",
167
163
  "xml2js": "0.6.2",
168
164
  "xpath": "0.0.34"
169
165
  },
@@ -382,22 +382,6 @@ declare namespace CodeceptJS {
382
382
  [key: string]: any;
383
383
  };
384
384
 
385
- type MockRequest = {
386
- method: 'GET'|'PUT'|'POST'|'PATCH'|'DELETE'|string;
387
- path: string;
388
- queryParams?: object;
389
- }
390
-
391
- type MockResponse = {
392
- status: number;
393
- body?: object;
394
- }
395
-
396
- type MockInteraction = {
397
- request: MockRequest;
398
- response: MockResponse;
399
- }
400
-
401
385
  interface PageScrollPosition {
402
386
  x: number;
403
387
  y: number;