codeceptjs 3.5.7-beta.1 → 3.5.8

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.
@@ -8,7 +8,6 @@ const output = require('../output');
8
8
  const supportedHelpers = require('./standardActingHelpers');
9
9
 
10
10
  const defaultConfig = {
11
- healTries: 1,
12
11
  healLimit: 2,
13
12
  healSteps: [
14
13
  'click',
@@ -55,14 +54,11 @@ const defaultConfig = {
55
54
  *
56
55
  */
57
56
  module.exports = function (config = {}) {
58
- const aiAssistant = AiAssistant.getInstance();
57
+ const aiAssistant = new AiAssistant();
59
58
 
60
59
  let currentTest = null;
61
60
  let currentStep = null;
62
61
  let healedSteps = 0;
63
- let caughtError;
64
- let healTries = 0;
65
- let isHealing = false;
66
62
 
67
63
  const healSuggestions = [];
68
64
 
@@ -71,35 +67,20 @@ module.exports = function (config = {}) {
71
67
  event.dispatcher.on(event.test.before, (test) => {
72
68
  currentTest = test;
73
69
  healedSteps = 0;
74
- caughtError = null;
75
70
  });
76
71
 
77
72
  event.dispatcher.on(event.step.started, step => currentStep = step);
78
73
 
79
- event.dispatcher.on(event.step.after, (step) => {
80
- if (isHealing) return;
74
+ event.dispatcher.on(event.step.before, () => {
81
75
  const store = require('../store');
82
76
  if (store.debugMode) return;
77
+
83
78
  recorder.catchWithoutStop(async (err) => {
84
- isHealing = true;
85
- if (caughtError === err) throw err; // avoid double handling
86
- 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
- }
79
+ if (!aiAssistant.isEnabled) throw err;
91
80
  if (!currentStep) throw err;
92
81
  if (!config.healSteps.includes(currentStep.name)) throw err;
93
82
  const test = currentTest;
94
83
 
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
-
103
84
  if (healedSteps >= config.healLimit) {
104
85
  output.print(colors.bold.red(`Can't heal more than ${config.healLimit} step(s) in a test`));
105
86
  output.print('Entire flow can be broken, please check it manually');
@@ -130,17 +111,9 @@ module.exports = function (config = {}) {
130
111
 
131
112
  if (!html) throw err;
132
113
 
133
- healTries++;
134
- await aiAssistant.setHtmlContext(html);
114
+ aiAssistant.setHtmlContext(html);
135
115
  await tryToHeal(step, err);
136
-
137
- recorder.add('close healing session', () => {
138
- recorder.session.restore('heal');
139
- recorder.ignoreErr(err);
140
- });
141
- await recorder.promise();
142
-
143
- isHealing = false;
116
+ recorder.session.restore();
144
117
  });
145
118
  });
146
119
 
@@ -182,9 +155,6 @@ module.exports = function (config = {}) {
182
155
  for (const codeSnippet of codeSnippets) {
183
156
  try {
184
157
  debug('Executing', codeSnippet);
185
- recorder.catch((e) => {
186
- console.log(e);
187
- });
188
158
  await eval(codeSnippet); // eslint-disable-line
189
159
 
190
160
  healSuggestions.push({
@@ -193,17 +163,14 @@ module.exports = function (config = {}) {
193
163
  snippet: codeSnippet,
194
164
  });
195
165
 
196
- recorder.add('healed', () => output.print(colors.bold.green(' Code healed successfully')));
166
+ output.print(colors.bold.green(' Code healed successfully'));
197
167
  healedSteps++;
198
168
  return;
199
169
  } catch (err) {
200
170
  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
171
  }
204
172
  }
205
173
 
206
174
  output.debug(`Couldn't heal the code for ${failedStep.toCode()}`);
207
175
  }
208
- return recorder.promise();
209
176
  };
package/lib/recorder.js CHANGED
@@ -11,7 +11,6 @@ let errFn;
11
11
  let queueId = 0;
12
12
  let sessionId = null;
13
13
  let asyncErr = null;
14
- let ignoredErrs = [];
15
14
 
16
15
  let tasks = [];
17
16
  let oldPromises = [];
@@ -94,7 +93,6 @@ module.exports = {
94
93
  promise = Promise.resolve();
95
94
  oldPromises = [];
96
95
  tasks = [];
97
- ignoredErrs = [];
98
96
  this.session.running = false;
99
97
  // reset this retries makes the retryFailedStep plugin won't work if there is Before/BeforeSuit block due to retries is undefined on Scenario
100
98
  // this.retries = [];
@@ -228,10 +226,9 @@ module.exports = {
228
226
  * @inner
229
227
  */
230
228
  catch(customErrFn) {
231
- const fnDescription = customErrFn?.toString()?.replace(/\s{2,}/g, ' ').replace(/\n/g, ' ')?.slice(0, 50);
232
- debug(`${currentQueue()}Queued | catch with error handler ${fnDescription || ''}`);
229
+ debug(`${currentQueue()}Queued | catch with error handler`);
233
230
  return promise = promise.catch((err) => {
234
- log(`${currentQueue()}Error | ${err} ${fnDescription}...`);
231
+ log(`${currentQueue()}Error | ${err}`);
235
232
  if (!(err instanceof Error)) { // strange things may happen
236
233
  err = new Error(`[Wrapped Error] ${printObjectProperties(err)}`); // we should be prepared for them
237
234
  }
@@ -250,15 +247,15 @@ module.exports = {
250
247
  * @inner
251
248
  */
252
249
  catchWithoutStop(customErrFn) {
253
- const fnDescription = customErrFn?.toString()?.replace(/\s{2,}/g, ' ').replace(/\n/g, ' ')?.slice(0, 50);
254
250
  return promise = promise.catch((err) => {
255
- if (ignoredErrs.includes(err)) return; // already caught
256
- log(`${currentQueue()}Error (Non-Terminated) | ${err} | ${fnDescription || ''}...`);
251
+ log(`${currentQueue()}Error | ${err}`);
257
252
  if (!(err instanceof Error)) { // strange things may happen
258
253
  err = new Error(`[Wrapped Error] ${JSON.stringify(err)}`); // we should be prepared for them
259
254
  }
260
255
  if (customErrFn) {
261
256
  return customErrFn(err);
257
+ } if (errFn) {
258
+ return errFn(err);
262
259
  }
263
260
  });
264
261
  },
@@ -277,10 +274,6 @@ module.exports = {
277
274
  });
278
275
  },
279
276
 
280
- ignoreErr(err) {
281
- ignoredErrs.push(err);
282
- },
283
-
284
277
  /**
285
278
  * @param {*} err
286
279
  * @inner
package/lib/utils.js CHANGED
@@ -11,7 +11,7 @@ function deepMerge(target, source) {
11
11
  }
12
12
 
13
13
  module.exports.genTestId = (test) => {
14
- return require('crypto').createHash('md5').update(test.fullTitle()).digest('base64')
14
+ return require('crypto').createHash('sha256').update(test.fullTitle()).digest('base64')
15
15
  .slice(0, -2);
16
16
  };
17
17
 
package/lib/workers.js CHANGED
@@ -94,10 +94,31 @@ const createWorkerObjects = (testGroups, config, testRoot, options, selectedRuns
94
94
  });
95
95
  }
96
96
  const workersToExecute = [];
97
+
98
+ const currentOutputFolder = config.output;
99
+ let currentMochawesomeReportDir;
100
+ let currentMochaJunitReporterFile;
101
+
102
+ if (config.mocha && config.mocha.reporterOptions) {
103
+ currentMochawesomeReportDir = config.mocha.reporterOptions?.mochawesome.options.reportDir;
104
+ currentMochaJunitReporterFile = config.mocha.reporterOptions['mocha-junit-reporter'].options.mochaFile;
105
+ }
106
+
97
107
  collection.createRuns(selectedRuns, config).forEach((worker) => {
98
- const workerName = worker.getOriginalName() || worker.getName();
108
+ const separator = path.sep;
109
+ const _config = { ...config };
110
+ let workerName = worker.name.replace(':', '_');
111
+ _config.output = `${currentOutputFolder}${separator}${workerName}`;
112
+ if (config.mocha && config.mocha.reporterOptions) {
113
+ _config.mocha.reporterOptions.mochawesome.options.reportDir = `${currentMochawesomeReportDir}${separator}${workerName}`;
114
+
115
+ const _tempArray = currentMochaJunitReporterFile.split(separator);
116
+ _tempArray.splice(_tempArray.findIndex(item => item.includes('.xml')), 0, workerName);
117
+ _config.mocha.reporterOptions['mocha-junit-reporter'].options.mochaFile = _tempArray.join(separator);
118
+ }
119
+ workerName = worker.getOriginalName() || worker.getName();
99
120
  const workerConfig = worker.getConfig();
100
- workersToExecute.push(getOverridenConfig(workerName, workerConfig, config));
121
+ workersToExecute.push(getOverridenConfig(workerName, workerConfig, _config));
101
122
  });
102
123
  const workers = [];
103
124
  let index = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeceptjs",
3
- "version": "3.5.7-beta.1",
3
+ "version": "3.5.8",
4
4
  "description": "Supercharged End 2 End Testing Framework for NodeJS",
5
5
  "keywords": [
6
6
  "acceptance",
@@ -43,8 +43,10 @@
43
43
  "test:unit": "mocha test/unit --recursive --timeout 10000",
44
44
  "test:runner": "mocha test/runner --recursive --timeout 10000",
45
45
  "test": "npm run test:unit && npm run test:runner",
46
- "test:appium-quick": "mocha test/helper/Appium_test.js --grep 'quick'",
47
- "test:appium-other": "mocha test/helper/Appium_test.js --grep 'second'",
46
+ "test:appium-quick": "mocha test/helper/AppiumV2_test.js --grep 'quick'",
47
+ "test:appium-other": "mocha test/helper/AppiumV2_test.js --grep 'second'",
48
+ "test:ios:appium-quick": "mocha test/helper/AppiumV2_ios_test.js --grep 'quick'",
49
+ "test:ios:appium-other": "mocha test/helper/AppiumV2_ios_test.js --grep 'second'",
48
50
  "test-app:start": "php -S 127.0.0.1:8000 -t test/data/app",
49
51
  "test-app:stop": "kill -9 $(lsof -t -i:8000)",
50
52
  "test:unit:webbapi:playwright": "mocha test/helper/Playwright_test.js",
@@ -86,9 +88,9 @@
86
88
  "fn-args": "4.0.0",
87
89
  "fs-extra": "8.1.0",
88
90
  "glob": "6.0.1",
89
- "html-minifier-terser": "^7.2.0",
91
+ "html-minifier": "4.0.0",
90
92
  "inquirer": "6.5.2",
91
- "joi": "17.6.0",
93
+ "joi": "17.11.0",
92
94
  "js-beautify": "1.14.9",
93
95
  "lodash.clonedeep": "4.5.0",
94
96
  "lodash.merge": "4.6.2",
@@ -115,24 +117,24 @@
115
117
  "@types/node": "20.4.4",
116
118
  "@wdio/sauce-service": "8.3.8",
117
119
  "@wdio/selenium-standalone-service": "8.3.2",
118
- "@wdio/utils": "8.16.22",
120
+ "@wdio/utils": "8.20.3",
119
121
  "apollo-server-express": "2.25.3",
120
122
  "chai-as-promised": "7.1.1",
121
123
  "chai-subset": "1.6.0",
122
- "contributor-faces": "1.0.3",
124
+ "contributor-faces": "1.1.0",
123
125
  "documentation": "12.3.0",
124
- "dtslint": "4.1.6",
125
- "electron": "27.0.2",
126
- "eslint": "8.50.0",
126
+ "dtslint": "4.2.1",
127
+ "electron": "27.0.4",
128
+ "eslint": "8.53.0",
127
129
  "eslint-config-airbnb-base": "15.0.0",
128
- "eslint-plugin-import": "2.25.4",
130
+ "eslint-plugin-import": "2.29.0",
129
131
  "eslint-plugin-mocha": "6.3.0",
130
132
  "expect": "29.7.0",
131
- "express": "4.17.2",
133
+ "express": "4.18.2",
132
134
  "graphql": "14.6.0",
133
135
  "husky": "8.0.3",
134
136
  "inquirer-test": "2.0.1",
135
- "jsdoc": "3.6.10",
137
+ "jsdoc": "3.6.11",
136
138
  "jsdoc-typeof-plugin": "1.0.0",
137
139
  "json-server": "0.10.1",
138
140
  "playwright": "1.39.0",
@@ -140,13 +142,13 @@
140
142
  "qrcode-terminal": "0.12.0",
141
143
  "rosie": "2.1.0",
142
144
  "runok": "0.9.3",
143
- "sinon": "15.2.0",
145
+ "sinon": "17.0.1",
144
146
  "sinon-chai": "3.7.0",
145
147
  "testcafe": "3.3.0",
146
148
  "ts-morph": "19.0.0",
147
149
  "ts-node": "10.9.1",
148
150
  "tsd-jsdoc": "2.5.0",
149
- "typedoc": "0.24.8",
151
+ "typedoc": "0.25.3",
150
152
  "typedoc-plugin-markdown": "3.13.4",
151
153
  "typescript": "5.2.2",
152
154
  "wdio-docker-service": "1.5.0",
@@ -508,10 +508,12 @@ declare namespace CodeceptJS {
508
508
  * I.setNetworkConnection(4) // airplane mode off, wifi off, data on
509
509
  * I.setNetworkConnection(6) // airplane mode off, wifi on, data on
510
510
  * ```
511
- * See corresponding [webdriverio reference](http://webdriver.io/api/mobile/setNetworkConnection.html).
512
- * @returns Appium: support only Android
511
+ * See corresponding [webdriverio reference](https://webdriver.io/docs/api/chromium/#setnetworkconnection).
512
+ *
513
+ * Appium: support only Android
514
+ * @param value - The network connection mode bitmask
513
515
  */
514
- setNetworkConnection(): Promise<{}>;
516
+ setNetworkConnection(value: number): Promise<number>;
515
517
  /**
516
518
  * Update the current setting on the device
517
519
  *
@@ -2816,6 +2818,10 @@ declare namespace CodeceptJS {
2816
2818
  * npm i playwright-core@^1.18 --save
2817
2819
  * ```
2818
2820
  *
2821
+ * Breaking Changes: if you use Playwright v1.38 and later, it will no longer download browsers automatically.
2822
+ *
2823
+ * Run `npx playwright install` to download browsers after `npm install`.
2824
+ *
2819
2825
  * Using playwright-core package, will prevent the download of browser binaries and allow connecting to an existing browser installation or for connecting to a remote one.
2820
2826
  *
2821
2827
  *
@@ -3178,6 +3184,18 @@ declare namespace CodeceptJS {
3178
3184
  * @returns automatically synchronized promise through #recorder
3179
3185
  */
3180
3186
  blur(locator: CodeceptJS.LocatorOrString, options?: any): Promise<void>;
3187
+ /**
3188
+ * Return the checked status of given element.
3189
+ * @param locator - element located by CSS|XPath|strict locator.
3190
+ * @param [options] - See https://playwright.dev/docs/api/class-locator#locator-is-checked
3191
+ */
3192
+ grabCheckedElementStatus(locator: CodeceptJS.LocatorOrString, options?: any): Promise<boolean>;
3193
+ /**
3194
+ * Return the disabled status of given element.
3195
+ * @param locator - element located by CSS|XPath|strict locator.
3196
+ * @param [options] - See https://playwright.dev/docs/api/class-locator#locator-is-disabled
3197
+ */
3198
+ grabDisabledElementStatus(locator: CodeceptJS.LocatorOrString, options?: any): Promise<boolean>;
3181
3199
  /**
3182
3200
  * Drag an item to a destination element.
3183
3201
  *
@@ -6171,6 +6189,14 @@ declare namespace CodeceptJS {
6171
6189
  *
6172
6190
  * <!-- configuration -->
6173
6191
  *
6192
+ * #### Trace Recording Customization
6193
+ *
6194
+ * Trace recording provides complete information on test execution and includes screenshots, and network requests logged during run.
6195
+ * Traces will be saved to `output/trace`
6196
+ *
6197
+ * * `trace`: enables trace recording for failed tests; trace are saved into `output/trace` folder
6198
+ * * `keepTraceForPassedTests`: - save trace for passed tests
6199
+ *
6174
6200
  * #### Example #1: Wait for 0 network connections.
6175
6201
  *
6176
6202
  * ```js
@@ -508,10 +508,12 @@ declare namespace CodeceptJS {
508
508
  * I.setNetworkConnection(4) // airplane mode off, wifi off, data on
509
509
  * I.setNetworkConnection(6) // airplane mode off, wifi on, data on
510
510
  * ```
511
- * See corresponding [webdriverio reference](http://webdriver.io/api/mobile/setNetworkConnection.html).
512
- * @returns Appium: support only Android
511
+ * See corresponding [webdriverio reference](https://webdriver.io/docs/api/chromium/#setnetworkconnection).
512
+ *
513
+ * Appium: support only Android
514
+ * @param value - The network connection mode bitmask
513
515
  */
514
- setNetworkConnection(): Promise<{}>;
516
+ setNetworkConnection(value: number): Promise<number>;
515
517
  /**
516
518
  * Update the current setting on the device
517
519
  *
@@ -2903,6 +2905,10 @@ declare namespace CodeceptJS {
2903
2905
  * npm i playwright-core@^1.18 --save
2904
2906
  * ```
2905
2907
  *
2908
+ * Breaking Changes: if you use Playwright v1.38 and later, it will no longer download browsers automatically.
2909
+ *
2910
+ * Run `npx playwright install` to download browsers after `npm install`.
2911
+ *
2906
2912
  * Using playwright-core package, will prevent the download of browser binaries and allow connecting to an existing browser installation or for connecting to a remote one.
2907
2913
  *
2908
2914
  *
@@ -3265,6 +3271,18 @@ declare namespace CodeceptJS {
3265
3271
  * @returns automatically synchronized promise through #recorder
3266
3272
  */
3267
3273
  blur(locator: CodeceptJS.LocatorOrString, options?: any): Promise<void>;
3274
+ /**
3275
+ * Return the checked status of given element.
3276
+ * @param locator - element located by CSS|XPath|strict locator.
3277
+ * @param [options] - See https://playwright.dev/docs/api/class-locator#locator-is-checked
3278
+ */
3279
+ grabCheckedElementStatus(locator: CodeceptJS.LocatorOrString, options?: any): Promise<boolean>;
3280
+ /**
3281
+ * Return the disabled status of given element.
3282
+ * @param locator - element located by CSS|XPath|strict locator.
3283
+ * @param [options] - See https://playwright.dev/docs/api/class-locator#locator-is-disabled
3284
+ */
3285
+ grabDisabledElementStatus(locator: CodeceptJS.LocatorOrString, options?: any): Promise<boolean>;
3268
3286
  /**
3269
3287
  * Drag an item to a destination element.
3270
3288
  *
@@ -6258,6 +6276,8 @@ declare namespace CodeceptJS {
6258
6276
  * @property [disableScreenshots = false] - don't save screenshot on failure.
6259
6277
  * @property [fullPageScreenshots = false] - make full page screenshots on failure.
6260
6278
  * @property [uniqueScreenshotNames = false] - option to prevent screenshot override if you have scenarios with the same name in different suites.
6279
+ * @property [trace = false] - record [tracing information](https://pptr.dev/api/puppeteer.tracing) with screenshots.
6280
+ * @property [keepTraceForPassedTests = false] - save trace for passed tests.
6261
6281
  * @property [keepBrowserState = false] - keep browser state between tests when `restart` is set to false.
6262
6282
  * @property [keepCookies = false] - keep cookies between tests when `restart` is set to false.
6263
6283
  * @property [waitForAction = 100] - how long to wait after click, doubleClick or PressKey actions in ms. Default: 100.
@@ -6280,6 +6300,8 @@ declare namespace CodeceptJS {
6280
6300
  disableScreenshots?: boolean;
6281
6301
  fullPageScreenshots?: boolean;
6282
6302
  uniqueScreenshotNames?: boolean;
6303
+ trace?: boolean;
6304
+ keepTraceForPassedTests?: boolean;
6283
6305
  keepBrowserState?: boolean;
6284
6306
  keepCookies?: boolean;
6285
6307
  waitForAction?: number;
@@ -6313,6 +6335,14 @@ declare namespace CodeceptJS {
6313
6335
  *
6314
6336
  * <!-- configuration -->
6315
6337
  *
6338
+ * #### Trace Recording Customization
6339
+ *
6340
+ * Trace recording provides complete information on test execution and includes screenshots, and network requests logged during run.
6341
+ * Traces will be saved to `output/trace`
6342
+ *
6343
+ * * `trace`: enables trace recording for failed tests; trace are saved into `output/trace` folder
6344
+ * * `keepTraceForPassedTests`: - save trace for passed tests
6345
+ *
6316
6346
  * #### Example #1: Wait for 0 network connections.
6317
6347
  *
6318
6348
  * ```js