codeceptjs 3.3.8-beta.1 → 3.4.0-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 (63) 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 +6 -6
  7. package/docs/build/Appium.js +2 -19
  8. package/docs/build/FileSystem.js +2 -2
  9. package/docs/build/GraphQLDataFactory.js +2 -2
  10. package/docs/build/Playwright.js +3 -2
  11. package/docs/build/TestCafe.js +4 -4
  12. package/docs/build/WebDriver.js +29 -164
  13. package/docs/helpers/ApiDataFactory.md +6 -6
  14. package/docs/helpers/FileSystem.md +2 -2
  15. package/docs/helpers/GraphQLDataFactory.md +2 -2
  16. package/docs/helpers/Playwright.md +2 -1
  17. package/docs/index.md +1 -1
  18. package/docs/plugins.md +73 -48
  19. package/docs/reports.md +0 -56
  20. package/docs/typescript.md +2 -8
  21. package/lib/actor.js +2 -1
  22. package/lib/cli.js +3 -3
  23. package/lib/codecept.js +2 -1
  24. package/lib/command/generate.js +3 -1
  25. package/lib/command/gherkin/snippets.js +8 -4
  26. package/lib/command/init.js +0 -8
  27. package/lib/command/run-workers.js +3 -6
  28. package/lib/command/utils.js +0 -10
  29. package/lib/command/workers/runTests.js +2 -2
  30. package/lib/config.js +5 -1
  31. package/lib/helper/ApiDataFactory.js +7 -7
  32. package/lib/helper/Appium.js +2 -19
  33. package/lib/helper/FileSystem.js +3 -3
  34. package/lib/helper/GraphQL.js +1 -1
  35. package/lib/helper/GraphQLDataFactory.js +3 -3
  36. package/lib/helper/JSONResponse.js +1 -1
  37. package/lib/helper/Mochawesome.js +1 -1
  38. package/lib/helper/Nightmare.js +1 -1
  39. package/lib/helper/Playwright.js +4 -3
  40. package/lib/helper/Protractor.js +1 -1
  41. package/lib/helper/Puppeteer.js +1 -1
  42. package/lib/helper/REST.js +1 -1
  43. package/lib/helper/TestCafe.js +5 -5
  44. package/lib/helper/WebDriver.js +30 -165
  45. package/lib/helper.js +0 -2
  46. package/lib/interfaces/bdd.js +1 -1
  47. package/lib/interfaces/featureConfig.js +1 -0
  48. package/lib/interfaces/gherkin.js +38 -25
  49. package/lib/listener/exit.js +2 -2
  50. package/lib/listener/retry.js +67 -0
  51. package/lib/listener/steps.js +1 -1
  52. package/lib/listener/timeout.js +47 -10
  53. package/lib/mochaFactory.js +3 -3
  54. package/lib/plugin/allure.js +14 -323
  55. package/lib/plugin/fakerTransform.js +2 -2
  56. package/lib/recorder.js +1 -1
  57. package/lib/scenario.js +25 -18
  58. package/lib/utils.js +6 -0
  59. package/lib/workers.js +4 -7
  60. package/package.json +13 -17
  61. package/typings/index.d.ts +66 -1
  62. package/typings/promiseBasedTypes.d.ts +12 -12
  63. package/typings/types.d.ts +95 -262
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-beta.1",
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,7 +128,7 @@
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
134
  "tsd-jsdoc": "https://github.com/englercj/tsd-jsdoc.git",
@@ -139,11 +136,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,22 @@ declare namespace CodeceptJS {
17
17
  path?: string,
18
18
  };
19
19
 
20
+ type RetryConfig = {
21
+ grep: string;
22
+ Feature: number;
23
+ Scenario: number;
24
+ Before: number;
25
+ After: number;
26
+ BeforeSuite: number;
27
+ AfterSuite: number;
28
+ };
29
+
30
+ type TimeoutConfig = {
31
+ grep: string;
32
+ Feature: number;
33
+ Scenario: number;
34
+ };
35
+
20
36
  type MainConfig = {
21
37
  /** Pattern to locate CodeceptJS tests.
22
38
  * Allows to enter glob pattern or an Array<string> of patterns to match tests / test file names.
@@ -172,8 +188,57 @@ declare namespace CodeceptJS {
172
188
  * ```js
173
189
  * timeout: 20,
174
190
  * ```
191
+ *
192
+ * Can be customized to use different timeouts for a subset of tests:
193
+ *
194
+ * ```js
195
+ * timeout: [
196
+ * 10,
197
+ * {
198
+ * grep: '@slow',
199
+ * Scenario: 20
200
+ * }
201
+ * ]
202
+ * ```
175
203
  */
176
- timeout?: number;
204
+ timeout?: number | Array<TimeoutConfig> | TimeoutConfig;
205
+
206
+ /**
207
+ * Configure retry strategy for tests
208
+ *
209
+ * To retry all tests 3 times:
210
+ *
211
+ * ```js
212
+ * retry: 3
213
+ * ```
214
+ *
215
+ * To retry only Before hook 3 times:
216
+ *
217
+ * ```js
218
+ * retry: {
219
+ * Before: 3
220
+ * }
221
+ * ```
222
+ *
223
+ * To retry tests marked as flaky 3 times, other 1 time:
224
+ *
225
+ * ```js
226
+ * retry: [
227
+ * {
228
+ * Scenario: 1,
229
+ * Before: 1
230
+ * },
231
+ * {
232
+ * grep: '@flaky',
233
+ * Scenario: 3
234
+ * Before: 3
235
+ * }
236
+ * ]
237
+ * ```
238
+ */
239
+ retry?: number | Array<RetryConfig> | RetryConfig;
240
+
241
+
177
242
  /** Disable registering global functions (Before, Scenario, etc). Not recommended */
178
243
  noGlobals?: boolean;
179
244
  /**
@@ -42,8 +42,8 @@ declare namespace CodeceptJS {
42
42
  * ```js
43
43
  * // tests/factories/posts.js
44
44
  *
45
- * const Factory = require('rosie').Factory;
46
- * const faker = require('@faker-js/faker');
45
+ * const { Factory } = require('rosie');
46
+ * const { faker } = require('@faker-js/faker');
47
47
  *
48
48
  * module.exports = new Factory()
49
49
  * // no need to set id, it will be set by REST API
@@ -190,10 +190,10 @@ declare namespace CodeceptJS {
190
190
  * I.have('user', { }, { age: 33, height: 55 })
191
191
  * ```
192
192
  * @param factory - factory to use
193
- * @param params - predefined parameters
194
- * @param options - options for programmatically generate the attributes
193
+ * @param [params] - predefined parameters
194
+ * @param [options] - options for programmatically generate the attributes
195
195
  */
196
- have(factory: any, params: any, options: any): Promise<any>;
196
+ have(factory: any, params?: any, options?: any): Promise<any>;
197
197
  /**
198
198
  * Generates bunch of records and saves multiple API requests to store them.
199
199
  *
@@ -208,7 +208,7 @@ declare namespace CodeceptJS {
208
208
  * I.haveMultiple('post', 3, { author: 'davert' }, { publish_date: '01.01.1997' });
209
209
  * ```
210
210
  */
211
- haveMultiple(factory: any, times: any, params: any, options: any): Promise<any>;
211
+ haveMultiple(factory: any, times: any, params?: any, options?: any): Promise<any>;
212
212
  /**
213
213
  * Executes request to create a record in API.
214
214
  * Can be replaced from a in custom helper.
@@ -1153,10 +1153,10 @@ declare namespace CodeceptJS {
1153
1153
  */
1154
1154
  seeFile(name: string): Promise<any>;
1155
1155
  /**
1156
- * Waits for file to be present in current directory.
1156
+ * Waits for the file to be present in the current directory.
1157
1157
  *
1158
1158
  * ```js
1159
- * I.handleDownloads();
1159
+ * I.handleDownloads('downloads/largeFilesName.txt');
1160
1160
  * I.click('Download large File');
1161
1161
  * I.amInPath('output/downloads');
1162
1162
  * I.waitForFile('largeFilesName.txt', 10); // wait 10 seconds for file
@@ -1337,8 +1337,8 @@ declare namespace CodeceptJS {
1337
1337
  * ```js
1338
1338
  * // tests/factories/users.js
1339
1339
  *
1340
- * const Factory = require('rosie').Factory;
1341
- * const faker = require('@faker-js/faker');
1340
+ * const { Factory } = require('rosie').Factory;
1341
+ * const { faker } = require('@faker-js/faker');
1342
1342
  *
1343
1343
  * // Used with a constructor function passed to Factory, so that the final build
1344
1344
  * // object matches the necessary pattern to be sent as the variables object.
@@ -3271,9 +3271,9 @@ declare namespace CodeceptJS {
3271
3271
  * I.waitForFile('avatar.jpg', 5);
3272
3272
  *
3273
3273
  * ```
3274
- * @param [fileName] - set filename for downloaded file
3274
+ * @param fileName - set filename for downloaded file
3275
3275
  */
3276
- handleDownloads(fileName?: string): Promise<void>;
3276
+ handleDownloads(fileName: string): Promise<void>;
3277
3277
  /**
3278
3278
  * Perform a click on a link or a button, given by a locator.
3279
3279
  * If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string.