codeceptjs 3.3.8-beta.1 → 3.4.0

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 (72) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +31 -32
  3. package/docs/advanced.md +48 -24
  4. package/docs/basics.md +115 -40
  5. package/docs/best.md +2 -2
  6. package/docs/build/ApiDataFactory.js +14 -9
  7. package/docs/build/Appium.js +2 -19
  8. package/docs/build/FileSystem.js +3 -3
  9. package/docs/build/GraphQL.js +1 -1
  10. package/docs/build/GraphQLDataFactory.js +3 -3
  11. package/docs/build/JSONResponse.js +1 -1
  12. package/docs/build/Mochawesome.js +1 -1
  13. package/docs/build/Nightmare.js +1 -1
  14. package/docs/build/Playwright.js +4 -3
  15. package/docs/build/Protractor.js +1 -1
  16. package/docs/build/Puppeteer.js +1 -1
  17. package/docs/build/REST.js +1 -1
  18. package/docs/build/TestCafe.js +5 -5
  19. package/docs/build/WebDriver.js +30 -165
  20. package/docs/changelog.md +49 -2
  21. package/docs/helpers/ApiDataFactory.md +6 -6
  22. package/docs/helpers/FileSystem.md +2 -2
  23. package/docs/helpers/GraphQLDataFactory.md +2 -2
  24. package/docs/helpers/Playwright.md +2 -1
  25. package/docs/index.md +1 -1
  26. package/docs/plugins.md +42 -125
  27. package/docs/reports.md +0 -56
  28. package/docs/tutorial.md +271 -0
  29. package/docs/typescript.md +2 -8
  30. package/lib/actor.js +2 -1
  31. package/lib/cli.js +3 -3
  32. package/lib/codecept.js +2 -1
  33. package/lib/command/generate.js +3 -1
  34. package/lib/command/gherkin/snippets.js +8 -4
  35. package/lib/command/init.js +0 -8
  36. package/lib/command/run-workers.js +3 -6
  37. package/lib/command/utils.js +0 -10
  38. package/lib/command/workers/runTests.js +2 -2
  39. package/lib/config.js +5 -1
  40. package/lib/helper/ApiDataFactory.js +14 -9
  41. package/lib/helper/Appium.js +2 -19
  42. package/lib/helper/FileSystem.js +3 -3
  43. package/lib/helper/GraphQL.js +1 -1
  44. package/lib/helper/GraphQLDataFactory.js +3 -3
  45. package/lib/helper/JSONResponse.js +1 -1
  46. package/lib/helper/Mochawesome.js +1 -1
  47. package/lib/helper/Nightmare.js +1 -1
  48. package/lib/helper/Playwright.js +4 -3
  49. package/lib/helper/Protractor.js +1 -1
  50. package/lib/helper/Puppeteer.js +1 -1
  51. package/lib/helper/REST.js +1 -1
  52. package/lib/helper/TestCafe.js +5 -5
  53. package/lib/helper/WebDriver.js +30 -165
  54. package/lib/helper.js +0 -2
  55. package/lib/interfaces/bdd.js +1 -1
  56. package/lib/interfaces/featureConfig.js +1 -0
  57. package/lib/interfaces/gherkin.js +38 -25
  58. package/lib/listener/exit.js +2 -2
  59. package/lib/listener/retry.js +67 -0
  60. package/lib/listener/steps.js +1 -1
  61. package/lib/listener/timeout.js +47 -10
  62. package/lib/mochaFactory.js +3 -3
  63. package/lib/plugin/allure.js +14 -323
  64. package/lib/plugin/fakerTransform.js +2 -2
  65. package/lib/recorder.js +1 -1
  66. package/lib/scenario.js +25 -18
  67. package/lib/utils.js +6 -0
  68. package/lib/workers.js +4 -7
  69. package/package.json +14 -18
  70. package/typings/index.d.ts +76 -1
  71. package/typings/promiseBasedTypes.d.ts +12 -12
  72. package/typings/types.d.ts +95 -262
@@ -1,324 +1,15 @@
1
- const Allure = require('allure-js-commons');
2
-
3
- const event = require('../event');
4
- const logger = require('../output');
5
- const { ansiRegExp } = require('../utils');
6
-
7
- const defaultConfig = {
8
- outputDir: global.output_dir,
9
- };
10
-
11
- /**
12
- * Allure reporter
13
- *
14
- * ![](https://user-images.githubusercontent.com/220264/45676511-8e052800-bb3a-11e8-8cbb-db5f73de2add.png)
15
- *
16
- * Enables Allure reporter.
17
- *
18
- * #### Usage
19
- *
20
- * To start please install `allure-commandline` package (which requires Java 8)
21
- *
22
- * ```
23
- * npm install -g allure-commandline --save-dev
24
- * ```
25
- *
26
- * Add this plugin to config file:
27
- *
28
- * ```js
29
- * "plugins": {
30
- * "allure": {}
31
- * }
32
- * ```
33
- *
34
- * Run tests with allure plugin enabled:
35
- *
36
- * ```
37
- * npx codeceptjs run --plugins allure
38
- * ```
39
- *
40
- * By default, allure reports are saved to `output` directory.
41
- * Launch Allure server and see the report like on a screenshot above:
42
- *
43
- * ```
44
- * allure serve output
45
- * ```
46
- *
47
- * #### Configuration
48
- *
49
- * * `outputDir` - a directory where allure reports should be stored. Standard output directory is set by default.
50
- * * `enableScreenshotDiffPlugin` - a boolean flag for add screenshot diff to report.
51
- * To attach, tou need to attach three files to the report - "diff.png", "actual.png", "expected.png".
52
- * See [Allure Screenshot Plugin](https://github.com/allure-framework/allure2/blob/master/plugins/screen-diff-plugin/README.md)
53
- *
54
- * #### Public API
55
- *
56
- * There are few public API methods which can be accessed from other plugins.
57
- *
58
- * ```js
59
- * const allure = codeceptjs.container.plugins('allure');
60
- * ```
61
- *
62
- * `allure` object has following methods:
63
- *
64
- * * `addAttachment(name, buffer, type)` - add an attachment to current test / suite
65
- * * `addLabel(name, value)` - adds a label to current test
66
- * * `addParameter(kind, name, value)` - adds a parameter to current test
67
- * * `createStep(name, stepFunc)` - create a step, stepFunc could consist an attachment
68
- * Example of usage:
69
- * ```js
70
- * allure.createStep('New created step', () => {
71
- * allure.addAttachment(
72
- * 'Request params',
73
- * '{"clientId":123, "name":"Tom", "age":29}',
74
- * 'application/json'
75
- * );
76
- * });
77
- * ```
78
- * ![Created Step Image](https://user-images.githubusercontent.com/63167966/139339384-e6e70a62-3638-406d-a224-f32473071428.png)
79
- * * `severity(value)` - adds severity label
80
- * * `epic(value)` - adds epic label
81
- * * `feature(value)` - adds feature label
82
- * * `story(value)` - adds story label
83
- * * `issue(value)` - adds issue label
84
- * * `setDescription(description, type)` - sets a description
85
- *
86
- */
87
- module.exports = (config) => {
88
- defaultConfig.outputDir = global.output_dir;
89
- config = Object.assign(defaultConfig, config);
90
-
91
- const plugin = {};
92
-
93
- const reporter = new Allure();
94
- reporter.setOptions({ targetDir: config.outputDir });
95
-
96
- let currentMetaStep = [];
97
- let currentStep;
98
-
99
- reporter.pendingCase = function (testName, timestamp, opts = {}) {
100
- reporter.startCase(testName, timestamp);
101
-
102
- if (opts.description) plugin.setDescription(opts.description);
103
- if (opts.severity) plugin.severity(opts.severity);
104
- if (opts.severity) plugin.addLabel('tag', opts.severity);
105
-
106
- reporter.endCase('pending', { message: opts.message || 'Test ignored' }, timestamp);
107
- };
108
-
109
- plugin.addAttachment = (name, buffer, type) => {
110
- reporter.addAttachment(name, buffer, type);
111
- };
112
-
113
- plugin.setDescription = (description, type) => {
114
- const currentTest = reporter.getCurrentTest();
115
- if (currentTest) {
116
- currentTest.setDescription(description, type);
117
- } else {
118
- logger.error(`The test is not run. Please use "setDescription" for events:
119
- "test.start", "test.before", "test.after", "test.passed", "test.failed", "test.finish"`);
120
- }
121
- };
122
-
123
- plugin.createStep = (name, stepFunc = () => { }) => {
124
- let result;
125
- let status = 'passed';
126
- reporter.startStep(name);
127
- try {
128
- result = stepFunc(this.arguments);
129
- } catch (error) {
130
- status = 'broken';
131
- throw error;
132
- } finally {
133
- if (!!result
134
- && (typeof result === 'object' || typeof result === 'function')
135
- && typeof result.then === 'function'
136
- ) {
137
- result.then(() => reporter.endStep('passed'), () => reporter.endStep('broken'));
138
- } else {
139
- reporter.endStep(status);
140
- }
141
- }
142
- return result;
143
- };
144
-
145
- plugin.createAttachment = (name, content, type) => {
146
- if (typeof content === 'function') {
147
- const attachmentName = name;
148
- const buffer = content.apply(this, arguments);
149
- return createAttachment(attachmentName, buffer, type);
150
- } reporter.addAttachment(name, content, type);
151
- };
152
-
153
- plugin.severity = (severity) => {
154
- plugin.addLabel('severity', severity);
155
- };
156
-
157
- plugin.epic = (epic) => {
158
- plugin.addLabel('epic', epic);
159
- };
160
-
161
- plugin.feature = (feature) => {
162
- plugin.addLabel('feature', feature);
163
- };
164
-
165
- plugin.story = (story) => {
166
- plugin.addLabel('story', story);
167
- };
168
-
169
- plugin.issue = (issue) => {
170
- plugin.addLabel('issue', issue);
171
- };
172
-
173
- plugin.addLabel = (name, value) => {
174
- const currentTest = reporter.getCurrentTest();
175
- if (currentTest) {
176
- currentTest.addLabel(name, value);
177
- } else {
178
- logger.error(`The test is not run. Please use "addLabel" for events:
179
- "test.start", "test.before", "test.after", "test.passed", "test.failed", "test.finish"`);
180
- }
181
- };
182
-
183
- plugin.addParameter = (kind, name, value) => {
184
- const currentTest = reporter.getCurrentTest();
185
- if (currentTest) {
186
- currentTest.addParameter(kind, name, value);
187
- } else {
188
- logger.error(`The test is not run. Please use "addParameter" for events:
189
- "test.start", "test.before", "test.after", "test.passed", "test.failed", "test.finish"`);
190
- }
191
- };
192
-
193
- event.dispatcher.on(event.suite.before, (suite) => {
194
- reporter.startSuite(suite.fullTitle());
195
- });
196
-
197
- event.dispatcher.on(event.suite.before, (suite) => {
198
- for (const test of suite.tests) {
199
- if (test.pending) {
200
- reporter.pendingCase(test.title, null, test.opts.skipInfo);
201
- }
202
- }
203
- });
204
-
205
- event.dispatcher.on(event.suite.after, () => {
206
- reporter.endSuite();
207
- });
208
-
209
- event.dispatcher.on(event.test.before, (test) => {
210
- reporter.startCase(test.title);
211
- if (config.enableScreenshotDiffPlugin) {
212
- const currentTest = reporter.getCurrentTest();
213
- currentTest.addLabel('testType', 'screenshotDiff');
214
- }
215
- currentStep = null;
216
- });
217
-
218
- event.dispatcher.on(event.test.started, (test) => {
219
- const currentTest = reporter.getCurrentTest();
220
- for (const tag of test.tags) {
221
- currentTest.addLabel('tag', tag);
222
- }
223
- });
224
-
225
- event.dispatcher.on(event.test.failed, (test, err) => {
226
- if (currentStep) reporter.endStep('failed');
227
- if (currentMetaStep.length) {
228
- currentMetaStep.forEach(() => reporter.endStep('failed'));
229
- currentMetaStep = [];
230
- }
231
-
232
- err.message = err.message.replace(ansiRegExp(), '');
233
- if (reporter.getCurrentTest()) {
234
- reporter.endCase('failed', err);
235
- } else {
236
- // this means before suite failed, we should report this.
237
- reporter.startCase(`BeforeSuite of suite ${reporter.getCurrentSuite().name} failed.`);
238
- reporter.endCase('failed', err);
239
- }
240
- });
241
-
242
- event.dispatcher.on(event.test.passed, () => {
243
- if (currentStep) reporter.endStep('passed');
244
- if (currentMetaStep.length) {
245
- currentMetaStep.forEach(() => reporter.endStep('passed'));
246
- currentMetaStep = [];
247
- }
248
- reporter.endCase('passed');
249
- });
250
-
251
- event.dispatcher.on(event.test.skipped, (test) => {
252
- let loaded = true;
253
- if (test.opts.skipInfo.isFastSkipped) {
254
- loaded = false;
255
- reporter.startSuite(test.parent.fullTitle());
256
- }
257
- reporter.pendingCase(test.title, null, test.opts.skipInfo);
258
- if (!loaded) {
259
- reporter.endSuite();
260
- }
261
- });
262
-
263
- event.dispatcher.on(event.step.started, (step) => {
264
- startMetaStep(step.metaStep);
265
- if (currentStep !== step) {
266
- // In multi-session scenarios, actors' names will be highlighted with ANSI
267
- // escape sequences which are invalid XML values
268
- step.actor = step.actor.replace(ansiRegExp(), '');
269
- reporter.startStep(step.toString());
270
- currentStep = step;
271
- }
272
- });
273
-
274
- event.dispatcher.on(event.step.comment, (step) => {
275
- reporter.startStep(step.toString());
276
- currentStep = step;
277
- reporter.endStep('passed');
278
- currentStep = null;
279
- });
280
-
281
- event.dispatcher.on(event.step.passed, (step) => {
282
- if (currentStep === step) {
283
- reporter.endStep('passed');
284
- currentStep = null;
285
- }
286
- });
287
-
288
- event.dispatcher.on(event.step.failed, (step) => {
289
- if (currentStep === step) {
290
- reporter.endStep('failed');
291
- currentStep = null;
292
- }
293
- });
294
-
295
- let maxLevel;
296
- function finishMetastep(level) {
297
- const metaStepsToFinish = currentMetaStep.splice(maxLevel - level);
298
- metaStepsToFinish.forEach(() => {
299
- // only if the current step is of type Step, end it.
300
- if (reporter.suites && reporter.suites.length && reporter.suites[0].currentStep && reporter.suites[0].currentStep.constructor.name === 'Step') {
301
- reporter.endStep('passed');
302
- }
303
- });
304
- }
305
-
306
- function startMetaStep(metaStep, level = 0) {
307
- maxLevel = level;
308
- if (!metaStep) {
309
- finishMetastep(0);
310
- maxLevel--;
311
- return;
312
- }
313
-
314
- startMetaStep(metaStep.metaStep, level + 1);
315
-
316
- if (metaStep.toString() !== currentMetaStep[maxLevel - level]) {
317
- finishMetastep(level);
318
- currentMetaStep.push(metaStep.toString());
319
- reporter.startStep(metaStep.toString());
320
- }
321
- }
322
-
323
- return plugin;
1
+ module.exports = () => {
2
+ console.log('Allure plugin was moved to @codeceptjs/allure-legacy. Please install it and update your config');
3
+ console.log();
4
+ console.log('npm install @codeceptjs/allure-legacy --save-dev');
5
+ console.log();
6
+ console.log('Then update your config to use it:');
7
+ console.log();
8
+ console.log('plugins: {');
9
+ console.log(' allure: {');
10
+ console.log(' enabled: true,');
11
+ console.log(' require: \'@codeceptjs/allure-legacy\',');
12
+ console.log(' }');
13
+ console.log('}');
14
+ console.log();
324
15
  };
@@ -1,4 +1,4 @@
1
- const faker = require('@faker-js/faker');
1
+ const { faker } = require('@faker-js/faker');
2
2
  const transform = require('../transform');
3
3
 
4
4
  /**
@@ -44,7 +44,7 @@ const transform = require('../transform');
44
44
  module.exports = function (config) {
45
45
  transform.addTransformerBeforeAll('gherkin.examples', (value) => {
46
46
  if (typeof value === 'string' && value.length > 0) {
47
- return faker.fake(value);
47
+ return faker.helpers.fake(value);
48
48
  }
49
49
  return value;
50
50
  });
package/lib/recorder.js CHANGED
@@ -127,7 +127,7 @@ module.exports = {
127
127
  },
128
128
 
129
129
  /**
130
- * @param {string} name
130
+ * @param {string} [name]
131
131
  * @inner
132
132
  */
133
133
  restore(name) {
package/lib/scenario.js CHANGED
@@ -2,7 +2,7 @@ const promiseRetry = require('promise-retry');
2
2
  const event = require('./event');
3
3
  const recorder = require('./recorder');
4
4
  const assertThrown = require('./assert/throws');
5
- const { isAsyncFunction } = require('./utils');
5
+ const { ucfirst, isAsyncFunction } = require('./utils');
6
6
  const parser = require('./parser');
7
7
 
8
8
  const injectHook = function (inject, suite) {
@@ -107,7 +107,7 @@ module.exports.test = (test) => {
107
107
  /**
108
108
  * Injects arguments to function from controller
109
109
  */
110
- module.exports.injected = function (fn, suite, hookName) {
110
+ module.exports.injected = function (fn, suite, hookName) {
111
111
  return function (done) {
112
112
  const errHandler = (err) => {
113
113
  recorder.session.start('teardown');
@@ -125,35 +125,42 @@ module.exports.injected = function (fn, suite, hookName) {
125
125
  if (!fn) throw new Error('fn is not defined');
126
126
 
127
127
  event.emit(event.hook.started, suite);
128
+
129
+ this.test.body = fn.toString();
130
+
128
131
  if (!recorder.isRunning()) {
129
- recorder.start();
130
132
  recorder.errHandler((err) => {
131
133
  errHandler(err);
132
134
  });
133
135
  }
134
136
 
135
- this.test.body = fn.toString();
137
+ const opts = suite.opts || {};
138
+ const retries = opts[`retry${ucfirst(hookName)}`] || 0;
136
139
 
137
- recorder.retry(suite.retries());
138
140
  promiseRetry(async (retry) => {
139
141
  try {
140
- await fn.call(this, getInjectedArguments(fn))
142
+ recorder.startUnlessRunning();
143
+ await fn.call(this, getInjectedArguments(fn));
144
+ await recorder.promise();
141
145
  } catch (err) {
142
146
  retry(err);
147
+ } finally {
148
+ recorder.stop();
149
+ recorder.start();
143
150
  }
144
- }, { retries: suite.retries() })
145
- .then(() => {
146
- recorder.add('fire hook.passed', () => event.emit(event.hook.passed, suite));
147
- recorder.add(`finish ${hookName} hook`, () => done());
148
- recorder.catch();
149
- }).catch((e) => {
150
- recorder.throw(e);
151
- recorder.catch((e) => {
152
- const err = (recorder.getAsyncErr() === null) ? e : recorder.getAsyncErr();
153
- errHandler(err);
151
+ }, { retries })
152
+ .then(() => {
153
+ recorder.add('fire hook.passed', () => event.emit(event.hook.passed, suite));
154
+ recorder.add(`finish ${hookName} hook`, () => done());
155
+ recorder.catch();
156
+ }).catch((e) => {
157
+ recorder.throw(e);
158
+ recorder.catch((e) => {
159
+ const err = (recorder.getAsyncErr() === null) ? e : recorder.getAsyncErr();
160
+ errHandler(err);
161
+ });
162
+ recorder.add('fire hook.failed', () => event.emit(event.hook.failed, suite, e));
154
163
  });
155
- recorder.add('fire hook.failed', () => event.emit(event.hook.failed, suite, e));
156
- });
157
164
  };
158
165
  };
159
166
 
package/lib/utils.js CHANGED
@@ -449,3 +449,9 @@ module.exports.requireWithFallback = function (...packages) {
449
449
 
450
450
  throw new Error(`Cannot find modules ${packages.join(',')}`);
451
451
  };
452
+
453
+ module.exports.isNotSet = function (obj) {
454
+ if (obj === null) return true;
455
+ if (obj === undefined) return true;
456
+ return false;
457
+ };
package/lib/workers.js CHANGED
@@ -1,9 +1,9 @@
1
1
  /* eslint-disable max-classes-per-file */
2
- const { EventEmitter } = require('events');
3
2
  const path = require('path');
4
3
  const mkdirp = require('mkdirp');
5
4
  const { Worker } = require('worker_threads');
6
5
  const { Suite, Test, reporters: { Base } } = require('mocha');
6
+ const { EventEmitter } = require('events');
7
7
  const ms = require('ms');
8
8
  const Codecept = require('./codecept');
9
9
  const MochaFactory = require('./mochaFactory');
@@ -107,8 +107,7 @@ const convertToMochaTests = (testGroup) => {
107
107
  mocha.files = testGroup;
108
108
  mocha.loadFiles();
109
109
  mocha.suite.eachTest((test) => {
110
- const { id } = test;
111
- group.push(id);
110
+ group.push(test.uid);
112
111
  });
113
112
  mocha.unloadFiles();
114
113
  }
@@ -242,8 +241,7 @@ class Workers extends EventEmitter {
242
241
  mocha.suite.eachTest((test) => {
243
242
  const i = groupCounter % groups.length;
244
243
  if (test) {
245
- const { id } = test;
246
- groups[i].push(id);
244
+ groups[i].push(test.uid);
247
245
  groupCounter++;
248
246
  }
249
247
  });
@@ -264,8 +262,7 @@ class Workers extends EventEmitter {
264
262
  const i = indexOfSmallestElement(groups);
265
263
  suite.tests.forEach((test) => {
266
264
  if (test) {
267
- const { id } = test;
268
- groups[i].push(id);
265
+ groups[i].push(test.uid);
269
266
  }
270
267
  });
271
268
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeceptjs",
3
- "version": "3.3.8-beta.1",
3
+ "version": "3.4.0",
4
4
  "description": "Supercharged End 2 End Testing Framework for NodeJS",
5
5
  "keywords": [
6
6
  "acceptance",
@@ -35,7 +35,6 @@
35
35
  },
36
36
  "repository": "Codeception/codeceptjs",
37
37
  "scripts": {
38
- "build": "tsc -p ./",
39
38
  "json-server": "./node_modules/json-server/bin/index.js test/data/rest/db.json -p 8010 --watch -m test/data/rest/headers.js",
40
39
  "json-server:graphql": "node test/data/graphql/index.js",
41
40
  "lint": "eslint bin/ examples/ lib/ test/ translations/ runok.js",
@@ -56,23 +55,23 @@
56
55
  "dependencies": {
57
56
  "@codeceptjs/configure": "^0.8.0",
58
57
  "@codeceptjs/helper": "^1.0.2",
58
+ "@cucumber/cucumber-expressions": "^16",
59
+ "@cucumber/gherkin": "^26",
60
+ "@cucumber/messages": "^21.0.1",
59
61
  "acorn": "^7.4.1",
60
- "allure-js-commons": "^1.3.2",
61
62
  "arrify": "^2.0.1",
62
- "axios": "^0.21.4",
63
+ "axios": "^1.3.3",
63
64
  "chai": "^4.3.6",
64
65
  "chai-deep-match": "^1.2.1",
65
66
  "chalk": "^4.1.2",
66
67
  "commander": "^2.20.3",
67
68
  "cross-spawn": "^7.0.3",
68
69
  "css-to-xpath": "^0.1.0",
69
- "cucumber-expressions": "^6.6.2",
70
70
  "envinfo": "^7.8.1",
71
71
  "escape-string-regexp": "^1.0.3",
72
72
  "figures": "^3.2.0",
73
73
  "fn-args": "^4.0.0",
74
74
  "fs-extra": "^8.1.0",
75
- "gherkin": "^5.1.0",
76
75
  "glob": "^6.0.1",
77
76
  "inquirer": "^6.5.2",
78
77
  "joi": "^17.6.0",
@@ -80,21 +79,19 @@
80
79
  "lodash.clonedeep": "^4.5.0",
81
80
  "lodash.merge": "^4.6.2",
82
81
  "mkdirp": "^1.0.4",
83
- "mocha": "8.1.3",
84
- "mocha-junit-reporter": "1.23.1",
82
+ "mocha": "^8.2.0",
83
+ "mocha-junit-reporter": "^1.23.3",
85
84
  "ms": "^2.1.3",
86
85
  "parse-function": "^5.6.4",
87
86
  "promise-retry": "^1.1.1",
88
- "requireg": "^0.2.2",
89
87
  "resq": "^1.10.2",
90
- "semver": "^6.3.0",
91
88
  "sprintf-js": "^1.1.1",
92
- "uuid": "^8.3.2"
89
+ "uuid": "^9.0"
93
90
  },
94
91
  "devDependencies": {
95
92
  "@codeceptjs/detox-helper": "^1.0.2",
96
93
  "@codeceptjs/mock-request": "^0.3.1",
97
- "@faker-js/faker": "^5.5.3",
94
+ "@faker-js/faker": "^7.6.0",
98
95
  "@pollyjs/adapter-puppeteer": "^5.1.0",
99
96
  "@pollyjs/core": "^5.1.0",
100
97
  "@types/inquirer": "^0.0.35",
@@ -118,10 +115,10 @@
118
115
  "form-data": "^3.0.1",
119
116
  "graphql": "^14.6.0",
120
117
  "husky": "^8.0.1",
118
+ "inquirer-test": "^2.0.1",
121
119
  "jsdoc": "^3.6.10",
122
120
  "jsdoc-typeof-plugin": "^1.0.0",
123
121
  "json-server": "^0.10.1",
124
- "mocha-parallel-tests": "^2.3.0",
125
122
  "nightmare": "^3.0.2",
126
123
  "nodemon": "^1.19.4",
127
124
  "playwright": "^1.23.2",
@@ -131,19 +128,18 @@
131
128
  "runok": "^0.9.2",
132
129
  "sinon": "^9.2.4",
133
130
  "sinon-chai": "^3.7.0",
134
- "testcafe": "^1.18.3",
131
+ "testcafe": "^2.1.0",
135
132
  "ts-morph": "^3.1.3",
136
133
  "ts-node": "^10.9.1",
137
- "tsd-jsdoc": "https://github.com/englercj/tsd-jsdoc.git",
134
+ "tsd-jsdoc": "^2.5.0",
138
135
  "typedoc": "^0.23.10",
139
136
  "typedoc-plugin-markdown": "^3.13.4",
140
137
  "typescript": "^4.8.4",
141
138
  "wdio-docker-service": "^1.5.0",
142
- "webdriverio": "^7.16.14",
139
+ "webdriverio": "^8.3.8",
143
140
  "xml2js": "^0.4.23",
144
141
  "xmldom": "^0.1.31",
145
- "xpath": "0.0.27",
146
- "inquirer-test": "^2.0.1"
142
+ "xpath": "0.0.27"
147
143
  },
148
144
  "engines": {
149
145
  "node": ">=8.9.1",
@@ -17,6 +17,32 @@ declare namespace CodeceptJS {
17
17
  path?: string,
18
18
  };
19
19
 
20
+ type RetryConfig = {
21
+ /** Filter tests by string or regexp pattern */
22
+ grep: string | RegExp;
23
+ /** Number of times to repeat scenarios of a Feature */
24
+ Feature: number;
25
+ /** Number of times to repeat scenarios */
26
+ Scenario: number;
27
+ /** Number of times to repeat Before hook */
28
+ Before: number;
29
+ /** Number of times to repeat After hook */
30
+ After: number;
31
+ /** Number of times to repeat BeforeSuite hook */
32
+ BeforeSuite: number;
33
+ /** Number of times to repeat AfterSuite hook */
34
+ AfterSuite: number;
35
+ };
36
+
37
+ type TimeoutConfig = {
38
+ /** Filter tests by string or regexp pattern */
39
+ grep: string | RegExp;
40
+ /** Set timeout for a scenarios of a Feature */
41
+ Feature: number;
42
+ /** Set timeout for scenarios */
43
+ Scenario: number;
44
+ };
45
+
20
46
  type MainConfig = {
21
47
  /** Pattern to locate CodeceptJS tests.
22
48
  * Allows to enter glob pattern or an Array<string> of patterns to match tests / test file names.
@@ -172,8 +198,57 @@ declare namespace CodeceptJS {
172
198
  * ```js
173
199
  * timeout: 20,
174
200
  * ```
201
+ *
202
+ * Can be customized to use different timeouts for a subset of tests:
203
+ *
204
+ * ```js
205
+ * timeout: [
206
+ * 10,
207
+ * {
208
+ * grep: '@slow',
209
+ * Scenario: 20
210
+ * }
211
+ * ]
212
+ * ```
175
213
  */
176
- timeout?: number;
214
+ timeout?: number | Array<TimeoutConfig> | TimeoutConfig;
215
+
216
+ /**
217
+ * Configure retry strategy for tests
218
+ *
219
+ * To retry all tests 3 times:
220
+ *
221
+ * ```js
222
+ * retry: 3
223
+ * ```
224
+ *
225
+ * To retry only Before hook 3 times:
226
+ *
227
+ * ```js
228
+ * retry: {
229
+ * Before: 3
230
+ * }
231
+ * ```
232
+ *
233
+ * To retry tests marked as flaky 3 times, other 1 time:
234
+ *
235
+ * ```js
236
+ * retry: [
237
+ * {
238
+ * Scenario: 1,
239
+ * Before: 1
240
+ * },
241
+ * {
242
+ * grep: '@flaky',
243
+ * Scenario: 3
244
+ * Before: 3
245
+ * }
246
+ * ]
247
+ * ```
248
+ */
249
+ retry?: number | Array<RetryConfig> | RetryConfig;
250
+
251
+
177
252
  /** Disable registering global functions (Before, Scenario, etc). Not recommended */
178
253
  noGlobals?: boolean;
179
254
  /**