codeceptjs 3.6.4 → 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 (88) hide show
  1. package/bin/codecept.js +84 -63
  2. package/lib/assert/empty.js +19 -19
  3. package/lib/assert/equal.js +32 -30
  4. package/lib/assert/error.js +14 -14
  5. package/lib/assert/include.js +42 -42
  6. package/lib/assert/throws.js +13 -11
  7. package/lib/assert/truth.js +17 -18
  8. package/lib/command/configMigrate.js +57 -52
  9. package/lib/command/definitions.js +88 -88
  10. package/lib/command/dryRun.js +65 -63
  11. package/lib/command/generate.js +191 -181
  12. package/lib/command/info.js +39 -37
  13. package/lib/command/init.js +289 -286
  14. package/lib/command/interactive.js +32 -32
  15. package/lib/command/list.js +26 -26
  16. package/lib/command/run-multiple.js +113 -93
  17. package/lib/command/run-rerun.js +22 -22
  18. package/lib/command/run-workers.js +63 -63
  19. package/lib/command/run.js +24 -26
  20. package/lib/command/utils.js +64 -63
  21. package/lib/data/context.js +60 -60
  22. package/lib/data/dataScenarioConfig.js +47 -47
  23. package/lib/data/dataTableArgument.js +29 -29
  24. package/lib/data/table.js +26 -20
  25. package/lib/helper/AI.js +67 -65
  26. package/lib/helper/ApiDataFactory.js +72 -69
  27. package/lib/helper/Appium.js +409 -379
  28. package/lib/helper/ExpectHelper.js +214 -248
  29. package/lib/helper/FileSystem.js +77 -78
  30. package/lib/helper/GraphQL.js +44 -43
  31. package/lib/helper/GraphQLDataFactory.js +49 -50
  32. package/lib/helper/JSONResponse.js +64 -62
  33. package/lib/helper/Mochawesome.js +28 -28
  34. package/lib/helper/MockServer.js +12 -12
  35. package/lib/helper/Nightmare.js +664 -572
  36. package/lib/helper/Playwright.js +1320 -1211
  37. package/lib/helper/Protractor.js +663 -629
  38. package/lib/helper/Puppeteer.js +1232 -1124
  39. package/lib/helper/REST.js +87 -72
  40. package/lib/helper/TestCafe.js +490 -491
  41. package/lib/helper/WebDriver.js +1294 -1156
  42. package/lib/interfaces/bdd.js +38 -51
  43. package/lib/interfaces/featureConfig.js +19 -19
  44. package/lib/interfaces/gherkin.js +122 -111
  45. package/lib/interfaces/scenarioConfig.js +29 -29
  46. package/lib/listener/artifacts.js +9 -9
  47. package/lib/listener/config.js +24 -23
  48. package/lib/listener/exit.js +12 -12
  49. package/lib/listener/helpers.js +42 -42
  50. package/lib/listener/mocha.js +11 -11
  51. package/lib/listener/retry.js +32 -30
  52. package/lib/listener/steps.js +50 -51
  53. package/lib/listener/timeout.js +53 -53
  54. package/lib/plugin/allure.js +14 -14
  55. package/lib/plugin/autoDelay.js +29 -36
  56. package/lib/plugin/autoLogin.js +70 -66
  57. package/lib/plugin/commentStep.js +18 -18
  58. package/lib/plugin/coverage.js +92 -77
  59. package/lib/plugin/customLocator.js +20 -19
  60. package/lib/plugin/debugErrors.js +24 -24
  61. package/lib/plugin/eachElement.js +37 -37
  62. package/lib/plugin/fakerTransform.js +6 -6
  63. package/lib/plugin/heal.js +66 -63
  64. package/lib/plugin/pauseOnFail.js +10 -10
  65. package/lib/plugin/retryFailedStep.js +31 -38
  66. package/lib/plugin/retryTo.js +28 -28
  67. package/lib/plugin/screenshotOnFail.js +107 -86
  68. package/lib/plugin/selenoid.js +131 -117
  69. package/lib/plugin/standardActingHelpers.js +2 -8
  70. package/lib/plugin/stepByStepReport.js +102 -92
  71. package/lib/plugin/stepTimeout.js +23 -22
  72. package/lib/plugin/subtitles.js +34 -34
  73. package/lib/plugin/tryTo.js +39 -29
  74. package/lib/plugin/wdio.js +77 -72
  75. package/lib/template/heal.js +11 -14
  76. package/package.json +4 -2
  77. package/translations/de-DE.js +1 -1
  78. package/translations/fr-FR.js +1 -1
  79. package/translations/index.js +9 -9
  80. package/translations/it-IT.js +1 -1
  81. package/translations/ja-JP.js +1 -1
  82. package/translations/pl-PL.js +1 -1
  83. package/translations/pt-BR.js +1 -1
  84. package/translations/ru-RU.js +1 -1
  85. package/translations/zh-CN.js +1 -1
  86. package/translations/zh-TW.js +1 -1
  87. package/typings/promiseBasedTypes.d.ts +238 -0
  88. package/typings/types.d.ts +32 -0
@@ -1,84 +1,84 @@
1
1
  class DataScenarioConfig {
2
2
  constructor(scenarios) {
3
- this.scenarios = scenarios;
3
+ this.scenarios = scenarios
4
4
  }
5
5
 
6
6
  /**
7
- * Declares that test throws error.
8
- * Can pass an Error object or regex matching expected message.
9
- *
10
- * @param {*} err
11
- */
7
+ * Declares that test throws error.
8
+ * Can pass an Error object or regex matching expected message.
9
+ *
10
+ * @param {*} err
11
+ */
12
12
  throws(err) {
13
- this.scenarios.forEach(scenario => scenario.throws(err));
14
- return this;
13
+ this.scenarios.forEach((scenario) => scenario.throws(err))
14
+ return this
15
15
  }
16
16
 
17
17
  /**
18
- * Declares that test should fail.
19
- * If test passes - throws an error.
20
- * Can pass an Error object or regex matching expected message.
21
- *
22
- */
18
+ * Declares that test should fail.
19
+ * If test passes - throws an error.
20
+ * Can pass an Error object or regex matching expected message.
21
+ *
22
+ */
23
23
  fails() {
24
- this.scenarios.forEach(scenario => scenario.fails());
25
- return this;
24
+ this.scenarios.forEach((scenario) => scenario.fails())
25
+ return this
26
26
  }
27
27
 
28
28
  /**
29
- * Retry this test for x times
30
- *
31
- * @param {*} retries
32
- */
29
+ * Retry this test for x times
30
+ *
31
+ * @param {*} retries
32
+ */
33
33
  retry(retries) {
34
- this.scenarios.forEach(scenario => scenario.retry(retries));
35
- return this;
34
+ this.scenarios.forEach((scenario) => scenario.retry(retries))
35
+ return this
36
36
  }
37
37
 
38
38
  /**
39
- * Set timeout for this test
40
- * @param {*} timeout
41
- */
39
+ * Set timeout for this test
40
+ * @param {*} timeout
41
+ */
42
42
  timeout(timeout) {
43
- this.scenarios.forEach(scenario => scenario.timeout(timeout));
44
- return this;
43
+ this.scenarios.forEach((scenario) => scenario.timeout(timeout))
44
+ return this
45
45
  }
46
46
 
47
47
  /**
48
- * Configures a helper.
49
- * Helper name can be omitted and values will be applied to first helper.
50
- */
48
+ * Configures a helper.
49
+ * Helper name can be omitted and values will be applied to first helper.
50
+ */
51
51
  config(helper, obj) {
52
- this.scenarios.forEach(scenario => scenario.config(helper, obj));
53
- return this;
52
+ this.scenarios.forEach((scenario) => scenario.config(helper, obj))
53
+ return this
54
54
  }
55
55
 
56
56
  /**
57
- * Append a tag name to scenario title
58
- * @param {*} tagName
59
- */
57
+ * Append a tag name to scenario title
58
+ * @param {*} tagName
59
+ */
60
60
  tag(tagName) {
61
- this.scenarios.forEach(scenario => scenario.tag(tagName));
62
- return this;
61
+ this.scenarios.forEach((scenario) => scenario.tag(tagName))
62
+ return this
63
63
  }
64
64
 
65
65
  /**
66
- * Pass in additional objects to inject into test
67
- * @param {*} obj
68
- */
66
+ * Pass in additional objects to inject into test
67
+ * @param {*} obj
68
+ */
69
69
  inject(obj) {
70
- this.scenarios.forEach(scenario => scenario.inject(obj));
71
- return this;
70
+ this.scenarios.forEach((scenario) => scenario.inject(obj))
71
+ return this
72
72
  }
73
73
 
74
74
  /**
75
- * Dynamically injects dependencies, see https://codecept.io/pageobjects/#dynamic-injection
76
- * @param {*} dependencies
77
- */
75
+ * Dynamically injects dependencies, see https://codecept.io/pageobjects/#dynamic-injection
76
+ * @param {*} dependencies
77
+ */
78
78
  injectDependencies(dependencies) {
79
- this.scenarios.forEach(scenario => scenario.injectDependencies(dependencies));
80
- return this;
79
+ this.scenarios.forEach((scenario) => scenario.injectDependencies(dependencies))
80
+ return this
81
81
  }
82
82
  }
83
83
 
84
- module.exports = DataScenarioConfig;
84
+ module.exports = DataScenarioConfig
@@ -7,60 +7,60 @@ class DataTableArgument {
7
7
  constructor(gherkinDataTable) {
8
8
  this.rawData = gherkinDataTable.rows.map((row) => {
9
9
  return row.cells.map((cell) => {
10
- return cell.value;
11
- });
12
- });
10
+ return cell.value
11
+ })
12
+ })
13
13
  }
14
14
 
15
15
  /** Returns the table as a 2-D array
16
- * @returns {string[][]}
17
- */
16
+ * @returns {string[][]}
17
+ */
18
18
  raw() {
19
- return this.rawData.slice(0);
19
+ return this.rawData.slice(0)
20
20
  }
21
21
 
22
22
  /** Returns the table as a 2-D array, without the first row
23
- * @returns {string[][]}
24
- */
23
+ * @returns {string[][]}
24
+ */
25
25
  rows() {
26
- const copy = this.raw();
27
- copy.shift();
28
- return copy;
26
+ const copy = this.raw()
27
+ copy.shift()
28
+ return copy
29
29
  }
30
30
 
31
31
  /** Returns an array of objects where each row is converted to an object (column header is the key)
32
- * @returns {any[]}
33
- */
32
+ * @returns {any[]}
33
+ */
34
34
  hashes() {
35
- const copy = this.raw();
36
- const header = copy.shift();
35
+ const copy = this.raw()
36
+ const header = copy.shift()
37
37
  return copy.map((row) => {
38
- const r = {};
39
- row.forEach((cell, index) => r[header[index]] = cell);
40
- return r;
41
- });
38
+ const r = {}
39
+ row.forEach((cell, index) => (r[header[index]] = cell))
40
+ return r
41
+ })
42
42
  }
43
43
 
44
44
  /** Returns an object where each row corresponds to an entry
45
45
  * (first column is the key, second column is the value)
46
- * @returns {Record<string, string>}
47
- */
46
+ * @returns {Record<string, string>}
47
+ */
48
48
  rowsHash() {
49
- const rows = this.raw();
50
- const everyRowHasTwoColumns = rows.every((row) => row.length === 2);
49
+ const rows = this.raw()
50
+ const everyRowHasTwoColumns = rows.every((row) => row.length === 2)
51
51
  if (!everyRowHasTwoColumns) {
52
- throw new Error('rowsHash can only be called on a data table where all rows have exactly two columns');
52
+ throw new Error('rowsHash can only be called on a data table where all rows have exactly two columns')
53
53
  }
54
54
  /** @type {Record<string, string>} */
55
- const result = {};
56
- rows.forEach((x) => (result[x[0]] = x[1]));
57
- return result;
55
+ const result = {}
56
+ rows.forEach((x) => (result[x[0]] = x[1]))
57
+ return result
58
58
  }
59
59
 
60
60
  /** Transposed the data */
61
61
  transpose() {
62
- this.rawData = this.rawData[0].map((x, i) => this.rawData.map((y) => y[i]));
62
+ this.rawData = this.rawData[0].map((x, i) => this.rawData.map((y) => y[i]))
63
63
  }
64
64
  }
65
65
 
66
- module.exports = DataTableArgument;
66
+ module.exports = DataTableArgument
package/lib/data/table.js CHANGED
@@ -4,40 +4,46 @@
4
4
  class DataTable {
5
5
  /** @param {Array<*>} array */
6
6
  constructor(array) {
7
- this.array = array;
8
- this.rows = new Array(0);
7
+ this.array = array
8
+ this.rows = new Array(0)
9
9
  }
10
10
 
11
11
  /** @param {Array<*>} array */
12
12
  add(array) {
13
- if (array.length !== this.array.length) throw new Error(`There is too many elements in given data array. Please provide data in this format: ${this.array}`);
14
- const tempObj = {};
15
- let arrayCounter = 0;
13
+ if (array.length !== this.array.length)
14
+ throw new Error(
15
+ `There is too many elements in given data array. Please provide data in this format: ${this.array}`,
16
+ )
17
+ const tempObj = {}
18
+ let arrayCounter = 0
16
19
  this.array.forEach((elem) => {
17
- tempObj[elem] = array[arrayCounter];
18
- tempObj.toString = () => JSON.stringify(tempObj);
19
- arrayCounter++;
20
- });
21
- this.rows.push({ skip: false, data: tempObj });
20
+ tempObj[elem] = array[arrayCounter]
21
+ tempObj.toString = () => JSON.stringify(tempObj)
22
+ arrayCounter++
23
+ })
24
+ this.rows.push({ skip: false, data: tempObj })
22
25
  }
23
26
 
24
27
  /** @param {Array<*>} array */
25
28
  xadd(array) {
26
- if (array.length !== this.array.length) throw new Error(`There is too many elements in given data array. Please provide data in this format: ${this.array}`);
27
- const tempObj = {};
28
- let arrayCounter = 0;
29
+ if (array.length !== this.array.length)
30
+ throw new Error(
31
+ `There is too many elements in given data array. Please provide data in this format: ${this.array}`,
32
+ )
33
+ const tempObj = {}
34
+ let arrayCounter = 0
29
35
  this.array.forEach((elem) => {
30
- tempObj[elem] = array[arrayCounter];
31
- tempObj.toString = () => JSON.stringify(tempObj);
32
- arrayCounter++;
33
- });
34
- this.rows.push({ skip: true, data: tempObj });
36
+ tempObj[elem] = array[arrayCounter]
37
+ tempObj.toString = () => JSON.stringify(tempObj)
38
+ arrayCounter++
39
+ })
40
+ this.rows.push({ skip: true, data: tempObj })
35
41
  }
36
42
 
37
43
  /** @param {Function} func */
38
44
  filter(func) {
39
- return this.rows.filter(row => func(row.data));
45
+ return this.rows.filter((row) => func(row.data))
40
46
  }
41
47
  }
42
48
 
43
- module.exports = DataTable;
49
+ module.exports = DataTable
package/lib/helper/AI.js CHANGED
@@ -1,14 +1,14 @@
1
- const Helper = require('@codeceptjs/helper');
2
- const ora = require('ora-classic');
3
- const fs = require('fs');
4
- const path = require('path');
5
- const ai = require('../ai');
6
- const standardActingHelpers = require('../plugin/standardActingHelpers');
7
- const Container = require('../container');
8
- const { splitByChunks, minifyHtml } = require('../html');
9
- const { beautify } = require('../utils');
10
- const output = require('../output');
11
- const { registerVariable } = require('../pause');
1
+ const Helper = require('@codeceptjs/helper')
2
+ const ora = require('ora-classic')
3
+ const fs = require('fs')
4
+ const path = require('path')
5
+ const ai = require('../ai')
6
+ const standardActingHelpers = require('../plugin/standardActingHelpers')
7
+ const Container = require('../container')
8
+ const { splitByChunks, minifyHtml } = require('../html')
9
+ const { beautify } = require('../utils')
10
+ const output = require('../output')
11
+ const { registerVariable } = require('../pause')
12
12
 
13
13
  /**
14
14
  * AI Helper for CodeceptJS.
@@ -26,22 +26,22 @@ const { registerVariable } = require('../pause');
26
26
  */
27
27
  class AI extends Helper {
28
28
  constructor(config) {
29
- super(config);
30
- this.aiAssistant = ai;
29
+ super(config)
30
+ this.aiAssistant = ai
31
31
 
32
32
  this.options = {
33
33
  chunkSize: 80000,
34
- };
35
- this.options = { ...this.options, ...config };
34
+ }
35
+ this.options = { ...this.options, ...config }
36
36
  }
37
37
 
38
38
  _beforeSuite() {
39
- const helpers = Container.helpers();
39
+ const helpers = Container.helpers()
40
40
 
41
41
  for (const helperName of standardActingHelpers) {
42
42
  if (Object.keys(helpers).indexOf(helperName) > -1) {
43
- this.helper = helpers[helperName];
44
- break;
43
+ this.helper = helpers[helperName]
44
+ break
45
45
  }
46
46
  }
47
47
  }
@@ -58,30 +58,34 @@ class AI extends Helper {
58
58
  * @returns {Promise<string>} - A Promise that resolves to the generated responses from the GPT model, joined by newlines.
59
59
  */
60
60
  async askGptOnPage(prompt) {
61
- const html = await this.helper.grabSource();
61
+ const html = await this.helper.grabSource()
62
62
 
63
- const htmlChunks = splitByChunks(html, this.options.chunkSize);
63
+ const htmlChunks = splitByChunks(html, this.options.chunkSize)
64
64
 
65
- if (htmlChunks.length > 1) this.debug(`Splitting HTML into ${htmlChunks.length} chunks`);
65
+ if (htmlChunks.length > 1) this.debug(`Splitting HTML into ${htmlChunks.length} chunks`)
66
66
 
67
- const responses = [];
67
+ const responses = []
68
68
 
69
69
  for (const chunk of htmlChunks) {
70
70
  const messages = [
71
71
  { role: 'user', content: prompt },
72
72
  { role: 'user', content: `Within this HTML: ${minifyHtml(chunk)}` },
73
- ];
73
+ ]
74
74
 
75
- if (htmlChunks.length > 1) messages.push({ role: 'user', content: 'If action is not possible on this page, do not propose anything, I will send another HTML fragment' });
75
+ if (htmlChunks.length > 1)
76
+ messages.push({
77
+ role: 'user',
78
+ content: 'If action is not possible on this page, do not propose anything, I will send another HTML fragment',
79
+ })
76
80
 
77
- const response = await this._processAIRequest(messages);
81
+ const response = await this._processAIRequest(messages)
78
82
 
79
- output.print(response);
83
+ output.print(response)
80
84
 
81
- responses.push(response);
85
+ responses.push(response)
82
86
  }
83
87
 
84
- return responses.join('\n\n');
88
+ return responses.join('\n\n')
85
89
  }
86
90
 
87
91
  /**
@@ -97,18 +101,18 @@ class AI extends Helper {
97
101
  * @returns {Promise<string>} - A Promise that resolves to the generated response from the GPT model.
98
102
  */
99
103
  async askGptOnPageFragment(prompt, locator) {
100
- const html = await this.helper.grabHTMLFrom(locator);
104
+ const html = await this.helper.grabHTMLFrom(locator)
101
105
 
102
106
  const messages = [
103
107
  { role: 'user', content: prompt },
104
108
  { role: 'user', content: `Within this HTML: ${minifyHtml(html)}` },
105
- ];
109
+ ]
106
110
 
107
- const response = await this._processAIRequest(messages);
111
+ const response = await this._processAIRequest(messages)
108
112
 
109
- output.print(response);
113
+ output.print(response)
110
114
 
111
- return response;
115
+ return response
112
116
  }
113
117
 
114
118
  /**
@@ -117,15 +121,13 @@ class AI extends Helper {
117
121
  * @returns {Promise<string>} - A Promise that resolves to the generated response from the GPT model.
118
122
  */
119
123
  async askGptGeneralPrompt(prompt) {
120
- const messages = [
121
- { role: 'user', content: prompt },
122
- ];
124
+ const messages = [{ role: 'user', content: prompt }]
123
125
 
124
- const response = await this._processAIRequest(messages);
126
+ const response = await this._processAIRequest(messages)
125
127
 
126
- output.print(response);
128
+ output.print(response)
127
129
 
128
- return response;
130
+ return response
129
131
  }
130
132
 
131
133
  /**
@@ -154,48 +156,48 @@ class AI extends Helper {
154
156
  * @returns {Promise<Object>} A promise that resolves to the requested page object.
155
157
  */
156
158
  async askForPageObject(pageName, extraPrompt = null, locator = null) {
157
- const html = locator ? await this.helper.grabHTMLFrom(locator) : await this.helper.grabSource();
159
+ const html = locator ? await this.helper.grabHTMLFrom(locator) : await this.helper.grabSource()
158
160
 
159
- const spinner = ora(' Processing AI request...').start();
160
- await this.aiAssistant.setHtmlContext(html);
161
- const response = await this.aiAssistant.generatePageObject(extraPrompt, locator);
162
- spinner.stop();
161
+ const spinner = ora(' Processing AI request...').start()
162
+ await this.aiAssistant.setHtmlContext(html)
163
+ const response = await this.aiAssistant.generatePageObject(extraPrompt, locator)
164
+ spinner.stop()
163
165
 
164
166
  if (!response[0]) {
165
- output.error('No response from AI');
166
- return '';
167
+ output.error('No response from AI')
168
+ return ''
167
169
  }
168
170
 
169
- const code = beautify(response[0]);
171
+ const code = beautify(response[0])
170
172
 
171
- output.print('----- Generated PageObject ----');
172
- output.print(code);
173
- output.print('-------------------------------');
173
+ output.print('----- Generated PageObject ----')
174
+ output.print(code)
175
+ output.print('-------------------------------')
174
176
 
175
- const fileName = path.join(output_dir, `${pageName}Page-${Date.now()}.js`);
177
+ const fileName = path.join(output_dir, `${pageName}Page-${Date.now()}.js`)
176
178
 
177
- output.print(output.styles.bold(`Page object for ${pageName} is saved to ${output.styles.bold(fileName)}`));
178
- fs.writeFileSync(fileName, code);
179
+ output.print(output.styles.bold(`Page object for ${pageName} is saved to ${output.styles.bold(fileName)}`))
180
+ fs.writeFileSync(fileName, code)
179
181
 
180
182
  try {
181
- registerVariable('page', require(fileName));
182
- output.success('Page object registered for this session as `page` variable');
183
- output.print('Use `=>page.methodName()` in shell to run methods of page object');
184
- output.print('Use `click(page.locatorName)` to check locators of page object');
183
+ registerVariable('page', require(fileName))
184
+ output.success('Page object registered for this session as `page` variable')
185
+ output.print('Use `=>page.methodName()` in shell to run methods of page object')
186
+ output.print('Use `click(page.locatorName)` to check locators of page object')
185
187
  } catch (err) {
186
- output.error('Error while registering page object');
187
- output.error(err.message);
188
+ output.error('Error while registering page object')
189
+ output.error(err.message)
188
190
  }
189
191
 
190
- return code;
192
+ return code
191
193
  }
192
194
 
193
195
  async _processAIRequest(messages) {
194
- const spinner = ora(' Processing AI request...').start();
195
- const response = await this.aiAssistant.createCompletion(messages);
196
- spinner.stop();
197
- return response;
196
+ const spinner = ora(' Processing AI request...').start()
197
+ const response = await this.aiAssistant.createCompletion(messages)
198
+ spinner.stop()
199
+ return response
198
200
  }
199
201
  }
200
202
 
201
- module.exports = AI;
203
+ module.exports = AI