codeceptjs 2.6.1 → 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.
package/docs/reports.md CHANGED
@@ -199,6 +199,18 @@ Allure reports can also be generated for `dry-run` command. So you can get the f
199
199
  npx codeceptjs dry-run --debug -p allure
200
200
  ```
201
201
 
202
+ ## ReportPortal
203
+
204
+ Allure is a great reportin tool, however, if you are running tests on different machines it is hard to merge its XML result files to build a proper report. So, for enterprise grade reporting we recommend using [ReportPortal](https://reportportal.io).
205
+
206
+ ![](https://camo.githubusercontent.com/6550c0365f1d0ce1e29c53f1860b12957d1fc529/68747470733a2f2f692e6962622e636f2f516d353247306e2f53637265656e73686f742d323031392d30342d31312d61742d31352d35372d34302e706e67)
207
+
208
+ [ReportPortal](https://reportportal.io) is open-source self-hosted service for aggregating test execution reports.
209
+ Think of it as Kibana but for test reports.
210
+
211
+ Use official [CodeceptJS Agent for ReportPortal](https://github.com/reportportal/agent-js-codecept/) to start publishing your test results.
212
+
213
+
202
214
  ## XML
203
215
 
204
216
  Use default xunit reporter of Mocha to print xml reports. Provide `--reporter xunit` to get the report to screen.
package/docs/visual.md CHANGED
@@ -112,79 +112,6 @@ MisMatch Percentage Calculated is 2.85
112
112
  1) `seeVisualDiff` which can be used to compare two images and calculate the misMatch percentage.
113
113
  2) `seeVisualDiffForElement` which can be used to compare elements on the two images and calculate misMatch percentage.
114
114
 
115
- ## Using Visual Knight
116
-
117
- Visual Knight is a SaaS product which strongly supports CodeceptJS with multiple use cases. It provides an user interface to handle mismatches, statistics and more. It was designed to support Designer, Product Owner and other roles which are not familiar with coding and all this tools. All captured images are saved in a secure cloud system to not mess up your git repository.
118
-
119
- ### Setup
120
-
121
- Create an account at [Visual Knight](https://www.visual-knight.io) and install the npm package
122
-
123
- ```
124
- npm install @visual-knight/codeceptjs -D
125
- ```
126
-
127
- ### Configuring
128
-
129
- ```json
130
- {
131
- "helpers": {
132
- "VisualKnight": {
133
- "require": "@visual-knight/codeceptjs",
134
- "key": "YOUR_API_KEY",
135
- "project": "YOUR_PROJECT_ID OR PROJECT_NAME"
136
- }
137
- }
138
- }
139
- ```
140
-
141
- ### Usage
142
-
143
- ```javascript
144
- /**
145
- * @param testName {string} Is provided to visual knight (must be unique)
146
- * @param options {ScreenshotOptions} Contains additional settings
147
- */
148
- I.compareFullpageScreenshot(testName, options)
149
- /**
150
- * @param testName {string} Is provided to visual knight (must be unique)
151
- * @param options {ScreenshotOptions} Contains additional settings
152
- */
153
- I.compareViewportScreenshot(testName, options)
154
- /**
155
- * @param cssSelector {string} Is provided to visual knight
156
- * @param testName {string} Is provided to visual knight (must be unique)
157
- * @param options {ScreenshotOptions} Contains additional settings
158
- */
159
- I.compareElementScreenshot(cssSelector, testName, options)
160
-
161
- /*
162
- ScreenshotOptions {
163
- hide?: string[] // Array of css selectors which gets hidden by "opacity: 0",
164
- remove?: string[] // Array of css selectors which gets hidden by "display: none",
165
- additional?: object // Data is saved as relation to the variation. (Future: can be used for filtering)
166
- }
167
- */
168
- ```
169
-
170
- > You can find the latest documentation here [CodeceptJS helper page](https://doc.visual-knight.io/adapters/codeceptjs)
171
-
172
- ### Example
173
-
174
- Lets consider visual testing for [CodeceptJS Home](http://codecept.io)
175
-
176
- ```js
177
- Feature('To test screen comparison with Visual Knight Example test');
178
-
179
- Scenario('Compare CodeceptIO Home Page @visual-test', async (I, adminPage) => {
180
- I.amOnPage("/");
181
- I.compareFullpageScreenshot("CodeceptIO Home Page")
182
- });
183
- ```
184
-
185
- Depending of your configuration this test will fail if no baseline exists and log the link to the image to accept or automatically accept the first run as baseline.
186
- > You can accept the first image as baseline automatically via ```autoBaseline: true``` _default is false_
187
-
188
115
  ## Using Applitools
189
116
 
190
117
  Applitools helps Test Automation engineers, DevOps, and FrontEnd Developers continuously test and validate visually perfect mobile, web, and native apps. Now it can be used with CodeceptJS.
@@ -0,0 +1,27 @@
1
+ Perform an emulated click on a link or a button, given by a locator.
2
+ Unlike normal click instead of sending native event, emulates a click with JavaScript.
3
+ This works on hidden, animated or inactive elements as well.
4
+
5
+ If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string.
6
+ For buttons, the "value" attribute, "name" attribute, and inner text are searched. For links, the link text is searched.
7
+ For images, the "alt" attribute and inner text of any parent links are searched.
8
+
9
+ The second parameter is a context (CSS or XPath locator) to narrow the search.
10
+
11
+ ```js
12
+ // simple link
13
+ I.forceClick('Logout');
14
+ // button of form
15
+ I.forceClick('Submit');
16
+ // CSS button
17
+ I.forceClick('#form input[type=submit]');
18
+ // XPath
19
+ I.forceClick('//form/*[@type=submit]');
20
+ // link in context
21
+ I.forceClick('Logout', '#nav');
22
+ // using strict locator
23
+ I.forceClick({css: 'nav a.login'});
24
+ ```
25
+
26
+ @param {CodeceptJS.LocatorOrString} locator clickable link or button located by text, or any element located by CSS|XPath|strict locator.
27
+ @param {?CodeceptJS.LocatorOrString} [context=null] (optional, `null` by default) element to search in CSS|XPath|Strict locator.
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.
@@ -101,10 +101,11 @@ module.exports = function (workers, options) {
101
101
 
102
102
  switch (message.event) {
103
103
  case event.test.failed:
104
- updateFinishedTests(repackTest(message.data), maxReruns);
105
104
  output.test.failed(repackTest(message.data));
105
+ updateFinishedTests(repackTest(message.data), maxReruns);
106
106
  break;
107
- case event.test.passed: output.test.passed(repackTest(message.data));
107
+ case event.test.passed:
108
+ output.test.passed(repackTest(message.data));
108
109
  updateFinishedTests(repackTest(message.data), maxReruns);
109
110
  break;
110
111
  case event.suite.before: output.suite.started(message.data); break;
@@ -232,11 +233,13 @@ function simplifyObject(object) {
232
233
  const updateFinishedTests = (test, maxReruns) => {
233
234
  const { id } = test;
234
235
  if (finishedTests[id]) {
235
- const stats = { passes: 0, failures: -1, tests: 0 };
236
236
  if (finishedTests[id].runs <= maxReruns) {
237
237
  finishedTests[id].runs++;
238
238
  }
239
- appendStats(stats);
239
+ if (test.retries !== -1) {
240
+ const stats = { passes: 0, failures: -1, tests: 0 };
241
+ appendStats(stats);
242
+ }
240
243
  } else {
241
244
  finishedTests[id] = test;
242
245
  finishedTests[id].runs = 1;
@@ -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/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}
@@ -1,5 +1,7 @@
1
1
  const requireg = require('requireg');
2
2
  const path = require('path');
3
+ const fs = require('fs');
4
+ const fsExtra = require('fs-extra');
3
5
 
4
6
  const Helper = require('../helper');
5
7
  const Locator = require('../locator');
@@ -69,7 +71,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
69
71
  * * `keepBrowserState`: (optional, default: false) - keep browser state between tests when `restart` is set to false.
70
72
  * * `keepCookies`: (optional, default: false) - keep cookies between tests when `restart` is set to false.
71
73
  * * `waitForAction`: (optional) how long to wait after click, doubleClick or PressKey actions in ms. Default: 100.
72
- * * `waitForNavigation`: (optional, default: 'load'). When to consider navigation succeeded. Possible options: `load`, `domcontentloaded`, `networkidle0`, `networkidle2`. See [Playwright API](https://github.com/GoogleChrome/Playwright/blob/master/docs/api.md#pagewaitfornavigationoptions). Array values are accepted as well.
74
+ * * `waitForNavigation`: (optional, default: 'load'). When to consider navigation succeeded. Possible options: `load`, `domcontentloaded`, `networkidle0`, `networkidle2`. Choose one of those options is possible. See [Playwright API](https://github.com/microsoft/playwright/blob/master/docs/api.md#pagewaitfornavigationoptions).
73
75
  * * `pressKeyDelay`: (optional, default: '10'). Delay between key presses in ms. Used when calling Playwrights page.type(...) in fillField/appendField
74
76
  * * `getPageTimeout` (optional, default: '0') config option to set maximum navigation time in milliseconds.
75
77
  * * `waitForTimeout`: (optional) default wait* timeout in ms. Default: 1000.
@@ -94,7 +96,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
94
96
  * }
95
97
  * ```
96
98
  *
97
- * #### Example #2: Wait for DOMContentLoaded event and 0 network connections
99
+ * #### Example #2: Wait for DOMContentLoaded event
98
100
  *
99
101
  * ```js
100
102
  * {
@@ -102,7 +104,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
102
104
  * Playwright : {
103
105
  * url: "http://localhost",
104
106
  * restart: false,
105
- * waitForNavigation: [ "domcontentloaded", "networkidle0" ],
107
+ * waitForNavigation: "domcontentloaded",
106
108
  * waitForAction: 500
107
109
  * }
108
110
  * }
@@ -533,7 +535,7 @@ class Playwright extends Helper {
533
535
  this.browser.on('targetchanged', (target) => {
534
536
  this.debugSection('Url', target.url());
535
537
  });
536
- this.browserContext = await this.browser.newContext(this.options.emulate);
538
+ this.browserContext = await this.browser.newContext({ acceptDownloads: true, ...this.options.emulate });
537
539
 
538
540
  const existingPages = await this.browserContext.pages();
539
541
 
@@ -993,6 +995,36 @@ class Playwright extends Helper {
993
995
  return empty('elements on a page').assert(els.filter(v => v).fill('ELEMENT'));
994
996
  }
995
997
 
998
+ /**
999
+ * Handles a file download.Aa file name is required to save the file on disk.
1000
+ * Files are saved to "output" directory.
1001
+ *
1002
+ * Should be used with [FileSystem helper](https://codecept.io/helpers/FileSystem) to check that file were downloaded correctly.
1003
+ *
1004
+ * ```js
1005
+ * I.handleDownloads('downloads/avatar.jpg');
1006
+ * I.click('Download Avatar');
1007
+ * I.amInPath('output/downloads');
1008
+ * I.waitForFile('downloads/avatar.jpg', 5);
1009
+ *
1010
+ * ```
1011
+ *
1012
+ * @param {string} [fileName] set filename for downloaded file
1013
+ */
1014
+ async handleDownloads(fileName = 'downloads') {
1015
+ this.page.waitForEvent('download').then(async (download) => {
1016
+ const filePath = await download.path();
1017
+ const downloadPath = path.join(global.output_dir, fileName || path.basename(filePath));
1018
+ if (!fs.existsSync(path.dirname(downloadPath))) {
1019
+ fs.mkdirSync(path.dirname(downloadPath), '0777');
1020
+ }
1021
+ fs.copyFileSync(filePath, downloadPath);
1022
+ this.debug('Download completed');
1023
+ this.debugSection('Downloaded From', await download.url());
1024
+ this.debugSection('Downloaded To', downloadPath);
1025
+ });
1026
+ }
1027
+
996
1028
  /**
997
1029
  * {{> click }}
998
1030
  *
@@ -232,7 +232,7 @@ class Puppeteer extends Helper {
232
232
  try {
233
233
  requireg('puppeteer');
234
234
  } catch (e) {
235
- return ['puppeteer@^1.6.0'];
235
+ return ['puppeteer@^3.0.1'];
236
236
  }
237
237
  }
238
238
 
@@ -943,6 +943,36 @@ class Puppeteer extends Helper {
943
943
  return proceedClick.call(this, locator, context);
944
944
  }
945
945
 
946
+ /**
947
+ * {{> forceClick }}
948
+ *
949
+ * {{ react }}
950
+ */
951
+ async forceClick(locator, context = null) {
952
+ let matcher = await this.context;
953
+ if (context) {
954
+ const els = await this._locate(context);
955
+ assertElementExists(els, context);
956
+ matcher = els[0];
957
+ }
958
+
959
+ const els = await findClickable.call(this, matcher, locator);
960
+ if (context) {
961
+ assertElementExists(els, locator, 'Clickable element', `was not found inside element ${new Locator(context).toString()}`);
962
+ } else {
963
+ assertElementExists(els, locator, 'Clickable element');
964
+ }
965
+ const elem = els[0];
966
+ return this.executeScript((el) => {
967
+ if (document.activeElement instanceof HTMLElement) {
968
+ document.activeElement.blur();
969
+ }
970
+ const event = document.createEvent('MouseEvent');
971
+ event.initEvent('click', true, true);
972
+ return el.dispatchEvent(event);
973
+ }, elem);
974
+ }
975
+
946
976
  /**
947
977
  * {{> clickLink }}
948
978
  *
@@ -516,6 +516,11 @@ class WebDriver extends Helper {
516
516
  if (this.options.multiremote) {
517
517
  this.browser = await webdriverio.multiremote(this.options.multiremote);
518
518
  } else {
519
+ // remove non w3c capabilities
520
+ delete this.options.capabilities.protocol;
521
+ delete this.options.capabilities.hostname;
522
+ delete this.options.capabilities.port;
523
+ delete this.options.capabilities.path;
519
524
  this.browser = await webdriverio.remote(this.options);
520
525
  }
521
526
  } catch (err) {
@@ -765,13 +770,15 @@ class WebDriver extends Helper {
765
770
  * Find a clickable element by providing human readable text:
766
771
  *
767
772
  * ```js
768
- * this.helpers['WebDriver']._locateClickable('Next page').then // ...
773
+ * const els = await this.helpers.WebDriver._locateClickable('Next page');
774
+ * const els = await this.helpers.WebDriver._locateClickable('Next page', '.pages');
769
775
  * ```
770
776
  *
771
777
  * @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
772
778
  */
773
- async _locateClickable(locator) {
774
- return findClickable.call(this, locator, this.$$.bind(this)).then(res => res);
779
+ async _locateClickable(locator, context) {
780
+ const locateFn = prepareLocateFn.call(this, context);
781
+ return findClickable.call(this, locator, locateFn);
775
782
  }
776
783
 
777
784
  /**
@@ -842,6 +849,32 @@ class WebDriver extends Helper {
842
849
  return this.browser[clickMethod](getElementId(elem));
843
850
  }
844
851
 
852
+ /**
853
+ * {{> forceClick }}
854
+ *
855
+ * {{ react }}
856
+ */
857
+ async forceClick(locator, context = null) {
858
+ const locateFn = prepareLocateFn.call(this, context);
859
+
860
+ const res = await findClickable.call(this, locator, locateFn);
861
+ if (context) {
862
+ assertElementExists(res, locator, 'Clickable element', `was not found inside element ${new Locator(context)}`);
863
+ } else {
864
+ assertElementExists(res, locator, 'Clickable element');
865
+ }
866
+ const elem = usingFirstElement(res);
867
+
868
+ return this.executeScript((el) => {
869
+ if (document.activeElement instanceof HTMLElement) {
870
+ document.activeElement.blur();
871
+ }
872
+ const event = document.createEvent('MouseEvent');
873
+ event.initEvent('click', true, true);
874
+ return el.dispatchEvent(event);
875
+ }, elem);
876
+ }
877
+
845
878
  /**
846
879
  * {{> doubleClick }}
847
880
  *
@@ -1859,6 +1892,19 @@ class WebDriver extends Helper {
1859
1892
  */
1860
1893
  async waitForEnabled(locator, sec = null) {
1861
1894
  const aSec = sec || this.options.waitForTimeout;
1895
+ if (isWebDriver5()) {
1896
+ return this.browser.waitUntil(async () => {
1897
+ const res = await this.$$(withStrictLocator(locator));
1898
+ if (!res || res.length === 0) {
1899
+ return false;
1900
+ }
1901
+ const selected = await forEachAsync(res, async el => this.browser.isElementEnabled(getElementId(el)));
1902
+ if (Array.isArray(selected)) {
1903
+ return selected.filter(val => val === true).length > 0;
1904
+ }
1905
+ return selected;
1906
+ }, aSec * 1000, `element (${new Locator(locator)}) still not enabled after ${aSec} sec`);
1907
+ }
1862
1908
  return this.browser.waitUntil(async () => {
1863
1909
  const res = await this.$$(withStrictLocator(locator));
1864
1910
  if (!res || res.length === 0) {
@@ -1869,7 +1915,10 @@ class WebDriver extends Helper {
1869
1915
  return selected.filter(val => val === true).length > 0;
1870
1916
  }
1871
1917
  return selected;
1872
- }, aSec * 1000, `element (${new Locator(locator)}) still not enabled after ${aSec} sec`);
1918
+ }, {
1919
+ timeout: aSec * 1000,
1920
+ timeoutMsg: `element (${new Locator(locator)}) still not enabled after ${aSec} sec`,
1921
+ });
1873
1922
  }
1874
1923
 
1875
1924
  /**
@@ -72,6 +72,7 @@ const defaultConfig = {
72
72
  *
73
73
  */
74
74
  module.exports = (config) => {
75
+ defaultConfig.outputDir = global.output_dir;
75
76
  config = Object.assign(defaultConfig, config);
76
77
 
77
78
  const plugin = {};
@@ -1,4 +1,6 @@
1
1
  const debug = require('debug')('codeceptjs:plugin:wdio');
2
+ const path = require('path');
3
+ const fs = require('fs');
2
4
 
3
5
  const container = require('../container');
4
6
  const mainConfig = require('../config');
@@ -99,7 +101,14 @@ module.exports = (config) => {
99
101
  if (Service) {
100
102
  if (Service.launcher && typeof Service.launcher === 'function') {
101
103
  const Launcher = Service.launcher;
102
- launchers.push(new Launcher(config));
104
+
105
+ const version = JSON.parse(fs.readFileSync(path.join(require.resolve('webdriverio'), '/../../', 'package.json')).toString()).version;
106
+ if (version.indexOf('5') === 0) {
107
+ launchers.push(new Launcher(config));
108
+ } else {
109
+ const options = { logPath: global.output_dir, installArgs: {}, args: {} };
110
+ launchers.push(new Launcher(options, [config.capabilities], config));
111
+ }
103
112
  }
104
113
  if (typeof Service === 'function') {
105
114
  services.push(new Service(config, config.capabilities));
@@ -11,11 +11,11 @@ class Cli extends Base {
11
11
  constructor(runner, opts) {
12
12
  super(runner);
13
13
  let level = 0;
14
+ this.failedTests = [];
14
15
  opts = opts.reporterOptions || opts;
15
16
  if (opts.steps) level = 1;
16
17
  if (opts.debug) level = 2;
17
18
  if (opts.verbose) level = 3;
18
-
19
19
  output.level(level);
20
20
  output.print(`CodeceptJS v${require('../codecept').version()}`);
21
21
  output.print(`Using test root "${global.codecept_dir}"`);
@@ -42,6 +42,9 @@ class Cli extends Base {
42
42
  });
43
43
 
44
44
  runner.on('fail', (test, err) => {
45
+ if (test.ctx.currentTest) {
46
+ this.failedTests.push(test.ctx.currentTest.id);
47
+ }
45
48
  if (showSteps && test.steps) {
46
49
  return output.scenario.failed(test);
47
50
  }
@@ -90,6 +93,24 @@ class Cli extends Base {
90
93
  });
91
94
  }
92
95
 
96
+ runner.on('suite end', suite => {
97
+ let skippedCount = 0;
98
+ const grep = runner._grep;
99
+ for (const test of suite.tests) {
100
+ if (!test.state && !this.failedTests.includes(test.id)) {
101
+ if (matchTest(grep, test.title)) {
102
+ event.emit(event.test.skipped, test);
103
+ test.state = 'skipped';
104
+ output.test.skipped(test);
105
+ skippedCount += 1;
106
+ }
107
+ }
108
+ }
109
+
110
+ this.stats.pending += skippedCount;
111
+ this.stats.tests += skippedCount;
112
+ });
113
+
93
114
  runner.on('end', this.result.bind(this));
94
115
  }
95
116
 
@@ -129,6 +150,14 @@ class Cli extends Base {
129
150
  output.result(stats.passes, stats.failures, stats.pending, ms(stats.duration));
130
151
  }
131
152
  }
153
+
154
+ function matchTest(grep, test) {
155
+ if (grep) {
156
+ return grep.test(test);
157
+ }
158
+ return true;
159
+ }
160
+
132
161
  module.exports = function (runner, opts) {
133
162
  return new Cli(runner, opts);
134
163
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeceptjs",
3
- "version": "2.6.1",
3
+ "version": "2.6.2",
4
4
  "description": "Supercharged End 2 End Testing Framework for NodeJS",
5
5
  "keywords": [
6
6
  "acceptance",
@@ -82,6 +82,7 @@
82
82
  },
83
83
  "devDependencies": {
84
84
  "@codeceptjs/detox-helper": "^1.0.2",
85
+ "@codeceptjs/mock-request": "^0.3.0",
85
86
  "@pollyjs/adapter-puppeteer": "^2.6.3",
86
87
  "@pollyjs/core": "^2.6.3",
87
88
  "@types/inquirer": "^0.0.35",
@@ -109,9 +110,9 @@
109
110
  "mocha-parallel-tests": "^2.2.2",
110
111
  "nightmare": "^3.0.2",
111
112
  "nodemon": "^1.19.4",
112
- "playwright": "^0.12.1",
113
+ "playwright": "^0.14.0",
113
114
  "protractor": "^5.4.1",
114
- "puppeteer": "^1.20.0",
115
+ "puppeteer": "^3.0.0",
115
116
  "qrcode-terminal": "^0.12.0",
116
117
  "rosie": "^1.6.0",
117
118
  "runio.js": "^1.0.20",
@@ -2498,6 +2498,23 @@ declare namespace CodeceptJS {
2498
2498
  * @param {CodeceptJS.LocatorOrString} locator located by CSS|XPath|Strict locator.
2499
2499
  */
2500
2500
  dontSeeElementInDOM(locator: CodeceptJS.LocatorOrString): void;
2501
+ /**
2502
+ * Handles a file download.Aa file name is required to save the file on disk.
2503
+ * Files are saved to "output" directory.
2504
+ *
2505
+ * Should be used with [FileSystem helper](https://codecept.io/helpers/FileSystem) to check that file were downloaded correctly.
2506
+ *
2507
+ * ```js
2508
+ * I.handleDownloads('downloads/avatar.jpg');
2509
+ * I.click('Download Avatar');
2510
+ * I.amInPath('output/downloads');
2511
+ * I.waitForFile('downloads/avatar.jpg', 5);
2512
+ *
2513
+ * ```
2514
+ *
2515
+ * @param {string} [fileName] set filename for downloaded file
2516
+ */
2517
+ handleDownloads(fileName?: string): void;
2501
2518
  /**
2502
2519
  * Perform a click on a link or a button, given by a locator.
2503
2520
  * If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string.
@@ -5109,6 +5126,39 @@ declare namespace CodeceptJS {
5109
5126
  * {{ react }}
5110
5127
  */
5111
5128
  click(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): void;
5129
+ /**
5130
+ * Perform an emulated click on a link or a button, given by a locator.
5131
+ * Unlike normal click instead of sending native event, emulates a click with JavaScript.
5132
+ * This works on hidden, animated or inactive elements as well.
5133
+ *
5134
+ * If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string.
5135
+ * For buttons, the "value" attribute, "name" attribute, and inner text are searched. For links, the link text is searched.
5136
+ * For images, the "alt" attribute and inner text of any parent links are searched.
5137
+ *
5138
+ * The second parameter is a context (CSS or XPath locator) to narrow the search.
5139
+ *
5140
+ * ```js
5141
+ * // simple link
5142
+ * I.forceClick('Logout');
5143
+ * // button of form
5144
+ * I.forceClick('Submit');
5145
+ * // CSS button
5146
+ * I.forceClick('#form input[type=submit]');
5147
+ * // XPath
5148
+ * I.forceClick('//form/*[@type=submit]');
5149
+ * // link in context
5150
+ * I.forceClick('Logout', '#nav');
5151
+ * // using strict locator
5152
+ * I.forceClick({css: 'nav a.login'});
5153
+ * ```
5154
+ *
5155
+ * @param {CodeceptJS.LocatorOrString} locator clickable link or button located by text, or any element located by CSS|XPath|strict locator.
5156
+ * @param {?CodeceptJS.LocatorOrString} [context=null] (optional, `null` by default) element to search in CSS|XPath|Strict locator.
5157
+ *
5158
+ *
5159
+ * {{ react }}
5160
+ */
5161
+ forceClick(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): void;
5112
5162
  /**
5113
5163
  * Performs a click on a link and waits for navigation before moving on.
5114
5164
  *
@@ -7120,7 +7170,8 @@ declare namespace CodeceptJS {
7120
7170
  * Find a clickable element by providing human readable text:
7121
7171
  *
7122
7172
  * ```js
7123
- * this.helpers['WebDriver']._locateClickable('Next page').then // ...
7173
+ * const els = await this.helpers.WebDriver._locateClickable('Next page');
7174
+ * const els = await this.helpers.WebDriver._locateClickable('Next page', '.pages');
7124
7175
  * ```
7125
7176
  *
7126
7177
  * @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
@@ -7193,6 +7244,39 @@ declare namespace CodeceptJS {
7193
7244
  * {{ react }}
7194
7245
  */
7195
7246
  click(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): void;
7247
+ /**
7248
+ * Perform an emulated click on a link or a button, given by a locator.
7249
+ * Unlike normal click instead of sending native event, emulates a click with JavaScript.
7250
+ * This works on hidden, animated or inactive elements as well.
7251
+ *
7252
+ * If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string.
7253
+ * For buttons, the "value" attribute, "name" attribute, and inner text are searched. For links, the link text is searched.
7254
+ * For images, the "alt" attribute and inner text of any parent links are searched.
7255
+ *
7256
+ * The second parameter is a context (CSS or XPath locator) to narrow the search.
7257
+ *
7258
+ * ```js
7259
+ * // simple link
7260
+ * I.forceClick('Logout');
7261
+ * // button of form
7262
+ * I.forceClick('Submit');
7263
+ * // CSS button
7264
+ * I.forceClick('#form input[type=submit]');
7265
+ * // XPath
7266
+ * I.forceClick('//form/*[@type=submit]');
7267
+ * // link in context
7268
+ * I.forceClick('Logout', '#nav');
7269
+ * // using strict locator
7270
+ * I.forceClick({css: 'nav a.login'});
7271
+ * ```
7272
+ *
7273
+ * @param {CodeceptJS.LocatorOrString} locator clickable link or button located by text, or any element located by CSS|XPath|strict locator.
7274
+ * @param {?CodeceptJS.LocatorOrString} [context=null] (optional, `null` by default) element to search in CSS|XPath|Strict locator.
7275
+ *
7276
+ *
7277
+ * {{ react }}
7278
+ */
7279
+ forceClick(locator: CodeceptJS.LocatorOrString, context?: CodeceptJS.LocatorOrString): void;
7196
7280
  /**
7197
7281
  * Performs a double-click on an element matched by link|button|label|CSS or XPath.
7198
7282
  * Context can be specified as second parameter to narrow search.
@@ -9970,6 +10054,7 @@ declare namespace CodeceptJS {
9970
10054
  * @property {'test.passed'} passed
9971
10055
  * @property {'test.failed'} failed
9972
10056
  * @property {'test.finish'} finished
10057
+ * @property {'test.skipped'} skipped
9973
10058
  */
9974
10059
  const test: {
9975
10060
  started: 'test.start';
@@ -9978,6 +10063,7 @@ declare namespace CodeceptJS {
9978
10063
  passed: 'test.passed';
9979
10064
  failed: 'test.failed';
9980
10065
  finished: 'test.finish';
10066
+ skipped: 'test.skipped';
9981
10067
  };
9982
10068
  /**
9983
10069
  * @type {object}