codeceptjs 2.4.3 → 2.6.2

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 (76) hide show
  1. package/CHANGELOG.md +117 -0
  2. package/README.md +32 -7
  3. package/bin/codecept.js +3 -0
  4. package/docs/basics.md +11 -5
  5. package/docs/bdd.md +4 -4
  6. package/docs/build/MockRequest.js +3 -0
  7. package/docs/build/Nightmare.js +10 -2
  8. package/docs/build/Playwright.js +3187 -0
  9. package/docs/build/Protractor.js +16 -2
  10. package/docs/build/Puppeteer.js +126 -19
  11. package/docs/build/REST.js +3 -1
  12. package/docs/build/TestCafe.js +11 -3
  13. package/docs/build/WebDriver.js +361 -28
  14. package/docs/changelog.md +116 -0
  15. package/docs/configuration.md +2 -2
  16. package/docs/custom-helpers.md +55 -10
  17. package/docs/helpers/Appium.md +81 -1
  18. package/docs/helpers/MockRequest.md +281 -38
  19. package/docs/helpers/Nightmare.md +10 -2
  20. package/docs/helpers/Playwright.md +1770 -0
  21. package/docs/helpers/Protractor.md +15 -3
  22. package/docs/helpers/Puppeteer-firefox.md +32 -1
  23. package/docs/helpers/Puppeteer.md +126 -76
  24. package/docs/helpers/TestCafe.md +10 -2
  25. package/docs/helpers/WebDriver.md +208 -118
  26. package/docs/locators.md +2 -0
  27. package/docs/playwright.md +306 -0
  28. package/docs/plugins.md +103 -0
  29. package/docs/reports.md +12 -0
  30. package/docs/shadow.md +68 -0
  31. package/docs/visual.md +0 -73
  32. package/docs/webapi/forceClick.mustache +27 -0
  33. package/docs/webapi/seeInPopup.mustache +7 -0
  34. package/docs/webapi/setCookie.mustache +10 -2
  35. package/docs/webapi/type.mustache +12 -0
  36. package/docs/webdriver.md +7 -3
  37. package/lib/codecept.js +1 -1
  38. package/lib/command/definitions.js +2 -2
  39. package/lib/command/generate.js +4 -4
  40. package/lib/command/gherkin/snippets.js +4 -4
  41. package/lib/command/init.js +1 -1
  42. package/lib/command/interactive.js +3 -0
  43. package/lib/command/run-multiple.js +2 -2
  44. package/lib/command/run-rerun.js +2 -0
  45. package/lib/command/run-workers.js +22 -8
  46. package/lib/command/run.js +2 -0
  47. package/lib/command/workers/runTests.js +1 -0
  48. package/lib/container.js +1 -1
  49. package/lib/event.js +2 -0
  50. package/lib/helper/MockRequest.js +3 -0
  51. package/lib/helper/Playwright.js +2422 -0
  52. package/lib/helper/Protractor.js +1 -2
  53. package/lib/helper/Puppeteer.js +84 -19
  54. package/lib/helper/REST.js +3 -1
  55. package/lib/helper/TestCafe.js +1 -1
  56. package/lib/helper/WebDriver.js +313 -26
  57. package/lib/helper/extras/PlaywrightPropEngine.js +53 -0
  58. package/lib/helper/scripts/isElementClickable.js +54 -14
  59. package/lib/interfaces/gherkin.js +1 -1
  60. package/lib/listener/helpers.js +3 -0
  61. package/lib/locator.js +5 -0
  62. package/lib/mochaFactory.js +12 -10
  63. package/lib/plugin/allure.js +8 -1
  64. package/lib/plugin/autoDelay.js +1 -8
  65. package/lib/plugin/commentStep.js +133 -0
  66. package/lib/plugin/screenshotOnFail.js +3 -10
  67. package/lib/plugin/selenoid.js +2 -2
  68. package/lib/plugin/standardActingHelpers.js +13 -0
  69. package/lib/plugin/stepByStepReport.js +1 -8
  70. package/lib/plugin/wdio.js +10 -1
  71. package/lib/reporter/cli.js +30 -1
  72. package/lib/session.js +7 -4
  73. package/package.json +13 -10
  74. package/typings/Mocha.d.ts +567 -16
  75. package/typings/index.d.ts +9 -5
  76. package/typings/types.d.ts +1634 -74
package/docs/webdriver.md CHANGED
@@ -53,6 +53,8 @@ exports.config = {
53
53
  }
54
54
  ```
55
55
 
56
+ > ⚠ It is not recommended to use wdio plugin & selenium-standalone when running tests in parallel. Consider **switching to Selenoid** if you need parallel run or using cloud services.
57
+
56
58
 
57
59
  ## Configuring WebDriver
58
60
 
@@ -104,7 +106,7 @@ path: '/',
104
106
 
105
107
  > If you face issues connecting to WebDriver, please check that corresponding server is running on a specified port. If host is other than `localhost` or port is other than `4444`, update the configuration.
106
108
 
107
- ### Selenium in Docker
109
+ ### Selenium in Docker (Selenoid)
108
110
 
109
111
  Browsers can be executed in Docker containers. This is useful when testing on Continous Integration server.
110
112
  We recommend using [Selenoid](https://aerokube.com/selenoid/) to run browsers in container.
@@ -204,7 +206,7 @@ Scenario('login test', (I) => {
204
206
  > ▶ Actions like `amOnPage`, `click`, `fillField` are not limited to WebDriver only. They work similarly for all available helpers. [Go to Basics guide to learn them](/basics#writing-tests).
205
207
 
206
208
 
207
- An empty test case can be created with `codeceptjs gt` command.
209
+ An empty test case can be created with `npx codeceptjs gt` command.
208
210
 
209
211
  ```
210
212
  npx codeceptjs gt
@@ -223,7 +225,7 @@ Scenario('open my website', (I) => {
223
225
 
224
226
  This is just enough to run a test, open a browser, and think what to do next to write a test case.
225
227
 
226
- When you execute such test with `codeceptjs run` command you may see the browser is started
228
+ When you execute such test with `npx codeceptjs run` command you may see the browser is started
227
229
 
228
230
  ```
229
231
  npx codeceptjs run --steps
@@ -264,6 +266,8 @@ Scenario('create todo item', (I) => {
264
266
 
265
267
  > [▶ Working example of CodeceptJS WebDriver tests](https://github.com/DavertMik/codeceptjs-webdriver-example) for TodoMVC application.
266
268
 
269
+ WebDriver helper supports standard [CSS/XPath and text locators](/locators) as well as non-trivial [React locators](/react) and [Shadow DOM](/shadow).
270
+
267
271
  ## Waiting
268
272
 
269
273
  Web applications do not always respond instantly. That's why WebDriver protocol has methods to wait for changes on a page. CodeceptJS provides such commands prefixed with `wait*` so you could explicitly define what effects we wait for.
package/lib/codecept.js CHANGED
@@ -6,7 +6,7 @@ const resolve = require('path').resolve;
6
6
 
7
7
  const container = require('./container');
8
8
  const Config = require('./config');
9
- const event = require('../lib/event');
9
+ const event = require('./event');
10
10
  const runHook = require('./hooks');
11
11
  const output = require('./output');
12
12
 
@@ -93,8 +93,8 @@ function getPath(originalPath, targetFolderPath, testsPath) {
93
93
  if (parsedPath.base.endsWith('.d.ts')) parsedPath.base = parsedPath.base.substring(0, parsedPath.base.length - 5);
94
94
  else if (parsedPath.ext === '.ts') parsedPath.base = parsedPath.name;
95
95
 
96
- if (!parsedPath.dir.startsWith('.')) return path.join(parsedPath.dir, parsedPath.base);
97
- const relativePath = path.relative(targetFolderPath, path.join(testsPath, parsedPath.dir, parsedPath.base));
96
+ if (!parsedPath.dir.startsWith('.')) return path.posix.join(parsedPath.dir, parsedPath.base);
97
+ const relativePath = path.posix.relative(targetFolderPath, path.posix.join(testsPath, parsedPath.dir, parsedPath.base));
98
98
 
99
99
  return relativePath.startsWith('.') ? relativePath : `./${relativePath}`;
100
100
  }
@@ -26,20 +26,20 @@ module.exports.test = function (genPath) {
26
26
  output.print('Creating a new test...');
27
27
  output.print('----------------------');
28
28
 
29
- const defaultExt = config.tests.match(/([^\*/]*?)$/[1])[0] || '_test.js';
29
+ const defaultExt = config.tests.match(/([^\*/]*?)$/)[1] || '_test.js';
30
30
 
31
31
  return inquirer.prompt([
32
32
  {
33
33
  type: 'input',
34
34
  name: 'feature',
35
- message: 'Feature which is being tested',
35
+ message: 'Feature which is being tested (ex: account, login, etc)',
36
36
  },
37
37
  {
38
38
  type: 'input',
39
39
  message: 'Filename of a test',
40
40
  name: 'filename',
41
41
  default(answers) {
42
- return (answers.feature).replace(' ', '_').toLowerCase() + defaultExt;
42
+ return (answers.feature).replace(' ', '_') + defaultExt;
43
43
  },
44
44
  },
45
45
  ]).then((result) => {
@@ -60,7 +60,7 @@ module.exports.test = function (genPath) {
60
60
  testContent = testContent.replace('{{actor}}', 'I');
61
61
 
62
62
  if (!safeFileWrite(testFile, testContent)) return;
63
- output.success(`Test for ${result.filename} was created in ${testFile}`);
63
+ output.success(`\nTest for ${result.filename} was created in ${testFile}`);
64
64
  });
65
65
  };
66
66
 
@@ -49,7 +49,7 @@ module.exports = function (genPath, options) {
49
49
  });
50
50
  output.print(`Loaded ${files.length} files`);
51
51
 
52
- let newSteps = [];
52
+ const newSteps = new Map();
53
53
 
54
54
  const parseSteps = (steps) => {
55
55
  const newSteps = [];
@@ -88,9 +88,9 @@ module.exports = function (genPath, options) {
88
88
  const ast = parser.parse(fs.readFileSync(file).toString());
89
89
  for (const child of ast.feature.children) {
90
90
  if (child.type === 'ScenarioOutline') continue; // skip scenario outline
91
- newSteps = newSteps.concat(parseSteps(child.steps).map((step) => {
91
+ parseSteps(child.steps).map((step) => {
92
92
  return Object.assign(step, { file: file.replace(global.codecept_dir, '').slice(1) });
93
- }));
93
+ }).map((step) => newSteps.set(`${step.type}(${step})`, step));
94
94
  }
95
95
  };
96
96
 
@@ -106,7 +106,7 @@ module.exports = function (genPath, options) {
106
106
  stepFile = fsPath.join(global.codecept_dir, stepFile);
107
107
  }
108
108
 
109
- const snippets = newSteps
109
+ const snippets = [...newSteps.values()]
110
110
  .filter((value, index, self) => self.indexOf(value) === index)
111
111
  .map((step) => {
112
112
  return `
@@ -21,7 +21,7 @@ const defaultConfig = {
21
21
  mocha: {},
22
22
  };
23
23
 
24
- const helpers = ['WebDriver', 'Puppeteer', 'TestCafe', 'Protractor', 'Nightmare', 'Appium'];
24
+ const helpers = ['WebDriver', 'Puppeteer', 'TestCafe', 'Protractor', 'Nightmare', 'Appium', 'Playwright'];
25
25
  const translations = Object.keys(require('../../translations'));
26
26
 
27
27
  const noTranslation = 'English (no localization)';
@@ -6,7 +6,9 @@ const event = require('../event');
6
6
  const output = require('../output');
7
7
 
8
8
  module.exports = function (path, options) {
9
+ // Backward compatibility for --profile
9
10
  process.profile = options.profile;
11
+ process.env.profile = options.profile;
10
12
 
11
13
  const testsPath = getTestRoot(path);
12
14
  const config = getConfig(testsPath);
@@ -33,6 +35,7 @@ module.exports = function (path, options) {
33
35
  require('../pause')();
34
36
  recorder.add(() => event.emit(event.test.after));
35
37
  recorder.add(() => event.emit(event.suite.after, {}));
38
+ recorder.add(() => event.emit(event.all.result, {}));
36
39
  recorder.add(() => codecept.teardown());
37
40
  });
38
41
  };
@@ -14,7 +14,7 @@ const {
14
14
  const runner = path.join(__dirname, '/../../bin/codecept');
15
15
  let config;
16
16
  const childOpts = {};
17
- const copyOptions = ['override', 'steps', 'reporter', 'verbose', 'config', 'reporter-options', 'grep', 'fgrep', 'invert', 'debug', 'plugins'];
17
+ const copyOptions = ['override', 'steps', 'reporter', 'verbose', 'config', 'reporter-options', 'grep', 'fgrep', 'invert', 'debug', 'plugins', 'colors'];
18
18
  let overrides = {};
19
19
 
20
20
  // codeceptjs run-multiple smoke:chrome regression:firefox - will launch smoke run in chrome and regression in firefox
@@ -29,7 +29,7 @@ let processesDone;
29
29
 
30
30
  module.exports = function (selectedRuns, options) {
31
31
  // registering options globally to use in config
32
- process.profile = options.profile;
32
+ process.env.profile = options.profile;
33
33
  const configFile = options.config;
34
34
  let codecept;
35
35
 
@@ -7,7 +7,9 @@ const Codecept = require('../rerun');
7
7
 
8
8
  module.exports = function (test, options) {
9
9
  // registering options globally to use in config
10
+ // Backward compatibility for --profile
10
11
  process.profile = options.profile;
12
+ process.env.profile = options.profile;
11
13
  const configFile = options.config;
12
14
  let codecept;
13
15
 
@@ -32,7 +32,7 @@ module.exports = function (workers, options) {
32
32
  'Required minimum Node version of 11.7.0 to work with "run-workers"',
33
33
  );
34
34
 
35
- process.profile = options.profile;
35
+ process.env.profile = options.profile;
36
36
 
37
37
  const { Worker } = require('worker_threads');
38
38
 
@@ -46,6 +46,12 @@ module.exports = function (workers, options) {
46
46
  ...overrideConfigs,
47
47
  };
48
48
 
49
+ const configRerun = config.rerun || {};
50
+ let maxReruns = configRerun.maxReruns || 1;
51
+ if (maxReruns > 1) {
52
+ maxReruns *= numberOfWorkers;
53
+ }
54
+
49
55
  const testRoot = getTestRoot(configPath);
50
56
 
51
57
  const codecept = new Codecept(config, options);
@@ -95,11 +101,12 @@ module.exports = function (workers, options) {
95
101
 
96
102
  switch (message.event) {
97
103
  case event.test.failed:
98
- updateFinishedTests(repackTest(message.data));
99
104
  output.test.failed(repackTest(message.data));
105
+ updateFinishedTests(repackTest(message.data), maxReruns);
100
106
  break;
101
- case event.test.passed: output.test.passed(repackTest(message.data));
102
- updateFinishedTests(repackTest(message.data));
107
+ case event.test.passed:
108
+ output.test.passed(repackTest(message.data));
109
+ updateFinishedTests(repackTest(message.data), maxReruns);
103
110
  break;
104
111
  case event.suite.before: output.suite.started(message.data); break;
105
112
  case event.all.after: appendStats(message.data); break;
@@ -223,11 +230,18 @@ function simplifyObject(object) {
223
230
  }, {});
224
231
  }
225
232
 
226
- const updateFinishedTests = (test) => {
233
+ const updateFinishedTests = (test, maxReruns) => {
227
234
  const { id } = test;
228
235
  if (finishedTests[id]) {
229
- const stats = { passes: 0, failures: -1, tests: 0 };
230
- appendStats(stats);
236
+ if (finishedTests[id].runs <= maxReruns) {
237
+ finishedTests[id].runs++;
238
+ }
239
+ if (test.retries !== -1) {
240
+ const stats = { passes: 0, failures: -1, tests: 0 };
241
+ appendStats(stats);
242
+ }
243
+ } else {
244
+ finishedTests[id] = test;
245
+ finishedTests[id].runs = 1;
231
246
  }
232
- finishedTests[id] = test;
233
247
  };
@@ -10,7 +10,9 @@ const Codecept = require('../codecept');
10
10
 
11
11
  module.exports = function (test, options) {
12
12
  // registering options globally to use in config
13
+ // Backward compatibility for --profile
13
14
  process.profile = options.profile;
15
+ process.env.profile = options.profile;
14
16
  const configFile = options.config;
15
17
  let codecept;
16
18
 
@@ -80,6 +80,7 @@ function initializeListeners() {
80
80
  return {
81
81
  id: test.id,
82
82
  workerIndex,
83
+ retries: test._retries,
83
84
  title: test.title,
84
85
  status: test.status,
85
86
  duration: test.duration || 0,
package/lib/container.js CHANGED
@@ -99,7 +99,7 @@ class Container {
99
99
  * Get Mocha instance
100
100
  *
101
101
  * @api
102
- * @returns {Mocha | {}}
102
+ * @returns { * }
103
103
  */
104
104
  static mocha() {
105
105
  return container.mocha;
package/lib/event.js CHANGED
@@ -24,6 +24,7 @@ module.exports = {
24
24
  * @property {'test.passed'} passed
25
25
  * @property {'test.failed'} failed
26
26
  * @property {'test.finish'} finished
27
+ * @property {'test.skipped'} skipped
27
28
  */
28
29
  test: {
29
30
  started: 'test.start', // sync
@@ -32,6 +33,7 @@ module.exports = {
32
33
  passed: 'test.passed', // sync
33
34
  failed: 'test.failed', // sync
34
35
  finished: 'test.finish', // sync
36
+ skipped: 'test.skipped', // sync
35
37
  },
36
38
  /**
37
39
  * @type {object}
@@ -57,6 +57,9 @@ let PollyJS;
57
57
  */
58
58
  class MockRequest extends Helper {
59
59
  constructor(config) {
60
+ console.log('DEPRECATION NOTICE:');
61
+ console.log('MockRequest helper was moved to a standalone package: https://github.com/codecept-js/mock-request');
62
+ console.log('Disable MockRequest in config & install @codeceptjs/mock-request package\n');
60
63
  super(config);
61
64
  this._setConfig(config);
62
65
  PollyJS = requireg('@pollyjs/core').Polly;