codeceptjs 3.2.2 → 3.3.0-beta.3

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 (64) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/docs/advanced.md +2 -2
  3. package/docs/api.md +227 -188
  4. package/docs/build/ApiDataFactory.js +13 -6
  5. package/docs/build/Appium.js +98 -36
  6. package/docs/build/FileSystem.js +11 -1
  7. package/docs/build/GraphQL.js +11 -0
  8. package/docs/build/JSONResponse.js +297 -0
  9. package/docs/build/Nightmare.js +48 -48
  10. package/docs/build/Playwright.js +271 -151
  11. package/docs/build/Puppeteer.js +76 -67
  12. package/docs/build/REST.js +36 -0
  13. package/docs/build/TestCafe.js +44 -44
  14. package/docs/build/WebDriver.js +69 -69
  15. package/docs/changelog.md +7 -0
  16. package/docs/configuration.md +8 -8
  17. package/docs/custom-helpers.md +1 -1
  18. package/docs/data.md +9 -9
  19. package/docs/helpers/ApiDataFactory.md +7 -0
  20. package/docs/helpers/Appium.md +240 -198
  21. package/docs/helpers/FileSystem.md +11 -1
  22. package/docs/helpers/JSONResponse.md +230 -0
  23. package/docs/helpers/Playwright.md +283 -216
  24. package/docs/helpers/Puppeteer.md +9 -1
  25. package/docs/helpers/REST.md +30 -9
  26. package/docs/installation.md +3 -1
  27. package/docs/internal-api.md +265 -0
  28. package/docs/mobile.md +11 -11
  29. package/docs/nightmare.md +3 -3
  30. package/docs/playwright.md +73 -18
  31. package/docs/plugins.md +136 -36
  32. package/docs/puppeteer.md +28 -12
  33. package/docs/quickstart.md +2 -3
  34. package/docs/reports.md +44 -3
  35. package/docs/testcafe.md +1 -1
  36. package/docs/translation.md +2 -2
  37. package/docs/videos.md +2 -2
  38. package/docs/visual.md +2 -2
  39. package/docs/vue.md +1 -1
  40. package/docs/webdriver.md +92 -4
  41. package/lib/cli.js +25 -20
  42. package/lib/command/init.js +5 -15
  43. package/lib/command/workers/runTests.js +25 -7
  44. package/lib/config.js +17 -13
  45. package/lib/helper/ApiDataFactory.js +13 -6
  46. package/lib/helper/Appium.js +65 -3
  47. package/lib/helper/FileSystem.js +11 -1
  48. package/lib/helper/GraphQL.js +11 -0
  49. package/lib/helper/JSONResponse.js +297 -0
  50. package/lib/helper/Playwright.js +209 -89
  51. package/lib/helper/Puppeteer.js +12 -3
  52. package/lib/helper/REST.js +36 -0
  53. package/lib/helper/extras/Console.js +8 -0
  54. package/lib/helper/extras/PlaywrightRestartOpts.js +35 -0
  55. package/lib/interfaces/bdd.js +3 -1
  56. package/lib/plugin/allure.js +12 -0
  57. package/lib/plugin/autoLogin.js +1 -1
  58. package/lib/plugin/eachElement.js +127 -0
  59. package/lib/plugin/tryTo.js +6 -0
  60. package/lib/utils.js +20 -0
  61. package/package.json +25 -23
  62. package/translations/pt-BR.js +8 -0
  63. package/typings/index.d.ts +4 -0
  64. package/typings/types.d.ts +318 -109
@@ -0,0 +1,35 @@
1
+ const RESTART_OPTS = {
2
+ session: 'keep',
3
+ browser: true,
4
+ context: false,
5
+ };
6
+
7
+ let restarts = null;
8
+
9
+ module.exports = {
10
+
11
+ setRestartStrategy(options) {
12
+ const { restart } = options;
13
+ const stringOpts = Object.keys(RESTART_OPTS);
14
+
15
+ if (stringOpts.includes(restart)) {
16
+ return restarts = restart;
17
+ }
18
+
19
+ restarts = Object.keys(RESTART_OPTS).find(key => RESTART_OPTS[key] === restart);
20
+
21
+ console.log(restarts);
22
+
23
+ if (restarts === null || restarts === undefined) throw new Error('No restart strategy set, use the following values for restart: session, context, browser');
24
+ },
25
+
26
+ restartsSession() {
27
+ return restarts === 'session';
28
+ },
29
+ restartsContext() {
30
+ return restarts === 'context';
31
+ },
32
+ restartsBrowser() {
33
+ return restarts === 'browser';
34
+ },
35
+ };
@@ -25,7 +25,8 @@ const parameterTypeRegistry = new ParameterTypeRegistry();
25
25
  const matchStep = (step) => {
26
26
  for (const stepName in steps) {
27
27
  if (stepName.indexOf('/') === 0) {
28
- const res = step.match(new RegExp(stepName.slice(1, -1)));
28
+ const regExpArr = stepName.match(new RegExp('^/(.*?)/([gimy]*)$')) || [];
29
+ const res = step.match(new RegExp(regExpArr[1], regExpArr[2]));
29
30
  if (res) {
30
31
  const fn = steps[stepName];
31
32
  fn.params = res.slice(1);
@@ -56,6 +57,7 @@ module.exports = {
56
57
  Given: addStep,
57
58
  When: addStep,
58
59
  Then: addStep,
60
+ And: addStep,
59
61
  matchStep,
60
62
  getSteps,
61
63
  clearSteps,
@@ -64,6 +64,18 @@ const defaultConfig = {
64
64
  * * `addAttachment(name, buffer, type)` - add an attachment to current test / suite
65
65
  * * `addLabel(name, value)` - adds a label to current test
66
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)
67
79
  * * `severity(value)` - adds severity label
68
80
  * * `epic(value)` - adds epic label
69
81
  * * `feature(value)` - adds feature label
@@ -37,7 +37,7 @@ const defaultConfig = {
37
37
  * ```js
38
38
  * // inside a test file
39
39
  * // use login to inject auto-login function
40
- * Before(login => {
40
+ * Before(({ login }) => {
41
41
  * login('user'); // login using user session
42
42
  * });
43
43
  *
@@ -0,0 +1,127 @@
1
+ const output = require('../output');
2
+ const store = require('../store');
3
+ const recorder = require('../recorder');
4
+ const container = require('../container');
5
+ const event = require('../event');
6
+ const Step = require('../step');
7
+ const { isAsyncFunction } = require('../utils');
8
+
9
+ const defaultConfig = {
10
+ registerGlobal: true,
11
+ };
12
+
13
+ /**
14
+ * Provides `eachElement` global function to iterate over found elements to perform actions on them.
15
+ *
16
+ * `eachElement` takes following args:
17
+ * * `purpose` - the goal of an action. A comment text that will be displayed in output.
18
+ * * `locator` - a CSS/XPath locator to match elements
19
+ * * `fn(element, index)` - **asynchronous** function which will be executed for each matched element.
20
+ *
21
+ * Example of usage:
22
+ *
23
+ * ```js
24
+ * // this example works with Playwright and Puppeteer helper
25
+ * await eachElement('click all checkboxes', 'form input[type=checkbox]', async (el) => {
26
+ * await el.click();
27
+ * });
28
+ * ```
29
+ * Click odd elements:
30
+ *
31
+ * ```js
32
+ * // this example works with Playwright and Puppeteer helper
33
+ * await eachElement('click odd buttons', '.button-select', async (el, index) => {
34
+ * if (index % 2) await el.click();
35
+ * });
36
+ * ```
37
+ *
38
+ * Check all elements for visibility:
39
+ *
40
+ * ```js
41
+ * // this example works with Playwright and Puppeteer helper
42
+ * const assert = require('assert');
43
+ * await eachElement('check all items are visible', '.item', async (el) => {
44
+ * assert(await el.isVisible());
45
+ * });
46
+ * ```
47
+ * This method works with WebDriver, Playwright, Puppeteer, Appium helpers.
48
+ *
49
+ * Function parameter `el` represents a matched element.
50
+ * Depending on a helper API of `el` can be different. Refer to API of corresponding browser testing engine for a complete API list:
51
+ *
52
+ * * [Playwright ElementHandle](https://playwright.dev/docs/api/class-elementhandle)
53
+ * * [Puppeteer](https://pptr.dev/#?product=Puppeteer&show=api-class-elementhandle)
54
+ * * [webdriverio element](https://webdriver.io/docs/api)
55
+ *
56
+ * #### Configuration
57
+ *
58
+ * * `registerGlobal` - to register `eachElement` function globally, true by default
59
+ *
60
+ * If `registerGlobal` is false you can use eachElement from the plugin:
61
+ *
62
+ * ```js
63
+ * const eachElement = codeceptjs.container.plugins('eachElement');
64
+ * ```
65
+ *
66
+ * @param {string} purpose
67
+ * @param {CodeceptJS.LocatorOrString} locator
68
+ * @param {Function} fn
69
+ * @return {Promise<*> | undefined}
70
+ */
71
+ function eachElement(purpose, locator, fn) {
72
+ if (store.dryRun) return;
73
+ const helpers = Object.values(container.helpers());
74
+
75
+ const helper = helpers.filter(h => !!h._locate)[0];
76
+
77
+ if (!helper) {
78
+ throw new Error('No helper enabled with _locate method with returns a list of elements.');
79
+ }
80
+
81
+ if (!isAsyncFunction(fn)) {
82
+ throw new Error('Async function should be passed into each element');
83
+ }
84
+
85
+ const step = new Step(helper, `${purpose || 'each element'} within "${locator}"`);
86
+ step.helperMethod = '_locate';
87
+ // eachElement('select all users', 'locator', async (el) => {
88
+ event.dispatcher.emit(event.step.before, step);
89
+
90
+ return recorder.add('register each element wrapper', async () => {
91
+ event.emit(event.step.started, step);
92
+ const els = await helper._locate(locator);
93
+ output.debug(`Found ${els.length} elements for each elements to iterate`);
94
+
95
+ const errs = [];
96
+ let i = 0;
97
+ for (const el of els) {
98
+ try {
99
+ await fn(el, i);
100
+ } catch (err) {
101
+ output.error(`eachElement: failed operation on element #${i} ${el}`);
102
+ errs.push(err);
103
+ }
104
+ i++;
105
+ }
106
+
107
+ if (errs.length) {
108
+ event.dispatcher.emit(event.step.after, step);
109
+ event.emit(event.step.failed, step, errs[0]);
110
+ event.emit(event.step.finished, step);
111
+ throw errs[0];
112
+ }
113
+
114
+ event.dispatcher.emit(event.step.after, step);
115
+ event.emit(event.step.passed, step, null);
116
+ event.emit(event.step.finished, step);
117
+ });
118
+ }
119
+
120
+ module.exports = function (config) {
121
+ config = Object.assign(defaultConfig, config);
122
+
123
+ if (config.registerGlobal) {
124
+ global.eachElement = eachElement;
125
+ }
126
+ return eachElement;
127
+ };
@@ -42,6 +42,12 @@ const defaultConfig = {
42
42
  * #### Multiple Conditional Assertions
43
43
  *
44
44
  * ```js
45
+ *
46
+ * Add assert requires first:
47
+ * ```js
48
+ * const assert = require('assert');
49
+ * ```
50
+ * Then use the assert:
45
51
  * const result1 = await tryTo(() => I.see('Hello, user'));
46
52
  * const result2 = await tryTo(() => I.seeElement('.welcome'));
47
53
  * assert.ok(result1 && result2, 'Assertions were not succesful');
package/lib/utils.js CHANGED
@@ -431,3 +431,23 @@ module.exports.modifierKeys = modifierKeys;
431
431
  module.exports.isModifierKey = function (key) {
432
432
  return modifierKeys.includes(key);
433
433
  };
434
+
435
+ module.exports.requireWithFallback = function (...packages) {
436
+ const exists = function (pkg) {
437
+ try {
438
+ require.resolve(pkg);
439
+ } catch (e) {
440
+ return false;
441
+ }
442
+
443
+ return true;
444
+ };
445
+
446
+ for (const pkg of packages) {
447
+ if (exists(pkg)) {
448
+ return require(pkg);
449
+ }
450
+ }
451
+
452
+ throw new Error(`Cannot find modules ${packages.join(',')}`);
453
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeceptjs",
3
- "version": "3.2.2",
3
+ "version": "3.3.0-beta.3",
4
4
  "description": "Supercharged End 2 End Testing Framework for NodeJS",
5
5
  "keywords": [
6
6
  "acceptance",
@@ -53,18 +53,19 @@
53
53
  "dtslint": "dtslint typings --localTs './node_modules/typescript/lib'"
54
54
  },
55
55
  "dependencies": {
56
- "@codeceptjs/configure": "^0.6.2",
56
+ "@codeceptjs/configure": "^0.8.0",
57
57
  "@codeceptjs/helper": "^1.0.2",
58
58
  "acorn": "^7.4.1",
59
59
  "allure-js-commons": "^1.3.2",
60
60
  "arrify": "^2.0.1",
61
- "axios": "^0.21.1",
62
- "chalk": "^4.1.0",
61
+ "axios": "^0.21.4",
62
+ "chai-deep-match": "^1.2.1",
63
+ "chalk": "^4.1.2",
63
64
  "commander": "^2.20.3",
64
65
  "cross-spawn": "^7.0.3",
65
66
  "css-to-xpath": "^0.1.0",
66
67
  "cucumber-expressions": "^6.6.2",
67
- "envinfo": "^7.5.1",
68
+ "envinfo": "^7.8.1",
68
69
  "escape-string-regexp": "^1.0.3",
69
70
  "figures": "^3.2.0",
70
71
  "fn-args": "^4.0.0",
@@ -72,7 +73,8 @@
72
73
  "gherkin": "^5.1.0",
73
74
  "glob": "^6.0.1",
74
75
  "inquirer": "^6.5.2",
75
- "js-beautify": "^1.11.0",
76
+ "joi": "^17.6.0",
77
+ "js-beautify": "^1.14.0",
76
78
  "lodash.clonedeep": "^4.5.0",
77
79
  "lodash.merge": "^4.6.2",
78
80
  "mkdirp": "^1.0.4",
@@ -82,13 +84,13 @@
82
84
  "parse-function": "^5.6.4",
83
85
  "promise-retry": "^1.1.1",
84
86
  "requireg": "^0.2.2",
85
- "resq": "^1.10.0",
87
+ "resq": "^1.10.2",
86
88
  "sprintf-js": "^1.1.1",
87
89
  "uuid": "^8.3.2"
88
90
  },
89
91
  "devDependencies": {
90
92
  "@codeceptjs/detox-helper": "^1.0.2",
91
- "@codeceptjs/mock-request": "^0.3.0",
93
+ "@codeceptjs/mock-request": "^0.3.1",
92
94
  "@pollyjs/adapter-puppeteer": "^5.1.0",
93
95
  "@pollyjs/core": "^5.1.0",
94
96
  "@types/inquirer": "^0.0.35",
@@ -96,44 +98,44 @@
96
98
  "@wdio/sauce-service": "^5.22.5",
97
99
  "@wdio/selenium-standalone-service": "^5.16.10",
98
100
  "@wdio/utils": "^5.23.0",
99
- "apollo-server-express": "^2.19.0",
100
- "chai": "^3.4.1",
101
+ "apollo-server-express": "^2.25.3",
102
+ "chai": "^3.5.0",
101
103
  "chai-as-promised": "^5.2.0",
102
104
  "chai-subset": "^1.6.0",
103
105
  "contributor-faces": "^1.0.3",
104
106
  "documentation": "^12.3.0",
105
107
  "dtslint": "^4.1.6",
106
- "electron": "^12.0.0",
108
+ "electron": "^12.2.3",
107
109
  "eslint": "^6.8.0",
108
110
  "eslint-config-airbnb-base": "^14.2.1",
109
- "eslint-plugin-import": "^2.22.1",
111
+ "eslint-plugin-import": "^2.25.4",
110
112
  "eslint-plugin-mocha": "^6.3.0",
111
113
  "expect": "^26.6.2",
112
- "express": "^4.17.1",
113
- "faker": "^5.5.1",
114
- "form-data": "^3.0.0",
114
+ "express": "^4.17.2",
115
+ "faker": "5.5.3",
116
+ "form-data": "^3.0.1",
115
117
  "graphql": "^14.6.0",
116
- "husky": "^4.3.5",
117
- "jsdoc": "^3.6.6",
118
+ "husky": "^4.3.8",
119
+ "jsdoc": "^3.6.10",
118
120
  "jsdoc-typeof-plugin": "^1.0.0",
119
121
  "json-server": "^0.10.1",
120
122
  "mocha-parallel-tests": "^2.3.0",
121
123
  "nightmare": "^3.0.2",
122
124
  "nodemon": "^1.19.4",
123
- "playwright": "^1.9.1",
124
- "puppeteer": "^10.0.0",
125
+ "playwright": "^1.18.1",
126
+ "puppeteer": "^10.4.0",
125
127
  "qrcode-terminal": "^0.12.0",
126
128
  "rosie": "^1.6.0",
127
129
  "runok": "^0.9.2",
128
130
  "semver": "^6.3.0",
129
- "sinon": "^9.2.2",
130
- "sinon-chai": "^3.5.0",
131
- "testcafe": "^1.9.4",
131
+ "sinon": "^9.2.4",
132
+ "sinon-chai": "^3.7.0",
133
+ "testcafe": "^1.18.3",
132
134
  "ts-morph": "^3.1.3",
133
135
  "tsd-jsdoc": "^2.5.0",
134
136
  "typescript": "^4.4.3",
135
137
  "wdio-docker-service": "^1.5.0",
136
- "webdriverio": "^7.14.1",
138
+ "webdriverio": "^7.16.14",
137
139
  "xml2js": "^0.4.23",
138
140
  "xmldom": "^0.1.31",
139
141
  "xpath": "0.0.27"
@@ -1,5 +1,13 @@
1
1
  module.exports = {
2
2
  I: 'Eu',
3
+ contexts: {
4
+ Feature: 'Funcionalidade',
5
+ Scenario: 'Cenário',
6
+ Before: 'Antes',
7
+ After: 'Depois',
8
+ BeforeSuite: 'AntesDaSuite',
9
+ AfterSuite: 'DepoisDaSuite',
10
+ },
3
11
  actions: {
4
12
  amOutsideAngularApp: 'naoEstouEmAplicacaoAngular',
5
13
  amInsideAngularApp: 'estouNaAplicacaoAngular',
@@ -2,6 +2,8 @@
2
2
  /// <reference path="./types.d.ts" />
3
3
  /// <reference types="webdriverio" />
4
4
  /// <reference path="./Mocha.d.ts" />
5
+ /// <reference types="joi" />
6
+ /// <reference types="playwright" />
5
7
 
6
8
  declare namespace CodeceptJS {
7
9
  type WithTranslation<T> = T &
@@ -10,6 +12,8 @@ declare namespace CodeceptJS {
10
12
  type Cookie = {
11
13
  name: string;
12
14
  value: string;
15
+ domain?: string,
16
+ path?: string,
13
17
  };
14
18
 
15
19
  interface PageScrollPosition {