codeceptjs 3.5.7-beta.1 → 3.5.7

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.7",
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,17 +117,17 @@
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
126
  "dtslint": "4.1.6",
125
127
  "electron": "27.0.2",
126
- "eslint": "8.50.0",
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
133
  "express": "4.17.2",
@@ -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",
@@ -2816,6 +2816,10 @@ declare namespace CodeceptJS {
2816
2816
  * npm i playwright-core@^1.18 --save
2817
2817
  * ```
2818
2818
  *
2819
+ * Breaking Changes: if you use Playwright v1.38 and later, it will no longer download browsers automatically.
2820
+ *
2821
+ * Run `npx playwright install` to download browsers after `npm install`.
2822
+ *
2819
2823
  * 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
2824
  *
2821
2825
  *
@@ -3178,6 +3182,18 @@ declare namespace CodeceptJS {
3178
3182
  * @returns automatically synchronized promise through #recorder
3179
3183
  */
3180
3184
  blur(locator: CodeceptJS.LocatorOrString, options?: any): Promise<void>;
3185
+ /**
3186
+ * Return the checked status of given element.
3187
+ * @param locator - element located by CSS|XPath|strict locator.
3188
+ * @param [options] - See https://playwright.dev/docs/api/class-locator#locator-is-checked
3189
+ */
3190
+ grabCheckedElementStatus(locator: CodeceptJS.LocatorOrString, options?: any): Promise<boolean>;
3191
+ /**
3192
+ * Return the disabled status of given element.
3193
+ * @param locator - element located by CSS|XPath|strict locator.
3194
+ * @param [options] - See https://playwright.dev/docs/api/class-locator#locator-is-disabled
3195
+ */
3196
+ grabDisabledElementStatus(locator: CodeceptJS.LocatorOrString, options?: any): Promise<boolean>;
3181
3197
  /**
3182
3198
  * Drag an item to a destination element.
3183
3199
  *
@@ -6171,6 +6187,14 @@ declare namespace CodeceptJS {
6171
6187
  *
6172
6188
  * <!-- configuration -->
6173
6189
  *
6190
+ * #### Trace Recording Customization
6191
+ *
6192
+ * Trace recording provides complete information on test execution and includes screenshots, and network requests logged during run.
6193
+ * Traces will be saved to `output/trace`
6194
+ *
6195
+ * * `trace`: enables trace recording for failed tests; trace are saved into `output/trace` folder
6196
+ * * `keepTraceForPassedTests`: - save trace for passed tests
6197
+ *
6174
6198
  * #### Example #1: Wait for 0 network connections.
6175
6199
  *
6176
6200
  * ```js
@@ -2903,6 +2903,10 @@ declare namespace CodeceptJS {
2903
2903
  * npm i playwright-core@^1.18 --save
2904
2904
  * ```
2905
2905
  *
2906
+ * Breaking Changes: if you use Playwright v1.38 and later, it will no longer download browsers automatically.
2907
+ *
2908
+ * Run `npx playwright install` to download browsers after `npm install`.
2909
+ *
2906
2910
  * 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
2911
  *
2908
2912
  *
@@ -3265,6 +3269,18 @@ declare namespace CodeceptJS {
3265
3269
  * @returns automatically synchronized promise through #recorder
3266
3270
  */
3267
3271
  blur(locator: CodeceptJS.LocatorOrString, options?: any): Promise<void>;
3272
+ /**
3273
+ * Return the checked status of given element.
3274
+ * @param locator - element located by CSS|XPath|strict locator.
3275
+ * @param [options] - See https://playwright.dev/docs/api/class-locator#locator-is-checked
3276
+ */
3277
+ grabCheckedElementStatus(locator: CodeceptJS.LocatorOrString, options?: any): Promise<boolean>;
3278
+ /**
3279
+ * Return the disabled status of given element.
3280
+ * @param locator - element located by CSS|XPath|strict locator.
3281
+ * @param [options] - See https://playwright.dev/docs/api/class-locator#locator-is-disabled
3282
+ */
3283
+ grabDisabledElementStatus(locator: CodeceptJS.LocatorOrString, options?: any): Promise<boolean>;
3268
3284
  /**
3269
3285
  * Drag an item to a destination element.
3270
3286
  *
@@ -6258,6 +6274,8 @@ declare namespace CodeceptJS {
6258
6274
  * @property [disableScreenshots = false] - don't save screenshot on failure.
6259
6275
  * @property [fullPageScreenshots = false] - make full page screenshots on failure.
6260
6276
  * @property [uniqueScreenshotNames = false] - option to prevent screenshot override if you have scenarios with the same name in different suites.
6277
+ * @property [trace = false] - record [tracing information](https://pptr.dev/api/puppeteer.tracing) with screenshots.
6278
+ * @property [keepTraceForPassedTests = false] - save trace for passed tests.
6261
6279
  * @property [keepBrowserState = false] - keep browser state between tests when `restart` is set to false.
6262
6280
  * @property [keepCookies = false] - keep cookies between tests when `restart` is set to false.
6263
6281
  * @property [waitForAction = 100] - how long to wait after click, doubleClick or PressKey actions in ms. Default: 100.
@@ -6280,6 +6298,8 @@ declare namespace CodeceptJS {
6280
6298
  disableScreenshots?: boolean;
6281
6299
  fullPageScreenshots?: boolean;
6282
6300
  uniqueScreenshotNames?: boolean;
6301
+ trace?: boolean;
6302
+ keepTraceForPassedTests?: boolean;
6283
6303
  keepBrowserState?: boolean;
6284
6304
  keepCookies?: boolean;
6285
6305
  waitForAction?: number;
@@ -6313,6 +6333,14 @@ declare namespace CodeceptJS {
6313
6333
  *
6314
6334
  * <!-- configuration -->
6315
6335
  *
6336
+ * #### Trace Recording Customization
6337
+ *
6338
+ * Trace recording provides complete information on test execution and includes screenshots, and network requests logged during run.
6339
+ * Traces will be saved to `output/trace`
6340
+ *
6341
+ * * `trace`: enables trace recording for failed tests; trace are saved into `output/trace` folder
6342
+ * * `keepTraceForPassedTests`: - save trace for passed tests
6343
+ *
6316
6344
  * #### Example #1: Wait for 0 network connections.
6317
6345
  *
6318
6346
  * ```js