codeceptjs 3.6.4-beta.2 → 3.6.5-beta.1

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 (92) hide show
  1. package/bin/codecept.js +84 -63
  2. package/lib/ai.js +47 -1
  3. package/lib/assert/empty.js +19 -19
  4. package/lib/assert/equal.js +32 -30
  5. package/lib/assert/error.js +14 -14
  6. package/lib/assert/include.js +42 -42
  7. package/lib/assert/throws.js +13 -11
  8. package/lib/assert/truth.js +17 -18
  9. package/lib/command/configMigrate.js +57 -52
  10. package/lib/command/definitions.js +88 -88
  11. package/lib/command/dryRun.js +65 -63
  12. package/lib/command/generate.js +191 -181
  13. package/lib/command/info.js +39 -37
  14. package/lib/command/init.js +289 -286
  15. package/lib/command/interactive.js +32 -32
  16. package/lib/command/list.js +26 -26
  17. package/lib/command/run-multiple.js +113 -93
  18. package/lib/command/run-rerun.js +22 -22
  19. package/lib/command/run-workers.js +63 -63
  20. package/lib/command/run.js +24 -26
  21. package/lib/command/utils.js +64 -63
  22. package/lib/data/context.js +60 -60
  23. package/lib/data/dataScenarioConfig.js +47 -47
  24. package/lib/data/dataTableArgument.js +29 -29
  25. package/lib/data/table.js +26 -20
  26. package/lib/helper/AI.js +114 -35
  27. package/lib/helper/ApiDataFactory.js +72 -69
  28. package/lib/helper/Appium.js +409 -379
  29. package/lib/helper/ExpectHelper.js +214 -248
  30. package/lib/helper/FileSystem.js +77 -78
  31. package/lib/helper/GraphQL.js +44 -43
  32. package/lib/helper/GraphQLDataFactory.js +49 -50
  33. package/lib/helper/JSONResponse.js +64 -62
  34. package/lib/helper/Mochawesome.js +28 -28
  35. package/lib/helper/MockServer.js +12 -12
  36. package/lib/helper/Nightmare.js +664 -572
  37. package/lib/helper/Playwright.js +1320 -1211
  38. package/lib/helper/Protractor.js +663 -629
  39. package/lib/helper/Puppeteer.js +1232 -1124
  40. package/lib/helper/REST.js +115 -69
  41. package/lib/helper/TestCafe.js +490 -491
  42. package/lib/helper/WebDriver.js +1294 -1156
  43. package/lib/history.js +16 -3
  44. package/lib/interfaces/bdd.js +38 -51
  45. package/lib/interfaces/featureConfig.js +19 -19
  46. package/lib/interfaces/gherkin.js +122 -111
  47. package/lib/interfaces/scenarioConfig.js +29 -29
  48. package/lib/listener/artifacts.js +9 -9
  49. package/lib/listener/config.js +24 -23
  50. package/lib/listener/exit.js +12 -12
  51. package/lib/listener/helpers.js +42 -42
  52. package/lib/listener/mocha.js +11 -11
  53. package/lib/listener/retry.js +32 -30
  54. package/lib/listener/steps.js +50 -51
  55. package/lib/listener/timeout.js +53 -53
  56. package/lib/pause.js +17 -3
  57. package/lib/plugin/allure.js +14 -14
  58. package/lib/plugin/autoDelay.js +29 -36
  59. package/lib/plugin/autoLogin.js +70 -66
  60. package/lib/plugin/commentStep.js +18 -18
  61. package/lib/plugin/coverage.js +92 -77
  62. package/lib/plugin/customLocator.js +20 -19
  63. package/lib/plugin/debugErrors.js +24 -24
  64. package/lib/plugin/eachElement.js +37 -37
  65. package/lib/plugin/fakerTransform.js +6 -6
  66. package/lib/plugin/heal.js +66 -63
  67. package/lib/plugin/pauseOnFail.js +10 -10
  68. package/lib/plugin/retryFailedStep.js +31 -38
  69. package/lib/plugin/retryTo.js +28 -28
  70. package/lib/plugin/screenshotOnFail.js +107 -86
  71. package/lib/plugin/selenoid.js +131 -117
  72. package/lib/plugin/standardActingHelpers.js +2 -8
  73. package/lib/plugin/stepByStepReport.js +102 -92
  74. package/lib/plugin/stepTimeout.js +23 -22
  75. package/lib/plugin/subtitles.js +34 -34
  76. package/lib/plugin/tryTo.js +39 -29
  77. package/lib/plugin/wdio.js +77 -72
  78. package/lib/template/heal.js +11 -14
  79. package/package.json +5 -3
  80. package/translations/de-DE.js +1 -1
  81. package/translations/fr-FR.js +1 -1
  82. package/translations/index.js +9 -9
  83. package/translations/it-IT.js +1 -1
  84. package/translations/ja-JP.js +1 -1
  85. package/translations/pl-PL.js +1 -1
  86. package/translations/pt-BR.js +1 -1
  87. package/translations/ru-RU.js +1 -1
  88. package/translations/zh-CN.js +1 -1
  89. package/translations/zh-TW.js +1 -1
  90. package/typings/index.d.ts +42 -19
  91. package/typings/promiseBasedTypes.d.ts +280 -1
  92. package/typings/types.d.ts +76 -1
@@ -1,17 +1,17 @@
1
- const debug = require('debug')('codeceptjs:plugin:wdio');
1
+ const debug = require('debug')('codeceptjs:plugin:wdio')
2
2
 
3
- const container = require('../container');
4
- const mainConfig = require('../config');
5
- const recorder = require('../recorder');
6
- const event = require('../event');
7
- const output = require('../output');
3
+ const container = require('../container')
4
+ const mainConfig = require('../config')
5
+ const recorder = require('../recorder')
6
+ const event = require('../event')
7
+ const output = require('../output')
8
8
 
9
9
  const defaultConfig = {
10
10
  services: [],
11
11
  capabilities: {},
12
- };
12
+ }
13
13
 
14
- let restartsSession;
14
+ let restartsSession
15
15
 
16
16
  /**
17
17
  * Webdriverio services runner.
@@ -83,162 +83,167 @@ let restartsSession;
83
83
  */
84
84
  module.exports = (config) => {
85
85
  // Keep initial configs to pass as options to wdio services
86
- const wdioOptions = { ...config };
87
- const webDriver = container.helpers('WebDriver');
86
+ const wdioOptions = { ...config }
87
+ const webDriver = container.helpers('WebDriver')
88
88
  if (webDriver) {
89
- config = Object.assign(webDriver.options, config);
90
- restartsSession = !!config.restart;
89
+ config = Object.assign(webDriver.options, config)
90
+ restartsSession = !!config.restart
91
91
  }
92
- config = Object.assign(defaultConfig, config);
93
- const seleniumInstallArgs = { ...config.seleniumInstallArgs };
94
- const seleniumArgs = { ...config.seleniumArgs };
92
+ config = Object.assign(defaultConfig, config)
93
+ const seleniumInstallArgs = { ...config.seleniumInstallArgs }
94
+ const seleniumArgs = { ...config.seleniumArgs }
95
95
 
96
- const services = [];
97
- const launchers = [];
96
+ const services = []
97
+ const launchers = []
98
98
 
99
99
  for (const name of config.services) {
100
- const Service = safeRequire(`@wdio/${name.toLowerCase()}-service`);
100
+ const Service = safeRequire(`@wdio/${name.toLowerCase()}-service`)
101
101
  if (Service) {
102
102
  if (Service.launcher && typeof Service.launcher === 'function') {
103
- const Launcher = Service.launcher;
103
+ const Launcher = Service.launcher
104
104
 
105
105
  const options = {
106
- logPath: global.output_dir, installArgs: seleniumInstallArgs, args: seleniumArgs, ...wdioOptions,
107
- };
108
- launchers.push(new Launcher(options, [config.capabilities], config));
106
+ logPath: global.output_dir,
107
+ installArgs: seleniumInstallArgs,
108
+ args: seleniumArgs,
109
+ ...wdioOptions,
110
+ }
111
+ launchers.push(new Launcher(options, [config.capabilities], config))
109
112
  }
110
113
  if (typeof Service === 'function') {
111
- services.push(new Service(config, config.capabilities));
114
+ services.push(new Service(config, config.capabilities))
112
115
  }
113
- continue;
116
+ continue
114
117
  }
115
118
 
116
- throw new Error(`Couldn't initialize service ${name} from wdio plugin config.\nIt should be available either in '@wdio/${name.toLowerCase()}-service' package`);
119
+ throw new Error(
120
+ `Couldn't initialize service ${name} from wdio plugin config.\nIt should be available either in '@wdio/${name.toLowerCase()}-service' package`,
121
+ )
117
122
  }
118
123
 
119
- debug(`services ${services}, launchers ${launchers}`);
124
+ debug(`services ${services}, launchers ${launchers}`)
120
125
 
121
- recorder.startUnlessRunning();
126
+ recorder.startUnlessRunning()
122
127
 
123
128
  for (const launcher of launchers) {
124
- registerLauncher(launcher);
129
+ registerLauncher(launcher)
125
130
  }
126
131
 
127
132
  for (const service of services) {
128
- registerService(service);
133
+ registerService(service)
129
134
  }
130
135
 
131
136
  function registerService(service) {
132
- const name = service.constructor.name;
137
+ const name = service.constructor.name
133
138
  if (service.beforeSession) {
134
139
  event.dispatcher.on(event.all.before, () => {
135
140
  recorder.add(`service ${name} all.before`, async () => {
136
- await service.beforeSession(config, config.capabilities);
137
- });
138
- });
141
+ await service.beforeSession(config, config.capabilities)
142
+ })
143
+ })
139
144
  }
140
145
 
141
146
  if (service.afterSession) {
142
147
  event.dispatcher.on(event.all.result, (result) => {
143
148
  recorder.add(`service ${name} all.after`, async () => {
144
- await service.afterSession(result);
145
- });
146
- });
149
+ await service.afterSession(result)
150
+ })
151
+ })
147
152
  }
148
153
 
149
154
  if (service.beforeSuite) {
150
155
  event.dispatcher.on(event.suite.before, (suite) => {
151
- debug(`suite started: ${suite.title}`);
152
- recorder.add(`service ${name} suite.before`, () => service.beforeSuite(suite));
153
- });
156
+ debug(`suite started: ${suite.title}`)
157
+ recorder.add(`service ${name} suite.before`, () => service.beforeSuite(suite))
158
+ })
154
159
  }
155
160
 
156
161
  if (service.afterSuite) {
157
162
  event.dispatcher.on(event.suite.after, (suite) => {
158
- debug(`suite finished: ${suite.title}`);
159
- recorder.add(`service ${name} suite.after`, () => service.afterSuite(suite));
160
- });
163
+ debug(`suite finished: ${suite.title}`)
164
+ recorder.add(`service ${name} suite.after`, () => service.afterSuite(suite))
165
+ })
161
166
  }
162
167
 
163
168
  if (service.beforeTest) {
164
169
  event.dispatcher.on(event.test.started, async (test) => {
165
170
  if (test.parent) {
166
- test.parent.toString = () => test.parent.title;
171
+ test.parent.toString = () => test.parent.title
167
172
  }
168
173
  // test.parent = test.parent ? test.parent.title : null;
169
- debug(`test started: ${test.title}`);
174
+ debug(`test started: ${test.title}`)
170
175
  if (webDriver) {
171
- global.browser = webDriver.browser;
172
- global.browser.config = Object.assign(mainConfig.get('test', 1), global.browser.config);
176
+ global.browser = webDriver.browser
177
+ global.browser.config = Object.assign(mainConfig.get('test', 1), global.browser.config)
173
178
  }
174
- await service.beforeTest(test);
175
- });
179
+ await service.beforeTest(test)
180
+ })
176
181
  }
177
182
 
178
183
  if (service.afterTest) {
179
184
  event.dispatcher.on(event.test.finished, async (test) => {
180
- debug(`test finished: ${test.title}`);
181
- await service.afterTest(test);
182
- });
185
+ debug(`test finished: ${test.title}`)
186
+ await service.afterTest(test)
187
+ })
183
188
  }
184
189
 
185
190
  if (restartsSession && service.before) {
186
- event.dispatcher.on(event.test.started, () => service.before());
191
+ event.dispatcher.on(event.test.started, () => service.before())
187
192
  }
188
193
 
189
194
  if (restartsSession && service.after) {
190
- event.dispatcher.on(event.test.finished, () => service.after());
195
+ event.dispatcher.on(event.test.finished, () => service.after())
191
196
  }
192
197
 
193
198
  if (!restartsSession && service.before) {
194
- let initializedBrowser = false;
199
+ let initializedBrowser = false
195
200
  event.dispatcher.on(event.test.started, async () => {
196
201
  if (!initializedBrowser) {
197
- await service.before();
198
- initializedBrowser = true;
202
+ await service.before()
203
+ initializedBrowser = true
199
204
  }
200
- });
205
+ })
201
206
  }
202
207
 
203
208
  if (!restartsSession && service.after) {
204
- event.dispatcher.on(event.all.result, result => service.after(result));
209
+ event.dispatcher.on(event.all.result, (result) => service.after(result))
205
210
  }
206
211
  }
207
212
 
208
213
  function registerLauncher(launcher) {
209
- const name = launcher.constructor.name;
214
+ const name = launcher.constructor.name
210
215
  if (launcher.onPrepare) {
211
216
  event.dispatcher.on(event.all.before, () => {
212
217
  recorder.add(`launcher ${name} start`, async () => {
213
218
  // browserstack-service expects capabilities as array
214
219
  if (launcher.constructor.name === 'BrowserstackLauncherService') {
215
- await launcher.onPrepare(config, [config.capabilities]);
220
+ await launcher.onPrepare(config, [config.capabilities])
216
221
  } else {
217
- await launcher.onPrepare(config, config.capabilities);
222
+ await launcher.onPrepare(config, config.capabilities)
218
223
  }
219
- output.debug(`Started ${name}`);
220
- });
221
- });
224
+ output.debug(`Started ${name}`)
225
+ })
226
+ })
222
227
  }
223
228
 
224
229
  if (launcher.onComplete) {
225
230
  event.dispatcher.on(event.all.after, () => {
226
231
  recorder.add(`launcher ${name} start`, async () => {
227
- await launcher.onComplete(process.exitCode, config, config.capabilities);
228
- output.debug(`Stopped ${name}`);
229
- });
230
- });
232
+ await launcher.onComplete(process.exitCode, config, config.capabilities)
233
+ output.debug(`Stopped ${name}`)
234
+ })
235
+ })
231
236
  }
232
237
  }
233
- };
238
+ }
234
239
 
235
240
  function safeRequire(name) {
236
241
  try {
237
- return require(name);
242
+ return require(name)
238
243
  } catch (e) {
239
244
  if (!e.message.match(`Cannot find module '${name}'`)) {
240
- throw new Error(`Couldn't initialise "${name}".\n${e.stack}`);
245
+ throw new Error(`Couldn't initialise "${name}".\n${e.stack}`)
241
246
  }
242
- return null;
247
+ return null
243
248
  }
244
249
  }
@@ -1,4 +1,4 @@
1
- const { heal, ai } = require('codeceptjs');
1
+ const { heal, ai } = require('codeceptjs')
2
2
 
3
3
  heal.addRecipe('ai', {
4
4
  priority: 10,
@@ -16,24 +16,21 @@ heal.addRecipe('ai', {
16
16
  'doubleClick',
17
17
  ],
18
18
  fn: async (args) => {
19
- return ai.healFailedStep(args);
19
+ return ai.healFailedStep(args)
20
20
  },
21
- });
21
+ })
22
22
 
23
23
  heal.addRecipe('clickAndType', {
24
24
  priority: 1,
25
- steps: [
26
- 'fillField',
27
- 'appendField',
28
- ],
25
+ steps: ['fillField', 'appendField'],
29
26
  fn: async ({ step }) => {
30
- const locator = step.args[0];
31
- const text = step.args[1];
27
+ const locator = step.args[0]
28
+ const text = step.args[1]
32
29
 
33
30
  return ({ I }) => {
34
- I.click(locator);
35
- I.wait(1); // to open modal or something
36
- I.type(text);
37
- };
31
+ I.click(locator)
32
+ I.wait(1) // to open modal or something
33
+ I.type(text)
34
+ }
38
35
  },
39
- });
36
+ })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeceptjs",
3
- "version": "3.6.4-beta.2",
3
+ "version": "3.6.5-beta.1",
4
4
  "description": "Supercharged End 2 End Testing Framework for NodeJS",
5
5
  "keywords": [
6
6
  "acceptance",
@@ -39,6 +39,7 @@
39
39
  "json-server:graphql": "node test/data/graphql/index.js",
40
40
  "lint": "eslint bin/ examples/ lib/ test/ translations/ runok.js",
41
41
  "lint-fix": "eslint bin/ examples/ lib/ test/ translations/ runok.js --fix",
42
+ "prettier": "prettier --config prettier.config.js --write bin/**/*.js lib/**/*.js test/**/*.js translations/**/*.js runok.js",
42
43
  "docs": "./runok.js docs",
43
44
  "test:unit": "mocha test/unit --recursive --timeout 10000",
44
45
  "test:runner": "mocha test/runner --recursive --timeout 10000",
@@ -72,14 +73,14 @@
72
73
  "@codeceptjs/helper": "2.0.4",
73
74
  "@cucumber/cucumber-expressions": "17",
74
75
  "@cucumber/gherkin": "26",
75
- "@cucumber/messages": "24.1.0",
76
+ "@cucumber/messages": "25.0.1",
76
77
  "@xmldom/xmldom": "0.8.10",
77
78
  "acorn": "8.11.3",
78
79
  "arrify": "2.0.1",
79
80
  "axios": "1.7.2",
80
81
  "chai": "5.1.1",
81
82
  "chai-deep-match": "1.2.1",
82
- "chai-exclude": "2.1.0",
83
+ "chai-exclude": "2.1.1",
83
84
  "chai-json-schema": "1.5.1",
84
85
  "chai-json-schema-ajv": "5.2.4",
85
86
  "chai-match-pattern": "1.3.0",
@@ -149,6 +150,7 @@
149
150
  "jsdoc-typeof-plugin": "1.0.0",
150
151
  "json-server": "0.10.1",
151
152
  "playwright": "1.44.1",
153
+ "prettier": "^3.3.2",
152
154
  "puppeteer": "22.10.0",
153
155
  "qrcode-terminal": "0.12.0",
154
156
  "rosie": "2.1.1",
@@ -71,4 +71,4 @@ module.exports = {
71
71
  sendPostRequest: 'mache_einen_post_request',
72
72
  switchTo: 'wechlse_in_iframe',
73
73
  },
74
- };
74
+ }
@@ -73,4 +73,4 @@ module.exports = {
73
73
  sendDeleteRequest: 'envoieLaRequêteDelete',
74
74
  sendPostRequest: 'envoieLaRequêtePost',
75
75
  },
76
- };
76
+ }
@@ -1,9 +1,9 @@
1
- exports['de-DE'] = require('./de-DE');
2
- exports['it-IT'] = require('./it-IT');
3
- exports['fr-FR'] = require('./fr-FR');
4
- exports['ja-JP'] = require('./ja-JP');
5
- exports['pl-PL'] = require('./pl-PL');
6
- exports['pt-BR'] = require('./pt-BR');
7
- exports['ru-RU'] = require('./ru-RU');
8
- exports['zh-CN'] = require('./zh-CN');
9
- exports['zh-TW'] = require('./zh-TW');
1
+ exports['de-DE'] = require('./de-DE')
2
+ exports['it-IT'] = require('./it-IT')
3
+ exports['fr-FR'] = require('./fr-FR')
4
+ exports['ja-JP'] = require('./ja-JP')
5
+ exports['pl-PL'] = require('./pl-PL')
6
+ exports['pt-BR'] = require('./pt-BR')
7
+ exports['ru-RU'] = require('./ru-RU')
8
+ exports['zh-CN'] = require('./zh-CN')
9
+ exports['zh-TW'] = require('./zh-TW')
@@ -61,4 +61,4 @@ module.exports = {
61
61
  resizeWindow: 'ridimesiono_la_finestra',
62
62
  wait: 'aspetto',
63
63
  },
64
- };
64
+ }
@@ -57,4 +57,4 @@ module.exports = {
57
57
  resizeWindow: 'ウィンドウをリサイズする',
58
58
  wait: '待つ',
59
59
  },
60
- };
60
+ }
@@ -62,4 +62,4 @@ module.exports = {
62
62
  moveCursorTo: 'przesuwam_kursor_do',
63
63
  scrollTo: 'skroluję_do',
64
64
  },
65
- };
65
+ }
@@ -62,4 +62,4 @@ module.exports = {
62
62
  resizeWindow: 'redimensionaJanela',
63
63
  wait: 'aguardo',
64
64
  },
65
- };
65
+ }
@@ -55,4 +55,4 @@ module.exports = {
55
55
  resizeWindow: 'растягиваю_окно',
56
56
  wait: 'жду',
57
57
  },
58
- };
58
+ }
@@ -57,4 +57,4 @@ module.exports = {
57
57
  resizeWindow: '调整窗口尺寸',
58
58
  wait: '等',
59
59
  },
60
- };
60
+ }
@@ -57,4 +57,4 @@ module.exports = {
57
57
  resizeWindow: '調整窗口尺寸',
58
58
  wait: '等',
59
59
  },
60
- };
60
+ }
@@ -44,6 +44,44 @@ declare namespace CodeceptJS {
44
44
  Scenario: number;
45
45
  };
46
46
 
47
+ type AiPrompt = {
48
+ role: string;
49
+ content: string;
50
+ }
51
+
52
+ type AiConfig = {
53
+ /** request function to send prompts to AI provider */
54
+ request: (messages: any) => Promise<string>,
55
+
56
+ /** custom prompts */
57
+ prompts?: {
58
+ /** Returns prompt to write CodeceptJS steps inside pause mode */
59
+ writeStep?: (html: string, input: string) => Array<AiPrompt>;
60
+ /** Returns prompt to heal step when test fails on CI if healing is on */
61
+ healStep?: (html: string, object) => Array<AiPrompt>;
62
+ /** Returns prompt to generate page object inside pause mode */
63
+ generatePageObject?: (html: string, extraPrompt?: string, rootLocator?: string) => Array<AiPrompt>;
64
+ },
65
+
66
+ /** max tokens to use */
67
+ maxTokens?: number,
68
+
69
+
70
+ /** configuration for processing HTML for GPT */
71
+ html?: {
72
+ /** max size of HTML to be sent to OpenAI to avoid token limit */
73
+ maxLength?: number,
74
+ /** should HTML be changed by removing non-interactive elements */
75
+ simplify?: boolean,
76
+ /** should HTML be minified before sending */
77
+ minify?: boolean,
78
+ interactiveElements?: Array<string>,
79
+ textElements?: Array<string>,
80
+ allowedAttrs?: Array<string>,
81
+ allowedRoles?: Array<string>,
82
+ }
83
+ }
84
+
47
85
  type MainConfig = {
48
86
  /** Pattern to locate CodeceptJS tests.
49
87
  * Allows to enter glob pattern or an Array<string> of patterns to match tests / test file names.
@@ -165,6 +203,9 @@ declare namespace CodeceptJS {
165
203
  */
166
204
  JSONResponse?: any;
167
205
 
206
+ /** Enable AI features for development purposes */
207
+ AI?: any;
208
+
168
209
  [key: string]: any;
169
210
  },
170
211
  /**
@@ -353,25 +394,7 @@ declare namespace CodeceptJS {
353
394
  /**
354
395
  * [AI](https://codecept.io/ai/) features configuration.
355
396
  */
356
- ai?: {
357
- /** OpenAI model to use */
358
- model?: string,
359
- /** temperature, measure of randomness. Lower is better. */
360
- temperature?: number,
361
- /** configuration for processing HTML for GPT */
362
- html?: {
363
- /** max size of HTML to be sent to OpenAI to avoid token limit */
364
- maxLength?: number,
365
- /** should HTML be changed by removing non-interactive elements */
366
- simplify?: boolean,
367
- /** should HTML be minified before sending */
368
- minify?: boolean,
369
- interactiveElements?: Array<string>,
370
- textElements?: Array<string>,
371
- allowedAttrs?: Array<string>,
372
- allowedRoles?: Array<string>,
373
- }
374
- },
397
+ ai?: AiConfig,
375
398
 
376
399
  /**
377
400
  * Enable full promise-based helper methods for [TypeScript](https://codecept.io/typescript/) project.