codeceptjs 2.1.3 → 2.2.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.
- package/CHANGELOG.md +125 -37
- package/README.md +15 -22
- package/bin/codecept.js +4 -1
- package/docs/acceptance.md +44 -1
- package/docs/advanced.md +1 -1
- package/docs/angular.md +6 -9
- package/docs/basics.md +388 -75
- package/docs/bdd.md +4 -3
- package/docs/best.md +1 -1
- package/docs/books.md +31 -0
- package/docs/build/Appium.js +215 -176
- package/docs/build/Nightmare.js +618 -489
- package/docs/build/Polly.js +189 -0
- package/docs/build/Protractor.js +747 -608
- package/docs/build/Puppeteer.js +914 -633
- package/docs/build/REST.js +1 -1
- package/docs/build/TestCafe.js +1835 -0
- package/docs/build/WebDriver.js +861 -805
- package/docs/build/WebDriverIO.js +616 -617
- package/docs/changelog.md +410 -316
- package/docs/commands.md +6 -6
- package/docs/community-helpers.md +2 -0
- package/docs/detox.md +235 -0
- package/docs/examples.md +23 -0
- package/docs/helpers/ApiDataFactory.md +11 -10
- package/docs/helpers/Appium.md +130 -61
- package/docs/helpers/Detox.md +579 -0
- package/docs/helpers/FileSystem.md +2 -1
- package/docs/helpers/Mochawesome.md +1 -0
- package/docs/helpers/Nightmare.md +348 -128
- package/docs/helpers/Polly.md +85 -0
- package/docs/helpers/Protractor.md +451 -184
- package/docs/helpers/Puppeteer-firefox.md +55 -0
- package/docs/helpers/Puppeteer.md +619 -183
- package/docs/helpers/REST.md +17 -16
- package/docs/helpers/SeleniumWebdriver.md +9 -8
- package/docs/helpers/TestCafe.md +1168 -0
- package/docs/helpers/WebDriver.md +600 -291
- package/docs/helpers/WebDriverIO.md +393 -278
- package/docs/helpers.md +37 -18
- package/docs/locators.md +2 -0
- package/docs/mobile-react-native-locators.md +64 -0
- package/docs/mobile.md +5 -0
- package/docs/plugins.md +54 -13
- package/docs/puppeteer.md +74 -26
- package/docs/quickstart.md +47 -12
- package/docs/react.md +67 -0
- package/docs/reports.md +1 -1
- package/docs/{webapi/_keys.mustache → shared/keys.mustache} +0 -0
- package/docs/shared/react.mustache +1 -0
- package/docs/testcafe.md +157 -0
- package/docs/videos.md +19 -0
- package/docs/webapi/amOnPage.mustache +1 -1
- package/docs/webapi/appendField.mustache +2 -2
- package/docs/webapi/attachFile.mustache +2 -2
- package/docs/webapi/checkOption.mustache +2 -2
- package/docs/webapi/clearCookie.mustache +1 -1
- package/docs/webapi/clearField.mustache +1 -1
- package/docs/webapi/click.mustache +2 -2
- package/docs/webapi/clickLink.mustache +3 -3
- package/docs/webapi/dontSee.mustache +6 -3
- package/docs/webapi/dontSeeCheckboxIsChecked.mustache +7 -1
- package/docs/webapi/dontSeeCookie.mustache +5 -1
- package/docs/webapi/dontSeeCurrentUrlEquals.mustache +6 -1
- package/docs/webapi/dontSeeElement.mustache +5 -1
- package/docs/webapi/dontSeeElementInDOM.mustache +5 -1
- package/docs/webapi/dontSeeInCurrentUrl.mustache +1 -1
- package/docs/webapi/dontSeeInField.mustache +7 -2
- package/docs/webapi/dontSeeInSource.mustache +5 -1
- package/docs/webapi/dontSeeInTitle.mustache +5 -1
- package/docs/webapi/doubleClick.mustache +2 -2
- package/docs/webapi/downloadFile.mustache +2 -2
- package/docs/webapi/dragAndDrop.mustache +2 -2
- package/docs/webapi/dragSlider.mustache +2 -2
- package/docs/webapi/executeAsyncScript.mustache +1 -1
- package/docs/webapi/executeScript.mustache +1 -1
- package/docs/webapi/fillField.mustache +2 -2
- package/docs/webapi/grabAttributeFrom.mustache +3 -2
- package/docs/webapi/grabBrowserLogs.mustache +3 -1
- package/docs/webapi/grabCookie.mustache +2 -1
- package/docs/webapi/grabCssPropertyFrom.mustache +3 -2
- package/docs/webapi/grabCurrentUrl.mustache +3 -1
- package/docs/webapi/grabDataFromPerformanceTiming.mustache +19 -0
- package/docs/webapi/grabHTMLFrom.mustache +2 -1
- package/docs/webapi/grabNumberOfOpenTabs.mustache +4 -2
- package/docs/webapi/grabNumberOfVisibleElements.mustache +3 -2
- package/docs/webapi/grabPageScrollPosition.mustache +3 -1
- package/docs/webapi/grabSource.mustache +3 -1
- package/docs/webapi/grabTextFrom.mustache +2 -1
- package/docs/webapi/grabTitle.mustache +3 -1
- package/docs/webapi/grabValueFrom.mustache +2 -1
- package/docs/webapi/moveCursorTo.mustache +3 -3
- package/docs/webapi/pressKey.mustache +1 -1
- package/docs/webapi/resizeWindow.mustache +2 -2
- package/docs/webapi/rightClick.mustache +2 -2
- package/docs/webapi/saveScreenshot.mustache +3 -3
- package/docs/webapi/say.mustache +2 -2
- package/docs/webapi/scrollPageToBottom.mustache +1 -1
- package/docs/webapi/scrollPageToTop.mustache +1 -1
- package/docs/webapi/scrollTo.mustache +3 -3
- package/docs/webapi/see.mustache +2 -2
- package/docs/webapi/seeAttributesOnElements.mustache +3 -3
- package/docs/webapi/seeCheckboxIsChecked.mustache +2 -1
- package/docs/webapi/seeCookie.mustache +1 -1
- package/docs/webapi/seeCssPropertiesOnElements.mustache +2 -2
- package/docs/webapi/seeCurrentUrlEquals.mustache +1 -1
- package/docs/webapi/seeElement.mustache +1 -1
- package/docs/webapi/seeElementInDOM.mustache +1 -1
- package/docs/webapi/seeInCurrentUrl.mustache +1 -1
- package/docs/webapi/seeInField.mustache +2 -2
- package/docs/webapi/seeInSource.mustache +1 -1
- package/docs/webapi/seeInTitle.mustache +5 -1
- package/docs/webapi/seeNumberOfElements.mustache +10 -0
- package/docs/webapi/seeNumberOfVisibleElements.mustache +2 -2
- package/docs/webapi/selectOption.mustache +2 -2
- package/docs/webapi/setCookie.mustache +1 -1
- package/docs/webapi/switchTo.mustache +6 -1
- package/docs/webapi/uncheckOption.mustache +2 -2
- package/docs/webapi/wait.mustache +1 -2
- package/docs/webapi/waitForDetached.mustache +3 -3
- package/docs/webapi/waitForElement.mustache +2 -2
- package/docs/webapi/waitForEnabled.mustache +1 -1
- package/docs/webapi/waitForFunction.mustache +3 -3
- package/docs/webapi/waitForInvisible.mustache +3 -3
- package/docs/webapi/waitForText.mustache +3 -3
- package/docs/webapi/waitForValue.mustache +3 -3
- package/docs/webapi/waitForVisible.mustache +3 -3
- package/docs/webapi/waitInUrl.mustache +2 -2
- package/docs/webapi/waitNumberOfVisibleElements.mustache +3 -3
- package/docs/webapi/waitToHide.mustache +3 -3
- package/docs/webapi/waitUntil.mustache +3 -3
- package/docs/webapi/waitUrlEquals.mustache +2 -2
- package/docs/webdriver.md +453 -0
- package/lib/codecept.js +11 -9
- package/lib/command/definitions.js +183 -30
- package/lib/command/gherkin/snippets.js +29 -9
- package/lib/command/init.js +31 -9
- package/lib/command/run-multiple.js +46 -59
- package/lib/command/utils.js +1 -1
- package/lib/container.js +30 -4
- package/lib/data/dataScenarioConfig.js +18 -0
- package/lib/helper/Appium.js +24 -24
- package/lib/helper/Nightmare.js +81 -84
- package/lib/helper/Polly.js +189 -0
- package/lib/helper/Protractor.js +96 -86
- package/lib/helper/Puppeteer.js +238 -113
- package/lib/helper/REST.js +1 -1
- package/lib/helper/TestCafe.js +1257 -0
- package/lib/helper/WebDriver.js +217 -277
- package/lib/helper/WebDriverIO.js +75 -75
- package/lib/helper/clientscripts/nightmare.js +8 -0
- package/lib/helper/extras/React.js +55 -0
- package/lib/helper/testcafe/testControllerHolder.js +42 -0
- package/lib/helper/testcafe/testcafe-utils.js +63 -0
- package/lib/history.js +39 -0
- package/lib/hooks.js +25 -1
- package/lib/interfaces/gherkin.js +17 -1
- package/lib/interfaces/scenarioConfig.js +2 -2
- package/lib/listener/config.js +3 -3
- package/lib/locator.js +6 -0
- package/lib/pause.js +22 -1
- package/lib/plugin/allure.js +63 -0
- package/lib/plugin/autoLogin.js +65 -16
- package/lib/plugin/puppeteerCoverage.js +6 -1
- package/lib/plugin/stepByStepReport.js +4 -3
- package/lib/scenario.js +23 -17
- package/lib/step.js +5 -2
- package/lib/ui.js +1 -1
- package/lib/utils.js +70 -20
- package/package.json +20 -19
- package/translations/de-DE.js +69 -0
- package/translations/index.js +1 -0
- package/docs/video.md +0 -26
package/docs/build/Puppeteer.js
CHANGED
|
@@ -11,7 +11,6 @@ const {
|
|
|
11
11
|
xpathLocator,
|
|
12
12
|
ucfirst,
|
|
13
13
|
fileExists,
|
|
14
|
-
clearString,
|
|
15
14
|
chunkArray,
|
|
16
15
|
convertCssPropertiesToCamelCase,
|
|
17
16
|
screenshotOutputFolder,
|
|
@@ -25,11 +24,13 @@ const ElementNotFound = require('./errors/ElementNotFound');
|
|
|
25
24
|
const RemoteBrowserConnectionRefused = require('./errors/RemoteBrowserConnectionRefused');
|
|
26
25
|
const Popup = require('./extras/Popup');
|
|
27
26
|
const Console = require('./extras/Console');
|
|
27
|
+
const findReact = require('./extras/React');
|
|
28
28
|
const axios = require('axios');
|
|
29
29
|
const fs = require('fs');
|
|
30
|
-
|
|
30
|
+
const fsExtra = require('fs-extra');
|
|
31
31
|
|
|
32
32
|
let puppeteer;
|
|
33
|
+
let perfTiming;
|
|
33
34
|
const popupStore = new Popup();
|
|
34
35
|
const consoleLogStore = new Console();
|
|
35
36
|
|
|
@@ -40,6 +41,8 @@ const consoleLogStore = new Console();
|
|
|
40
41
|
*
|
|
41
42
|
* Requires `puppeteer` package to be installed.
|
|
42
43
|
*
|
|
44
|
+
* > Experiemental Firefox support [can be activated](https://codecept.io/helpers/Puppeteer-firefox).
|
|
45
|
+
*
|
|
43
46
|
* ## Configuration
|
|
44
47
|
*
|
|
45
48
|
* This helper should be configured in codecept.json or codecept.conf.js
|
|
@@ -54,11 +57,13 @@ const consoleLogStore = new Console();
|
|
|
54
57
|
* * `keepCookies`: (optional, default: false) - keep cookies between tests when `restart` is set to false.
|
|
55
58
|
* * `waitForAction`: (optional) how long to wait after click, doubleClick or PressKey actions in ms. Default: 100.
|
|
56
59
|
* * `waitForNavigation`: (optional, default: 'load'). When to consider navigation succeeded. Possible options: `load`, `domcontentloaded`, `networkidle0`, `networkidle2`. See [Puppeteer API](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagewaitfornavigationoptions). Array values are accepted as well.
|
|
60
|
+
* * `pressKeyDelay`: (optional, default: '10'). Delay between key presses in ms. Used when calling Puppeteers page.type(...) in fillField/appendField
|
|
57
61
|
* * `getPageTimeout` (optional, default: '0') config option to set maximum navigation time in milliseconds.
|
|
58
62
|
* * `waitForTimeout`: (optional) default wait* timeout in ms. Default: 1000.
|
|
59
63
|
* * `windowSize`: (optional) default window size. Set a dimension like `640x480`.
|
|
60
64
|
* * `userAgent`: (optional) user-agent string.
|
|
61
65
|
* * `manualStart`: (optional, default: false) - do not start browser before a test, start it manually inside a helper with `this.helpers["Puppeteer"]._startBrowser()`.
|
|
66
|
+
* * `browser`: (optional, default: chrome) - can be changed to `firefox` when using [puppeteer-firefox](https://codecept.io/helpers/Puppeteer-firefox).
|
|
62
67
|
* * `chrome`: (optional) pass additional [Puppeteer run options](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions).
|
|
63
68
|
*
|
|
64
69
|
*
|
|
@@ -139,7 +144,8 @@ const consoleLogStore = new Console();
|
|
|
139
144
|
class Puppeteer extends Helper {
|
|
140
145
|
constructor(config) {
|
|
141
146
|
super(config);
|
|
142
|
-
|
|
147
|
+
|
|
148
|
+
puppeteer = requireg(config.browser === 'firefox' ? 'puppeteer-firefox' : 'puppeteer');
|
|
143
149
|
|
|
144
150
|
// set defaults
|
|
145
151
|
this.isRemoteBrowser = false;
|
|
@@ -151,8 +157,10 @@ class Puppeteer extends Helper {
|
|
|
151
157
|
|
|
152
158
|
_validateConfig(config) {
|
|
153
159
|
const defaults = {
|
|
160
|
+
browser: 'chrome',
|
|
154
161
|
waitForAction: 100,
|
|
155
162
|
waitForTimeout: 1000,
|
|
163
|
+
pressKeyDelay: 10,
|
|
156
164
|
fullPageScreenshots: false,
|
|
157
165
|
disableScreenshots: false,
|
|
158
166
|
uniqueScreenshotNames: false,
|
|
@@ -169,9 +177,13 @@ class Puppeteer extends Helper {
|
|
|
169
177
|
return Object.assign(defaults, config);
|
|
170
178
|
}
|
|
171
179
|
|
|
180
|
+
_getOptions(config) {
|
|
181
|
+
return config.browser === 'firefox' ? this.options.firefox : this.options.chrome;
|
|
182
|
+
}
|
|
183
|
+
|
|
172
184
|
_setConfig(config) {
|
|
173
185
|
this.options = this._validateConfig(config);
|
|
174
|
-
this.puppeteerOptions = Object.assign({ headless: !this.options.show }, this.
|
|
186
|
+
this.puppeteerOptions = Object.assign({ headless: !this.options.show }, this._getOptions(config));
|
|
175
187
|
this.isRemoteBrowser = !!this.puppeteerOptions.browserWSEndpoint;
|
|
176
188
|
popupStore.defaultAction = this.options.defaultPopupAction;
|
|
177
189
|
}
|
|
@@ -179,6 +191,9 @@ class Puppeteer extends Helper {
|
|
|
179
191
|
static _config() {
|
|
180
192
|
return [
|
|
181
193
|
{ name: 'url', message: 'Base url of site to be tested', default: 'http://localhost' },
|
|
194
|
+
{
|
|
195
|
+
name: 'show', message: 'Show browser window', default: true, type: 'confirm',
|
|
196
|
+
},
|
|
182
197
|
];
|
|
183
198
|
}
|
|
184
199
|
|
|
@@ -339,7 +354,9 @@ class Puppeteer extends Helper {
|
|
|
339
354
|
if (!page) return;
|
|
340
355
|
page.setDefaultNavigationTimeout(this.options.getPageTimeout);
|
|
341
356
|
this.context = await this.page.$('body');
|
|
342
|
-
|
|
357
|
+
if (this.config.browser === 'chrome') {
|
|
358
|
+
await page.bringToFront();
|
|
359
|
+
}
|
|
343
360
|
}
|
|
344
361
|
|
|
345
362
|
/**
|
|
@@ -488,32 +505,56 @@ class Puppeteer extends Helper {
|
|
|
488
505
|
this.context = await this.page.mainFrame().$('body');
|
|
489
506
|
}
|
|
490
507
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
508
|
+
_extractDataFromPerformanceTiming(timing, ...dataNames) {
|
|
509
|
+
const navigationStart = timing.navigationStart;
|
|
510
|
+
|
|
511
|
+
const extractedData = {};
|
|
512
|
+
dataNames.forEach((name) => {
|
|
513
|
+
extractedData[name] = timing[name] - navigationStart;
|
|
514
|
+
});
|
|
494
515
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
I.amOnPage('https://github.com'); // opens github
|
|
498
|
-
I.amOnPage('/login'); // opens a login page
|
|
499
|
-
```
|
|
516
|
+
return extractedData;
|
|
517
|
+
}
|
|
500
518
|
|
|
501
|
-
|
|
519
|
+
/**
|
|
520
|
+
* Opens a web page in a browser. Requires relative or absolute url.
|
|
521
|
+
* If url starts with `/`, opens a web page of a site defined in `url` config parameter.
|
|
522
|
+
*
|
|
523
|
+
* ```js
|
|
524
|
+
* I.amOnPage('/'); // opens main page of website
|
|
525
|
+
* I.amOnPage('https://github.com'); // opens github
|
|
526
|
+
* I.amOnPage('/login'); // opens a login page
|
|
527
|
+
* ```
|
|
528
|
+
*
|
|
529
|
+
* @param {string} url url path or global url.
|
|
530
|
+
* {--end--}
|
|
502
531
|
*/
|
|
503
532
|
async amOnPage(url) {
|
|
504
533
|
if (!(/^\w+\:\/\//.test(url))) {
|
|
505
534
|
url = this.options.url + url;
|
|
506
535
|
}
|
|
507
536
|
await this.page.goto(url, { waitUntil: this.options.waitForNavigation });
|
|
537
|
+
|
|
538
|
+
const performanceTiming = JSON.parse(await this.page.evaluate(() => JSON.stringify(window.performance.timing)));
|
|
539
|
+
|
|
540
|
+
perfTiming = this._extractDataFromPerformanceTiming(
|
|
541
|
+
performanceTiming,
|
|
542
|
+
'responseEnd',
|
|
543
|
+
'domInteractive',
|
|
544
|
+
'domContentLoadedEventEnd',
|
|
545
|
+
'loadEventEnd',
|
|
546
|
+
);
|
|
547
|
+
|
|
508
548
|
return this._waitForAction();
|
|
509
549
|
}
|
|
510
550
|
|
|
511
551
|
/**
|
|
512
552
|
* Resize the current window to provided width and height.
|
|
513
|
-
First parameter can be set to `maximize`.
|
|
514
|
-
|
|
515
|
-
@param width width in pixels or `maximize`.
|
|
516
|
-
@param height height in pixels.
|
|
553
|
+
* First parameter can be set to `maximize`.
|
|
554
|
+
*
|
|
555
|
+
* @param {number} width width in pixels or `maximize`.
|
|
556
|
+
* @param {number} height height in pixels.
|
|
557
|
+
* {--end--}
|
|
517
558
|
*
|
|
518
559
|
* Unlike other drivers Puppeteer changes the size of a viewport, not the window!
|
|
519
560
|
* Puppeteer does not control the window of a browser so it can't adjust its real size.
|
|
@@ -536,6 +577,8 @@ First parameter can be set to `maximize`.
|
|
|
536
577
|
* 'X-Sent-By': 'CodeceptJS',
|
|
537
578
|
* });
|
|
538
579
|
* ```
|
|
580
|
+
*
|
|
581
|
+
* @param {object} customHeaders headers to set
|
|
539
582
|
*/
|
|
540
583
|
async haveRequestHeaders(customHeaders) {
|
|
541
584
|
if (!customHeaders) {
|
|
@@ -546,16 +589,18 @@ First parameter can be set to `maximize`.
|
|
|
546
589
|
|
|
547
590
|
/**
|
|
548
591
|
* Moves cursor to element matched by locator.
|
|
549
|
-
Extra shift can be set with offsetX and offsetY options.
|
|
550
|
-
|
|
551
|
-
```js
|
|
552
|
-
I.moveCursorTo('.tooltip');
|
|
553
|
-
I.moveCursorTo('#submit', 5,5);
|
|
554
|
-
```
|
|
555
|
-
|
|
556
|
-
@param locator located by CSS|XPath|strict locator.
|
|
557
|
-
@param offsetX (optional) X-axis offset.
|
|
558
|
-
@param offsetY (optional) Y-axis offset.
|
|
592
|
+
* Extra shift can be set with offsetX and offsetY options.
|
|
593
|
+
*
|
|
594
|
+
* ```js
|
|
595
|
+
* I.moveCursorTo('.tooltip');
|
|
596
|
+
* I.moveCursorTo('#submit', 5,5);
|
|
597
|
+
* ```
|
|
598
|
+
*
|
|
599
|
+
* @param {string|object} locator located by CSS|XPath|strict locator.
|
|
600
|
+
* @param {number} offsetX (optional, `0` by default) X-axis offset.
|
|
601
|
+
* @param {number} offsetY (optional, `0` by default) Y-axis offset.
|
|
602
|
+
* {--end--}
|
|
603
|
+
* {{ react }}
|
|
559
604
|
*/
|
|
560
605
|
async moveCursorTo(locator, offsetX = 0, offsetY = 0) {
|
|
561
606
|
const els = await this._locate(locator);
|
|
@@ -569,13 +614,14 @@ I.moveCursorTo('#submit', 5,5);
|
|
|
569
614
|
|
|
570
615
|
/**
|
|
571
616
|
* Drag an item to a destination element.
|
|
572
|
-
|
|
573
|
-
```js
|
|
574
|
-
I.dragAndDrop('#dragHandle', '#container');
|
|
575
|
-
```
|
|
576
|
-
|
|
577
|
-
@param srcElement located by CSS|XPath|strict locator.
|
|
578
|
-
@param destElement located by CSS|XPath|strict locator.
|
|
617
|
+
*
|
|
618
|
+
* ```js
|
|
619
|
+
* I.dragAndDrop('#dragHandle', '#container');
|
|
620
|
+
* ```
|
|
621
|
+
*
|
|
622
|
+
* @param {string|object} srcElement located by CSS|XPath|strict locator.
|
|
623
|
+
* @param {string|object} destElement located by CSS|XPath|strict locator.
|
|
624
|
+
* {--end--}
|
|
579
625
|
*/
|
|
580
626
|
async dragAndDrop(srcElement, destElement) {
|
|
581
627
|
return proceedDragAndDrop.call(this, srcElement, destElement);
|
|
@@ -583,11 +629,11 @@ I.dragAndDrop('#dragHandle', '#container');
|
|
|
583
629
|
|
|
584
630
|
/**
|
|
585
631
|
* Reload the current page.
|
|
586
|
-
|
|
587
|
-
```js
|
|
588
|
-
I.refreshPage();
|
|
589
|
-
```
|
|
590
|
-
|
|
632
|
+
*
|
|
633
|
+
* ```js
|
|
634
|
+
* I.refreshPage();
|
|
635
|
+
* ```
|
|
636
|
+
* {--end--}
|
|
591
637
|
*/
|
|
592
638
|
async refreshPage() {
|
|
593
639
|
return this.page.reload({ timeout: this.options.getPageTimeout, waitUntil: this.options.waitForNavigation });
|
|
@@ -595,26 +641,28 @@ I.refreshPage();
|
|
|
595
641
|
|
|
596
642
|
/**
|
|
597
643
|
* Scroll page to the top.
|
|
598
|
-
|
|
599
|
-
```js
|
|
600
|
-
I.scrollPageToTop();
|
|
601
|
-
```
|
|
644
|
+
*
|
|
645
|
+
* ```js
|
|
646
|
+
* I.scrollPageToTop();
|
|
647
|
+
* ```
|
|
648
|
+
* {--end--}
|
|
602
649
|
*/
|
|
603
650
|
scrollPageToTop() {
|
|
604
|
-
return this.
|
|
651
|
+
return this.executeScript(() => {
|
|
605
652
|
window.scrollTo(0, 0);
|
|
606
653
|
});
|
|
607
654
|
}
|
|
608
655
|
|
|
609
656
|
/**
|
|
610
657
|
* Scroll page to the bottom.
|
|
611
|
-
|
|
612
|
-
```js
|
|
613
|
-
I.scrollPageToBottom();
|
|
614
|
-
```
|
|
658
|
+
*
|
|
659
|
+
* ```js
|
|
660
|
+
* I.scrollPageToBottom();
|
|
661
|
+
* ```
|
|
662
|
+
* {--end--}
|
|
615
663
|
*/
|
|
616
664
|
scrollPageToBottom() {
|
|
617
|
-
return this.
|
|
665
|
+
return this.executeScript(() => {
|
|
618
666
|
const body = document.body;
|
|
619
667
|
const html = document.documentElement;
|
|
620
668
|
window.scrollTo(0, Math.max(
|
|
@@ -626,16 +674,17 @@ I.scrollPageToBottom();
|
|
|
626
674
|
|
|
627
675
|
/**
|
|
628
676
|
* Scrolls to element matched by locator.
|
|
629
|
-
Extra shift can be set with offsetX and offsetY options.
|
|
630
|
-
|
|
631
|
-
```js
|
|
632
|
-
I.scrollTo('footer');
|
|
633
|
-
I.scrollTo('#submit', 5, 5);
|
|
634
|
-
```
|
|
635
|
-
|
|
636
|
-
@param locator located by CSS|XPath|strict locator.
|
|
637
|
-
@param offsetX (optional) X-axis offset.
|
|
638
|
-
@param offsetY (optional) Y-axis offset.
|
|
677
|
+
* Extra shift can be set with offsetX and offsetY options.
|
|
678
|
+
*
|
|
679
|
+
* ```js
|
|
680
|
+
* I.scrollTo('footer');
|
|
681
|
+
* I.scrollTo('#submit', 5, 5);
|
|
682
|
+
* ```
|
|
683
|
+
*
|
|
684
|
+
* @param {string|object} locator located by CSS|XPath|strict locator.
|
|
685
|
+
* @param {number} offsetX (optional, `0` by default) X-axis offset.
|
|
686
|
+
* @param {number} offsetY (optional, `0` by default) Y-axis offset.
|
|
687
|
+
* {--end--}
|
|
639
688
|
*/
|
|
640
689
|
async scrollTo(locator, offsetX = 0, offsetY = 0) {
|
|
641
690
|
if (typeof locator === 'number' && typeof offsetX === 'number') {
|
|
@@ -643,27 +692,28 @@ I.scrollTo('#submit', 5, 5);
|
|
|
643
692
|
offsetX = locator;
|
|
644
693
|
locator = null;
|
|
645
694
|
}
|
|
646
|
-
|
|
647
|
-
let y = 0;
|
|
695
|
+
|
|
648
696
|
if (locator) {
|
|
649
697
|
const els = await this._locate(locator);
|
|
650
698
|
assertElementExists(els, locator, 'Element');
|
|
651
699
|
await els[0]._scrollIntoViewIfNeeded();
|
|
652
700
|
const elementCoordinates = await els[0]._clickablePoint();
|
|
653
|
-
x
|
|
654
|
-
|
|
701
|
+
await this.executeScript((x, y) => window.scrollBy(x, y), elementCoordinates.x + offsetX, elementCoordinates.y + offsetY);
|
|
702
|
+
} else {
|
|
703
|
+
await this.executeScript((x, y) => window.scrollTo(x, y), offsetX, offsetY);
|
|
655
704
|
}
|
|
656
|
-
|
|
657
|
-
await this.page.evaluate((x, y) => {
|
|
658
|
-
window.scrollTo(x, y);
|
|
659
|
-
}, x + offsetX, y + offsetY);
|
|
660
705
|
return this._waitForAction();
|
|
661
706
|
}
|
|
662
707
|
|
|
663
708
|
/**
|
|
664
709
|
* Checks that title contains text.
|
|
665
|
-
|
|
666
|
-
|
|
710
|
+
*
|
|
711
|
+
* ```js
|
|
712
|
+
* I.seeInTitle('Home Page');
|
|
713
|
+
* ```
|
|
714
|
+
*
|
|
715
|
+
* @param {string} text text value to check.
|
|
716
|
+
* {--end--}
|
|
667
717
|
*/
|
|
668
718
|
async seeInTitle(text) {
|
|
669
719
|
const title = await this.page.title();
|
|
@@ -672,11 +722,14 @@ I.scrollTo('#submit', 5, 5);
|
|
|
672
722
|
|
|
673
723
|
/**
|
|
674
724
|
* Retrieves a page scroll position and returns it to test.
|
|
675
|
-
Resumes test execution, so **should be used inside an async function with `await`** operator.
|
|
676
|
-
|
|
677
|
-
```js
|
|
678
|
-
let { x, y } = await I.grabPageScrollPosition();
|
|
679
|
-
```
|
|
725
|
+
* Resumes test execution, so **should be used inside an async function with `await`** operator.
|
|
726
|
+
*
|
|
727
|
+
* ```js
|
|
728
|
+
* let { x, y } = await I.grabPageScrollPosition();
|
|
729
|
+
* ```
|
|
730
|
+
*
|
|
731
|
+
* @returns {Promise<object>} scroll position
|
|
732
|
+
* {--end--}
|
|
680
733
|
*/
|
|
681
734
|
async grabPageScrollPosition() {
|
|
682
735
|
/* eslint-disable comma-dangle */
|
|
@@ -704,8 +757,13 @@ let { x, y } = await I.grabPageScrollPosition();
|
|
|
704
757
|
|
|
705
758
|
/**
|
|
706
759
|
* Checks that title does not contain text.
|
|
707
|
-
|
|
708
|
-
|
|
760
|
+
*
|
|
761
|
+
* ```js
|
|
762
|
+
* I.dontSeeInTitle('Error');
|
|
763
|
+
* ```
|
|
764
|
+
*
|
|
765
|
+
* @param {string} text value to check.
|
|
766
|
+
* {--end--}
|
|
709
767
|
*/
|
|
710
768
|
async dontSeeInTitle(text) {
|
|
711
769
|
const title = await this.page.title();
|
|
@@ -714,11 +772,14 @@ let { x, y } = await I.grabPageScrollPosition();
|
|
|
714
772
|
|
|
715
773
|
/**
|
|
716
774
|
* Retrieves a page title and returns it to test.
|
|
717
|
-
Resumes test execution, so **should be used inside async with `await`** operator.
|
|
718
|
-
|
|
719
|
-
```js
|
|
720
|
-
let title = await I.grabTitle();
|
|
721
|
-
```
|
|
775
|
+
* Resumes test execution, so **should be used inside async with `await`** operator.
|
|
776
|
+
*
|
|
777
|
+
* ```js
|
|
778
|
+
* let title = await I.grabTitle();
|
|
779
|
+
* ```
|
|
780
|
+
*
|
|
781
|
+
* @returns {Promise<string>} title
|
|
782
|
+
* {--end--}
|
|
722
783
|
*/
|
|
723
784
|
async grabTitle() {
|
|
724
785
|
return this.page.title();
|
|
@@ -731,6 +792,8 @@ let title = await I.grabTitle();
|
|
|
731
792
|
* ```js
|
|
732
793
|
* const elements = await this.helpers['Puppeteer']._locate({name: 'password'});
|
|
733
794
|
* ```
|
|
795
|
+
*
|
|
796
|
+
* {{ react }}
|
|
734
797
|
*/
|
|
735
798
|
async _locate(locator) {
|
|
736
799
|
return findElements(await this.context, locator);
|
|
@@ -781,6 +844,8 @@ let title = await I.grabTitle();
|
|
|
781
844
|
* I.switchToNextTab();
|
|
782
845
|
* I.switchToNextTab(2);
|
|
783
846
|
* ```
|
|
847
|
+
*
|
|
848
|
+
* @param {number} [num=1]
|
|
784
849
|
*/
|
|
785
850
|
async switchToNextTab(num = 1) {
|
|
786
851
|
const pages = await this.browser.pages();
|
|
@@ -803,6 +868,7 @@ let title = await I.grabTitle();
|
|
|
803
868
|
* I.switchToPreviousTab();
|
|
804
869
|
* I.switchToPreviousTab(2);
|
|
805
870
|
* ```
|
|
871
|
+
* @param {number} [num=1]
|
|
806
872
|
*/
|
|
807
873
|
async switchToPreviousTab(num = 1) {
|
|
808
874
|
const pages = await this.browser.pages();
|
|
@@ -865,10 +931,13 @@ let title = await I.grabTitle();
|
|
|
865
931
|
|
|
866
932
|
/**
|
|
867
933
|
* Grab number of open tabs.
|
|
868
|
-
|
|
869
|
-
```js
|
|
870
|
-
I.grabNumberOfOpenTabs();
|
|
871
|
-
```
|
|
934
|
+
*
|
|
935
|
+
* ```js
|
|
936
|
+
* let tabs = await I.grabNumberOfOpenTabs();
|
|
937
|
+
* ```
|
|
938
|
+
*
|
|
939
|
+
* @returns {Promise<number>} number of open tabs
|
|
940
|
+
* {--end--}
|
|
872
941
|
*/
|
|
873
942
|
async grabNumberOfOpenTabs() {
|
|
874
943
|
const pages = await this.browser.pages();
|
|
@@ -877,14 +946,15 @@ I.grabNumberOfOpenTabs();
|
|
|
877
946
|
|
|
878
947
|
/**
|
|
879
948
|
* Checks that a given Element is visible
|
|
880
|
-
Element is located by CSS or XPath.
|
|
881
|
-
|
|
882
|
-
```js
|
|
883
|
-
I.seeElement('#modal');
|
|
884
|
-
```
|
|
885
|
-
@param locator located by CSS|XPath|strict locator.
|
|
949
|
+
* Element is located by CSS or XPath.
|
|
950
|
+
*
|
|
951
|
+
* ```js
|
|
952
|
+
* I.seeElement('#modal');
|
|
953
|
+
* ```
|
|
954
|
+
* @param {string|object} locator located by CSS|XPath|strict locator.
|
|
955
|
+
* {--end--}
|
|
956
|
+
* {{ react }}
|
|
886
957
|
*/
|
|
887
|
-
|
|
888
958
|
async seeElement(locator) {
|
|
889
959
|
let els = await this._locate(locator);
|
|
890
960
|
els = await Promise.all(els.map(el => el.boundingBox()));
|
|
@@ -893,8 +963,14 @@ I.seeElement('#modal');
|
|
|
893
963
|
|
|
894
964
|
/**
|
|
895
965
|
* Opposite to `seeElement`. Checks that element is not visible (or in DOM)
|
|
896
|
-
|
|
897
|
-
|
|
966
|
+
*
|
|
967
|
+
* ```js
|
|
968
|
+
* I.dontSeeElement('.modal'); // modal is not shown
|
|
969
|
+
* ```
|
|
970
|
+
*
|
|
971
|
+
* @param {string|object} locator located by CSS|XPath|Strict locator.
|
|
972
|
+
* {--end--}
|
|
973
|
+
* {{ react }}
|
|
898
974
|
*/
|
|
899
975
|
async dontSeeElement(locator) {
|
|
900
976
|
let els = await this._locate(locator);
|
|
@@ -904,12 +980,13 @@ I.seeElement('#modal');
|
|
|
904
980
|
|
|
905
981
|
/**
|
|
906
982
|
* Checks that a given Element is present in the DOM
|
|
907
|
-
Element is located by CSS or XPath.
|
|
908
|
-
|
|
909
|
-
```js
|
|
910
|
-
I.seeElementInDOM('#modal');
|
|
911
|
-
```
|
|
912
|
-
@param locator located by CSS|XPath|strict locator.
|
|
983
|
+
* Element is located by CSS or XPath.
|
|
984
|
+
*
|
|
985
|
+
* ```js
|
|
986
|
+
* I.seeElementInDOM('#modal');
|
|
987
|
+
* ```
|
|
988
|
+
* @param {string|object} locator element located by CSS|XPath|strict locator.
|
|
989
|
+
* {--end--}
|
|
913
990
|
*/
|
|
914
991
|
async seeElementInDOM(locator) {
|
|
915
992
|
const els = await this._locate(locator);
|
|
@@ -918,8 +995,13 @@ I.seeElementInDOM('#modal');
|
|
|
918
995
|
|
|
919
996
|
/**
|
|
920
997
|
* Opposite to `seeElementInDOM`. Checks that element is not on page.
|
|
921
|
-
|
|
922
|
-
|
|
998
|
+
*
|
|
999
|
+
* ```js
|
|
1000
|
+
* I.dontSeeElementInDOM('.nav'); // checks that element is not on page visible or not
|
|
1001
|
+
* ```
|
|
1002
|
+
*
|
|
1003
|
+
* @param {string|object} locator located by CSS|XPath|Strict locator.
|
|
1004
|
+
* {--end--}
|
|
923
1005
|
*/
|
|
924
1006
|
async dontSeeElementInDOM(locator) {
|
|
925
1007
|
const els = await this._locate(locator);
|
|
@@ -928,29 +1010,32 @@ I.seeElementInDOM('#modal');
|
|
|
928
1010
|
|
|
929
1011
|
/**
|
|
930
1012
|
* Perform a click on a link or a button, given by a locator.
|
|
931
|
-
If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string.
|
|
932
|
-
For buttons, the "value" attribute, "name" attribute, and inner text are searched. For links, the link text is searched.
|
|
933
|
-
For images, the "alt" attribute and inner text of any parent links are searched.
|
|
934
|
-
|
|
935
|
-
The second parameter is a context (CSS or XPath locator) to narrow the search.
|
|
936
|
-
|
|
937
|
-
```js
|
|
938
|
-
// simple link
|
|
939
|
-
I.click('Logout');
|
|
940
|
-
// button of form
|
|
941
|
-
I.click('Submit');
|
|
942
|
-
// CSS button
|
|
943
|
-
I.click('#form input[type=submit]');
|
|
944
|
-
// XPath
|
|
945
|
-
I.click('//form/*[@type=submit]');
|
|
946
|
-
// link in context
|
|
947
|
-
I.click('Logout', '#nav');
|
|
948
|
-
// using strict locator
|
|
949
|
-
I.click({css: 'nav a.login'});
|
|
950
|
-
```
|
|
951
|
-
|
|
952
|
-
@param locator clickable link or button located by text, or any element located by CSS|XPath|strict locator.
|
|
953
|
-
@param context (optional) element to search in CSS|XPath|Strict locator.
|
|
1013
|
+
* If a fuzzy locator is given, the page will be searched for a button, link, or image matching the locator string.
|
|
1014
|
+
* For buttons, the "value" attribute, "name" attribute, and inner text are searched. For links, the link text is searched.
|
|
1015
|
+
* For images, the "alt" attribute and inner text of any parent links are searched.
|
|
1016
|
+
*
|
|
1017
|
+
* The second parameter is a context (CSS or XPath locator) to narrow the search.
|
|
1018
|
+
*
|
|
1019
|
+
* ```js
|
|
1020
|
+
* // simple link
|
|
1021
|
+
* I.click('Logout');
|
|
1022
|
+
* // button of form
|
|
1023
|
+
* I.click('Submit');
|
|
1024
|
+
* // CSS button
|
|
1025
|
+
* I.click('#form input[type=submit]');
|
|
1026
|
+
* // XPath
|
|
1027
|
+
* I.click('//form/*[@type=submit]');
|
|
1028
|
+
* // link in context
|
|
1029
|
+
* I.click('Logout', '#nav');
|
|
1030
|
+
* // using strict locator
|
|
1031
|
+
* I.click({css: 'nav a.login'});
|
|
1032
|
+
* ```
|
|
1033
|
+
*
|
|
1034
|
+
* @param {string|object} locator clickable link or button located by text, or any element located by CSS|XPath|strict locator.
|
|
1035
|
+
* @param {string|object} context (optional, `null` by default) element to search in CSS|XPath|Strict locator.
|
|
1036
|
+
* {--end--}
|
|
1037
|
+
*
|
|
1038
|
+
* {{ react }}
|
|
954
1039
|
*/
|
|
955
1040
|
async click(locator, context = null) {
|
|
956
1041
|
return proceedClick.call(this, locator, context);
|
|
@@ -958,45 +1043,74 @@ I.click({css: 'nav a.login'});
|
|
|
958
1043
|
|
|
959
1044
|
/**
|
|
960
1045
|
* Performs a click on a link and waits for navigation before moving on.
|
|
961
|
-
|
|
962
|
-
```js
|
|
963
|
-
I.
|
|
964
|
-
```
|
|
965
|
-
@param locator clickable link or button located by text, or any element located by CSS|XPath|strict locator
|
|
966
|
-
@param context (optional) element to search in CSS|XPath|Strict locator
|
|
1046
|
+
*
|
|
1047
|
+
* ```js
|
|
1048
|
+
* I.clickLink('Logout', '#nav');
|
|
1049
|
+
* ```
|
|
1050
|
+
* @param {string|object} locator clickable link or button located by text, or any element located by CSS|XPath|strict locator
|
|
1051
|
+
* @param {string|object} context (optional, `null` by default) element to search in CSS|XPath|Strict locator
|
|
1052
|
+
* {--end--}
|
|
1053
|
+
*
|
|
1054
|
+
* {{ react }}
|
|
967
1055
|
*/
|
|
968
1056
|
async clickLink(locator, context = null) {
|
|
969
1057
|
return proceedClick.call(this, locator, context, { waitForNavigation: true });
|
|
970
1058
|
}
|
|
971
1059
|
|
|
972
1060
|
/**
|
|
973
|
-
*
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1061
|
+
* Sets a directory to where save files. Allows to test file downloads.
|
|
1062
|
+
* Should be used with [FileSystem helper](https://codecept.io/helpers/FileSystem) to check that file were downloaded correctly.
|
|
1063
|
+
*
|
|
1064
|
+
* By default files are saved to `output/downloads`.
|
|
1065
|
+
* This directory is cleaned on every `handleDownloads` call, to ensure no old files are kept.
|
|
1066
|
+
*
|
|
1067
|
+
* ```js
|
|
1068
|
+
* I.handleDownloads();
|
|
1069
|
+
* I.click('Download Avatar');
|
|
1070
|
+
* I.amInPath('output/downloads');
|
|
1071
|
+
* I.seeFile('avatar.jpg');
|
|
1072
|
+
*
|
|
1073
|
+
* ```
|
|
1074
|
+
*
|
|
1075
|
+
* @param {string} [downloadPath='downloads'] change this parameter to set another directory for saving
|
|
1076
|
+
*/
|
|
1077
|
+
async handleDownloads(downloadPath = 'downloads') {
|
|
1078
|
+
downloadPath = path.join(global.output_dir, downloadPath);
|
|
1079
|
+
if (!fs.existsSync(downloadPath)) {
|
|
1080
|
+
fs.mkdirSync(downloadPath, '0777');
|
|
1081
|
+
}
|
|
1082
|
+
fsExtra.emptyDirSync(downloadPath);
|
|
1083
|
+
return this.page._client.send('Page.setDownloadBehavior', { behavior: 'allow', downloadPath });
|
|
1084
|
+
}
|
|
981
1085
|
|
|
982
|
-
|
|
983
|
-
|
|
1086
|
+
/**
|
|
1087
|
+
* This method is **depreacted**.
|
|
1088
|
+
*
|
|
1089
|
+
* Please use `handleDownloads()` instead.
|
|
984
1090
|
*/
|
|
985
1091
|
async downloadFile(locator, customName) {
|
|
986
1092
|
let fileName;
|
|
987
1093
|
await this.page.setRequestInterception(true);
|
|
988
|
-
this.click(locator);
|
|
989
1094
|
|
|
990
1095
|
const xRequest = await new Promise((resolve) => {
|
|
991
1096
|
this.page.on('request', (request) => {
|
|
1097
|
+
console.log('rq', request, customName);
|
|
992
1098
|
const grabbedFileName = request.url().split('/')[request.url().split('/').length - 1];
|
|
993
1099
|
const fileExtension = request.url().split('/')[request.url().split('/').length - 1].split('.')[1];
|
|
1100
|
+
console.log('nm', customName, fileExtension);
|
|
1101
|
+
if (customName && path.extname(customName) !== fileExtension) {
|
|
1102
|
+
console.log('bypassing a request');
|
|
1103
|
+
request.continue();
|
|
1104
|
+
return;
|
|
1105
|
+
}
|
|
994
1106
|
customName ? fileName = `${customName}.${fileExtension}` : fileName = grabbedFileName;
|
|
995
1107
|
request.abort();
|
|
996
1108
|
resolve(request);
|
|
997
1109
|
});
|
|
998
1110
|
});
|
|
999
1111
|
|
|
1112
|
+
await this.click(locator);
|
|
1113
|
+
|
|
1000
1114
|
const options = {
|
|
1001
1115
|
encoding: null,
|
|
1002
1116
|
method: xRequest._method,
|
|
@@ -1009,14 +1123,21 @@ I.downloadFile('td[class="text-right file-link"] a', 'thisIsCustomName');
|
|
|
1009
1123
|
options.headers.Cookie = cookies.map(ck => `${ck.name}=${ck.value}`).join(';');
|
|
1010
1124
|
|
|
1011
1125
|
const response = await axios({
|
|
1012
|
-
method: options.method,
|
|
1126
|
+
method: options.method,
|
|
1127
|
+
url: options.uri,
|
|
1128
|
+
headers: options.headers,
|
|
1129
|
+
responseType: 'arraybuffer',
|
|
1130
|
+
onDownloadProgress(e) {
|
|
1131
|
+
console.log('+', e);
|
|
1132
|
+
},
|
|
1013
1133
|
});
|
|
1014
1134
|
|
|
1015
1135
|
const outputFile = path.join(`${global.output_dir}/${fileName}`);
|
|
1016
1136
|
|
|
1017
1137
|
try {
|
|
1018
|
-
|
|
1138
|
+
await new Promise((resolve, reject) => {
|
|
1019
1139
|
const wstream = fs.createWriteStream(outputFile);
|
|
1140
|
+
console.log(response);
|
|
1020
1141
|
wstream.write(response.data);
|
|
1021
1142
|
wstream.end();
|
|
1022
1143
|
this.debug(`File is downloaded in ${outputFile}`);
|
|
@@ -1030,17 +1151,20 @@ I.downloadFile('td[class="text-right file-link"] a', 'thisIsCustomName');
|
|
|
1030
1151
|
|
|
1031
1152
|
/**
|
|
1032
1153
|
* Performs a double-click on an element matched by link|button|label|CSS or XPath.
|
|
1033
|
-
Context can be specified as second parameter to narrow search.
|
|
1034
|
-
|
|
1035
|
-
```js
|
|
1036
|
-
I.doubleClick('Edit');
|
|
1037
|
-
I.doubleClick('Edit', '.actions');
|
|
1038
|
-
I.doubleClick({css: 'button.accept'});
|
|
1039
|
-
I.doubleClick('.btn.edit');
|
|
1040
|
-
```
|
|
1041
|
-
|
|
1042
|
-
@param locator clickable link or button located by text, or any element located by CSS|XPath|strict locator.
|
|
1043
|
-
@param context (optional) element to search in CSS|XPath|Strict locator.
|
|
1154
|
+
* Context can be specified as second parameter to narrow search.
|
|
1155
|
+
*
|
|
1156
|
+
* ```js
|
|
1157
|
+
* I.doubleClick('Edit');
|
|
1158
|
+
* I.doubleClick('Edit', '.actions');
|
|
1159
|
+
* I.doubleClick({css: 'button.accept'});
|
|
1160
|
+
* I.doubleClick('.btn.edit');
|
|
1161
|
+
* ```
|
|
1162
|
+
*
|
|
1163
|
+
* @param {string|object} locator clickable link or button located by text, or any element located by CSS|XPath|strict locator.
|
|
1164
|
+
* @param {string|object} context (optional, `null` by default) element to search in CSS|XPath|Strict locator.
|
|
1165
|
+
* {--end--}
|
|
1166
|
+
*
|
|
1167
|
+
* {{ react }}
|
|
1044
1168
|
*/
|
|
1045
1169
|
async doubleClick(locator, context = null) {
|
|
1046
1170
|
return proceedClick.call(this, locator, context, { clickCount: 2 });
|
|
@@ -1048,19 +1172,21 @@ I.doubleClick('.btn.edit');
|
|
|
1048
1172
|
|
|
1049
1173
|
/**
|
|
1050
1174
|
* Performs right click on a clickable element matched by semantic locator, CSS or XPath.
|
|
1051
|
-
|
|
1052
|
-
```js
|
|
1053
|
-
// right click element with id el
|
|
1054
|
-
I.rightClick('#el');
|
|
1055
|
-
// right click link or button with text "Click me"
|
|
1056
|
-
I.rightClick('Click me');
|
|
1057
|
-
// right click button with text "Click me" inside .context
|
|
1058
|
-
I.rightClick('Click me', '.context');
|
|
1059
|
-
```
|
|
1060
|
-
|
|
1061
|
-
@param locator clickable element located by CSS|XPath|strict locator.
|
|
1062
|
-
@param context (optional) element located by CSS|XPath|strict locator.
|
|
1063
|
-
|
|
1175
|
+
*
|
|
1176
|
+
* ```js
|
|
1177
|
+
* // right click element with id el
|
|
1178
|
+
* I.rightClick('#el');
|
|
1179
|
+
* // right click link or button with text "Click me"
|
|
1180
|
+
* I.rightClick('Click me');
|
|
1181
|
+
* // right click button with text "Click me" inside .context
|
|
1182
|
+
* I.rightClick('Click me', '.context');
|
|
1183
|
+
* ```
|
|
1184
|
+
*
|
|
1185
|
+
* @param {string|object} locator clickable element located by CSS|XPath|strict locator.
|
|
1186
|
+
* @param {string|object} context (optional, `null` by default) element located by CSS|XPath|strict locator.
|
|
1187
|
+
* {--end--}
|
|
1188
|
+
*
|
|
1189
|
+
* {{ react }}
|
|
1064
1190
|
*/
|
|
1065
1191
|
async rightClick(locator, context = null) {
|
|
1066
1192
|
return proceedClick.call(this, locator, context, { button: 'right' });
|
|
@@ -1068,17 +1194,18 @@ I.rightClick('Click me', '.context');
|
|
|
1068
1194
|
|
|
1069
1195
|
/**
|
|
1070
1196
|
* Selects a checkbox or radio button.
|
|
1071
|
-
Element is located by label or name or CSS or XPath.
|
|
1072
|
-
|
|
1073
|
-
The second parameter is a context (CSS or XPath locator) to narrow the search.
|
|
1074
|
-
|
|
1075
|
-
```js
|
|
1076
|
-
I.checkOption('#agree');
|
|
1077
|
-
I.checkOption('I Agree to Terms and Conditions');
|
|
1078
|
-
I.checkOption('agree', '//form');
|
|
1079
|
-
```
|
|
1080
|
-
@param field checkbox located by label | name | CSS | XPath | strict locator.
|
|
1081
|
-
@param context (optional) element located by CSS | XPath | strict locator.
|
|
1197
|
+
* Element is located by label or name or CSS or XPath.
|
|
1198
|
+
*
|
|
1199
|
+
* The second parameter is a context (CSS or XPath locator) to narrow the search.
|
|
1200
|
+
*
|
|
1201
|
+
* ```js
|
|
1202
|
+
* I.checkOption('#agree');
|
|
1203
|
+
* I.checkOption('I Agree to Terms and Conditions');
|
|
1204
|
+
* I.checkOption('agree', '//form');
|
|
1205
|
+
* ```
|
|
1206
|
+
* @param {string|object} field checkbox located by label | name | CSS | XPath | strict locator.
|
|
1207
|
+
* @param {string} context (optional, `null` by default) element located by CSS | XPath | strict locator.
|
|
1208
|
+
* {--end--}
|
|
1082
1209
|
*/
|
|
1083
1210
|
async checkOption(field, context = null) {
|
|
1084
1211
|
const elm = await this._locateCheckable(field, context);
|
|
@@ -1093,17 +1220,18 @@ I.checkOption('agree', '//form');
|
|
|
1093
1220
|
|
|
1094
1221
|
/**
|
|
1095
1222
|
* Unselects a checkbox or radio button.
|
|
1096
|
-
Element is located by label or name or CSS or XPath.
|
|
1097
|
-
|
|
1098
|
-
The second parameter is a context (CSS or XPath locator) to narrow the search.
|
|
1099
|
-
|
|
1100
|
-
```js
|
|
1101
|
-
I.uncheckOption('#agree');
|
|
1102
|
-
I.uncheckOption('I Agree to Terms and Conditions');
|
|
1103
|
-
I.uncheckOption('agree', '//form');
|
|
1104
|
-
```
|
|
1105
|
-
@param field checkbox located by label | name | CSS | XPath | strict locator.
|
|
1106
|
-
@param context (optional) element located by CSS | XPath | strict locator.
|
|
1223
|
+
* Element is located by label or name or CSS or XPath.
|
|
1224
|
+
*
|
|
1225
|
+
* The second parameter is a context (CSS or XPath locator) to narrow the search.
|
|
1226
|
+
*
|
|
1227
|
+
* ```js
|
|
1228
|
+
* I.uncheckOption('#agree');
|
|
1229
|
+
* I.uncheckOption('I Agree to Terms and Conditions');
|
|
1230
|
+
* I.uncheckOption('agree', '//form');
|
|
1231
|
+
* ```
|
|
1232
|
+
* @param {string|object} field checkbox located by label | name | CSS | XPath | strict locator.
|
|
1233
|
+
* @param {string} context (optional, `null` by default) element located by CSS | XPath | strict locator.
|
|
1234
|
+
* {--end--}
|
|
1107
1235
|
*/
|
|
1108
1236
|
async uncheckOption(field, context = null) {
|
|
1109
1237
|
const elm = await this._locateCheckable(field, context);
|
|
@@ -1118,13 +1246,15 @@ I.uncheckOption('agree', '//form');
|
|
|
1118
1246
|
|
|
1119
1247
|
/**
|
|
1120
1248
|
* Verifies that the specified checkbox is checked.
|
|
1121
|
-
|
|
1122
|
-
```js
|
|
1123
|
-
I.seeCheckboxIsChecked('Agree');
|
|
1124
|
-
I.seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms
|
|
1125
|
-
I.seeCheckboxIsChecked({css: '#signup_form input[type=checkbox]'});
|
|
1126
|
-
```
|
|
1127
|
-
|
|
1249
|
+
*
|
|
1250
|
+
* ```js
|
|
1251
|
+
* I.seeCheckboxIsChecked('Agree');
|
|
1252
|
+
* I.seeCheckboxIsChecked('#agree'); // I suppose user agreed to terms
|
|
1253
|
+
* I.seeCheckboxIsChecked({css: '#signup_form input[type=checkbox]'});
|
|
1254
|
+
* ```
|
|
1255
|
+
*
|
|
1256
|
+
* @param {string|object} field located by label|name|CSS|XPath|strict locator.
|
|
1257
|
+
* {--end--}
|
|
1128
1258
|
*/
|
|
1129
1259
|
async seeCheckboxIsChecked(field) {
|
|
1130
1260
|
return proceedIsChecked.call(this, 'assert', field);
|
|
@@ -1132,8 +1262,15 @@ I.seeCheckboxIsChecked({css: '#signup_form input[type=checkbox]'});
|
|
|
1132
1262
|
|
|
1133
1263
|
/**
|
|
1134
1264
|
* Verifies that the specified checkbox is not checked.
|
|
1135
|
-
|
|
1136
|
-
|
|
1265
|
+
*
|
|
1266
|
+
* ```js
|
|
1267
|
+
* I.dontSeeeCheckboxIsChedcked('#agree'); // located by ID
|
|
1268
|
+
* I.dontSeeeCheckboxIsChedcked('I agree to terms'); // located by label
|
|
1269
|
+
* I.dontSeeeCheckboxIsChedcked('agree'); // located by name
|
|
1270
|
+
* ```
|
|
1271
|
+
*
|
|
1272
|
+
* @param {string|object} field located by label|name|CSS|XPath|strict locator.
|
|
1273
|
+
* {--end--}
|
|
1137
1274
|
*/
|
|
1138
1275
|
async dontSeeCheckboxIsChecked(field) {
|
|
1139
1276
|
return proceedIsChecked.call(this, 'negate', field);
|
|
@@ -1141,16 +1278,19 @@ I.seeCheckboxIsChecked({css: '#signup_form input[type=checkbox]'});
|
|
|
1141
1278
|
|
|
1142
1279
|
/**
|
|
1143
1280
|
* Presses a key on a focused element.
|
|
1144
|
-
Special keys like 'Enter', 'Control', [etc](https://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/value)
|
|
1145
|
-
will be replaced with corresponding unicode.
|
|
1146
|
-
If modifier key is used (Control, Command, Alt, Shift) in array, it will be released afterwards.
|
|
1147
|
-
|
|
1148
|
-
```js
|
|
1149
|
-
I.pressKey('Enter');
|
|
1150
|
-
I.pressKey(['Control','a']);
|
|
1151
|
-
```
|
|
1152
|
-
|
|
1153
|
-
@param key key or array of keys to press.
|
|
1281
|
+
* Special keys like 'Enter', 'Control', [etc](https://code.google.com/p/selenium/wiki/JsonWireProtocol#/session/:sessionId/element/:id/value)
|
|
1282
|
+
* will be replaced with corresponding unicode.
|
|
1283
|
+
* If modifier key is used (Control, Command, Alt, Shift) in array, it will be released afterwards.
|
|
1284
|
+
*
|
|
1285
|
+
* ```js
|
|
1286
|
+
* I.pressKey('Enter');
|
|
1287
|
+
* I.pressKey(['Control','a']);
|
|
1288
|
+
* ```
|
|
1289
|
+
*
|
|
1290
|
+
* @param {string|array} key key or array of keys to press.
|
|
1291
|
+
* {--end--}
|
|
1292
|
+
*
|
|
1293
|
+
* {{ keys }}
|
|
1154
1294
|
*/
|
|
1155
1295
|
async pressKey(key) {
|
|
1156
1296
|
let modifier;
|
|
@@ -1167,21 +1307,22 @@ I.pressKey(['Control','a']);
|
|
|
1167
1307
|
|
|
1168
1308
|
/**
|
|
1169
1309
|
* Fills a text field or textarea, after clearing its value, with the given string.
|
|
1170
|
-
Field is located by name, label, CSS, or XPath.
|
|
1171
|
-
|
|
1172
|
-
```js
|
|
1173
|
-
// by label
|
|
1174
|
-
I.fillField('Email', 'hello@world.com');
|
|
1175
|
-
// by name
|
|
1176
|
-
I.fillField('password', secret('123456'));
|
|
1177
|
-
// by CSS
|
|
1178
|
-
I.fillField('form#login input[name=username]', 'John');
|
|
1179
|
-
// or by strict locator
|
|
1180
|
-
I.fillField({css: 'form#login input[name=username]'}, 'John');
|
|
1181
|
-
```
|
|
1182
|
-
@param field located by label|name|CSS|XPath|strict locator.
|
|
1183
|
-
@param value text value to fill.
|
|
1184
|
-
|
|
1310
|
+
* Field is located by name, label, CSS, or XPath.
|
|
1311
|
+
*
|
|
1312
|
+
* ```js
|
|
1313
|
+
* // by label
|
|
1314
|
+
* I.fillField('Email', 'hello@world.com');
|
|
1315
|
+
* // by name
|
|
1316
|
+
* I.fillField('password', secret('123456'));
|
|
1317
|
+
* // by CSS
|
|
1318
|
+
* I.fillField('form#login input[name=username]', 'John');
|
|
1319
|
+
* // or by strict locator
|
|
1320
|
+
* I.fillField({css: 'form#login input[name=username]'}, 'John');
|
|
1321
|
+
* ```
|
|
1322
|
+
* @param {string|object} field located by label|name|CSS|XPath|strict locator.
|
|
1323
|
+
* @param {string} value text value to fill.
|
|
1324
|
+
* {--end--}
|
|
1325
|
+
* {{ react }}
|
|
1185
1326
|
*/
|
|
1186
1327
|
async fillField(field, value) {
|
|
1187
1328
|
const els = await findFields.call(this, field);
|
|
@@ -1195,20 +1336,21 @@ I.fillField({css: 'form#login input[name=username]'}, 'John');
|
|
|
1195
1336
|
} else if (editable) {
|
|
1196
1337
|
await this._evaluateHandeInContext(el => el.innerHTML = '', el);
|
|
1197
1338
|
}
|
|
1198
|
-
await el.type(value.toString(), { delay:
|
|
1339
|
+
await el.type(value.toString(), { delay: this.options.pressKeyDelay });
|
|
1199
1340
|
return this._waitForAction();
|
|
1200
1341
|
}
|
|
1201
1342
|
|
|
1202
1343
|
|
|
1203
1344
|
/**
|
|
1204
1345
|
* Clears a `<textarea>` or text `<input>` element's value.
|
|
1205
|
-
|
|
1206
|
-
```js
|
|
1207
|
-
I.clearField('Email');
|
|
1208
|
-
I.clearField('user[email]');
|
|
1209
|
-
I.clearField('#email');
|
|
1210
|
-
```
|
|
1211
|
-
@param field located by label|name|CSS|XPath|strict locator.
|
|
1346
|
+
*
|
|
1347
|
+
* ```js
|
|
1348
|
+
* I.clearField('Email');
|
|
1349
|
+
* I.clearField('user[email]');
|
|
1350
|
+
* I.clearField('#email');
|
|
1351
|
+
* ```
|
|
1352
|
+
* @param {string|object} editable field located by label|name|CSS|XPath|strict locator.
|
|
1353
|
+
* {--end--}
|
|
1212
1354
|
*/
|
|
1213
1355
|
async clearField(field) {
|
|
1214
1356
|
return this.fillField(field, '');
|
|
@@ -1216,34 +1358,38 @@ I.clearField('#email');
|
|
|
1216
1358
|
|
|
1217
1359
|
/**
|
|
1218
1360
|
* Appends text to a input field or textarea.
|
|
1219
|
-
Field is located by name, label, CSS or XPath
|
|
1220
|
-
|
|
1221
|
-
```js
|
|
1222
|
-
I.appendField('#myTextField', 'appended');
|
|
1223
|
-
```
|
|
1224
|
-
@param field located by label|name|CSS|XPath|strict locator
|
|
1225
|
-
@param value text value to append.
|
|
1361
|
+
* Field is located by name, label, CSS or XPath
|
|
1362
|
+
*
|
|
1363
|
+
* ```js
|
|
1364
|
+
* I.appendField('#myTextField', 'appended');
|
|
1365
|
+
* ```
|
|
1366
|
+
* @param {string|object} field located by label|name|CSS|XPath|strict locator
|
|
1367
|
+
* @param {string} value text value to append.
|
|
1368
|
+
* {--end--}
|
|
1369
|
+
*
|
|
1370
|
+
* {{ react }}
|
|
1226
1371
|
*/
|
|
1227
1372
|
async appendField(field, value) {
|
|
1228
1373
|
const els = await findFields.call(this, field);
|
|
1229
1374
|
assertElementExists(els, field, 'Field');
|
|
1230
1375
|
await els[0].press('End');
|
|
1231
|
-
await els[0].type(value, { delay:
|
|
1376
|
+
await els[0].type(value, { delay: this.options.pressKeyDelay });
|
|
1232
1377
|
return this._waitForAction();
|
|
1233
1378
|
}
|
|
1234
1379
|
|
|
1235
1380
|
/**
|
|
1236
1381
|
* Checks that the given input field or textarea equals to given value.
|
|
1237
|
-
For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and XPath.
|
|
1238
|
-
|
|
1239
|
-
```js
|
|
1240
|
-
I.seeInField('Username', 'davert');
|
|
1241
|
-
I.seeInField({css: 'form textarea'},'Type your comment here');
|
|
1242
|
-
I.seeInField('form input[type=hidden]','hidden_value');
|
|
1243
|
-
I.seeInField('#searchform input','Search');
|
|
1244
|
-
```
|
|
1245
|
-
@param field located by label|name|CSS|XPath|strict locator.
|
|
1246
|
-
@param value value to check.
|
|
1382
|
+
* For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and XPath.
|
|
1383
|
+
*
|
|
1384
|
+
* ```js
|
|
1385
|
+
* I.seeInField('Username', 'davert');
|
|
1386
|
+
* I.seeInField({css: 'form textarea'},'Type your comment here');
|
|
1387
|
+
* I.seeInField('form input[type=hidden]','hidden_value');
|
|
1388
|
+
* I.seeInField('#searchform input','Search');
|
|
1389
|
+
* ```
|
|
1390
|
+
* @param {string|object} field located by label|name|CSS|XPath|strict locator.
|
|
1391
|
+
* @param {string} value value to check.
|
|
1392
|
+
* {--end--}
|
|
1247
1393
|
*/
|
|
1248
1394
|
async seeInField(field, value) {
|
|
1249
1395
|
return proceedSeeInField.call(this, 'assert', field, value);
|
|
@@ -1251,10 +1397,16 @@ I.seeInField('#searchform input','Search');
|
|
|
1251
1397
|
|
|
1252
1398
|
/**
|
|
1253
1399
|
* Checks that value of input field or textare doesn't equal to given value
|
|
1254
|
-
Opposite to `seeInField`.
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
@
|
|
1400
|
+
* Opposite to `seeInField`.
|
|
1401
|
+
*
|
|
1402
|
+
* ```js
|
|
1403
|
+
* I.dontSeeInField('email', 'user@user.com'); // field by name
|
|
1404
|
+
* I.dontSeeInField({ css: 'form input.email' }, 'user@user.com'); // field by CSS
|
|
1405
|
+
* ```
|
|
1406
|
+
*
|
|
1407
|
+
* @param {string|object} field located by label|name|CSS|XPath|strict locator.
|
|
1408
|
+
* @param {string} value value to check.
|
|
1409
|
+
* {--end--}
|
|
1258
1410
|
*/
|
|
1259
1411
|
async dontSeeInField(field, value) {
|
|
1260
1412
|
return proceedSeeInField.call(this, 'negate', field, value);
|
|
@@ -1263,17 +1415,17 @@ Opposite to `seeInField`.
|
|
|
1263
1415
|
|
|
1264
1416
|
/**
|
|
1265
1417
|
* Attaches a file to element located by label, name, CSS or XPath
|
|
1266
|
-
Path to file is relative current codecept directory (where codecept.json or codecept.conf.js is located).
|
|
1267
|
-
File will be uploaded to remote system (if tests are running remotely).
|
|
1268
|
-
|
|
1269
|
-
```js
|
|
1270
|
-
I.attachFile('Avatar', 'data/avatar.jpg');
|
|
1271
|
-
I.attachFile('form input[name=avatar]', 'data/avatar.jpg');
|
|
1272
|
-
```
|
|
1273
|
-
|
|
1274
|
-
@param locator field located by label|name|CSS|XPath|strict locator.
|
|
1275
|
-
@param pathToFile local file path relative to codecept.json config file.
|
|
1276
|
-
*
|
|
1418
|
+
* Path to file is relative current codecept directory (where codecept.json or codecept.conf.js is located).
|
|
1419
|
+
* File will be uploaded to remote system (if tests are running remotely).
|
|
1420
|
+
*
|
|
1421
|
+
* ```js
|
|
1422
|
+
* I.attachFile('Avatar', 'data/avatar.jpg');
|
|
1423
|
+
* I.attachFile('form input[name=avatar]', 'data/avatar.jpg');
|
|
1424
|
+
* ```
|
|
1425
|
+
*
|
|
1426
|
+
* @param {string|object} locator field located by label|name|CSS|XPath|strict locator.
|
|
1427
|
+
* @param {string} pathToFile local file path relative to codecept.json config file.
|
|
1428
|
+
* {--end--}
|
|
1277
1429
|
*/
|
|
1278
1430
|
async attachFile(locator, pathToFile) {
|
|
1279
1431
|
const file = path.join(global.codecept_dir, pathToFile);
|
|
@@ -1289,25 +1441,26 @@ I.attachFile('form input[name=avatar]', 'data/avatar.jpg');
|
|
|
1289
1441
|
|
|
1290
1442
|
/**
|
|
1291
1443
|
* Selects an option in a drop-down select.
|
|
1292
|
-
Field is searched by label | name | CSS | XPath.
|
|
1293
|
-
Option is selected by visible text or by value.
|
|
1294
|
-
|
|
1295
|
-
```js
|
|
1296
|
-
I.selectOption('Choose Plan', 'Monthly'); // select by label
|
|
1297
|
-
I.selectOption('subscription', 'Monthly'); // match option by text
|
|
1298
|
-
I.selectOption('subscription', '0'); // or by value
|
|
1299
|
-
I.selectOption('//form/select[@name=account]','Premium');
|
|
1300
|
-
I.selectOption('form select[name=account]', 'Premium');
|
|
1301
|
-
I.selectOption({css: 'form select[name=account]'}, 'Premium');
|
|
1302
|
-
```
|
|
1303
|
-
|
|
1304
|
-
Provide an array for the second argument to select multiple options.
|
|
1305
|
-
|
|
1306
|
-
```js
|
|
1307
|
-
I.selectOption('Which OS do you use?', ['Android', 'iOS']);
|
|
1308
|
-
```
|
|
1309
|
-
@param select field located by label|name|CSS|XPath|strict locator.
|
|
1310
|
-
@param option visible text or value of option.
|
|
1444
|
+
* Field is searched by label | name | CSS | XPath.
|
|
1445
|
+
* Option is selected by visible text or by value.
|
|
1446
|
+
*
|
|
1447
|
+
* ```js
|
|
1448
|
+
* I.selectOption('Choose Plan', 'Monthly'); // select by label
|
|
1449
|
+
* I.selectOption('subscription', 'Monthly'); // match option by text
|
|
1450
|
+
* I.selectOption('subscription', '0'); // or by value
|
|
1451
|
+
* I.selectOption('//form/select[@name=account]','Premium');
|
|
1452
|
+
* I.selectOption('form select[name=account]', 'Premium');
|
|
1453
|
+
* I.selectOption({css: 'form select[name=account]'}, 'Premium');
|
|
1454
|
+
* ```
|
|
1455
|
+
*
|
|
1456
|
+
* Provide an array for the second argument to select multiple options.
|
|
1457
|
+
*
|
|
1458
|
+
* ```js
|
|
1459
|
+
* I.selectOption('Which OS do you use?', ['Android', 'iOS']);
|
|
1460
|
+
* ```
|
|
1461
|
+
* @param {string|object} select field located by label|name|CSS|XPath|strict locator.
|
|
1462
|
+
* @param {string|array} option visible text or value of option.
|
|
1463
|
+
* {--end--}
|
|
1311
1464
|
*/
|
|
1312
1465
|
async selectOption(select, option) {
|
|
1313
1466
|
const els = await findFields.call(this, select);
|
|
@@ -1340,12 +1493,15 @@ I.selectOption('Which OS do you use?', ['Android', 'iOS']);
|
|
|
1340
1493
|
|
|
1341
1494
|
/**
|
|
1342
1495
|
* Grab number of visible elements by locator.
|
|
1343
|
-
|
|
1344
|
-
```js
|
|
1345
|
-
I.grabNumberOfVisibleElements('p');
|
|
1346
|
-
```
|
|
1347
|
-
|
|
1348
|
-
@param locator located by CSS|XPath|strict locator.
|
|
1496
|
+
*
|
|
1497
|
+
* ```js
|
|
1498
|
+
* let numOfElements = await I.grabNumberOfVisibleElements('p');
|
|
1499
|
+
* ```
|
|
1500
|
+
*
|
|
1501
|
+
* @param {string|object} locator located by CSS|XPath|strict locator.
|
|
1502
|
+
* @returns {Promise<number>} number of visible elements
|
|
1503
|
+
* {--end--}
|
|
1504
|
+
* {{ react }}
|
|
1349
1505
|
*/
|
|
1350
1506
|
async grabNumberOfVisibleElements(locator) {
|
|
1351
1507
|
let els = await this._locate(locator);
|
|
@@ -1355,12 +1511,13 @@ I.grabNumberOfVisibleElements('p');
|
|
|
1355
1511
|
|
|
1356
1512
|
/**
|
|
1357
1513
|
* Checks that current url contains a provided fragment.
|
|
1358
|
-
|
|
1359
|
-
```js
|
|
1360
|
-
I.seeInCurrentUrl('/register'); // we are on registration page
|
|
1361
|
-
```
|
|
1362
|
-
|
|
1363
|
-
@param url
|
|
1514
|
+
*
|
|
1515
|
+
* ```js
|
|
1516
|
+
* I.seeInCurrentUrl('/register'); // we are on registration page
|
|
1517
|
+
* ```
|
|
1518
|
+
*
|
|
1519
|
+
* @param {string} url a fragment to check
|
|
1520
|
+
* {--end--}
|
|
1364
1521
|
*/
|
|
1365
1522
|
async seeInCurrentUrl(url) {
|
|
1366
1523
|
stringIncludes('url').assert(url, await this._getPageUrl());
|
|
@@ -1368,8 +1525,9 @@ I.seeInCurrentUrl('/register'); // we are on registration page
|
|
|
1368
1525
|
|
|
1369
1526
|
/**
|
|
1370
1527
|
* Checks that current url does not contain a provided fragment.
|
|
1371
|
-
|
|
1372
|
-
@param url value to check.
|
|
1528
|
+
*
|
|
1529
|
+
* @param {string} url value to check.
|
|
1530
|
+
* {--end--}
|
|
1373
1531
|
*/
|
|
1374
1532
|
async dontSeeInCurrentUrl(url) {
|
|
1375
1533
|
stringIncludes('url').negate(url, await this._getPageUrl());
|
|
@@ -1377,15 +1535,16 @@ I.seeInCurrentUrl('/register'); // we are on registration page
|
|
|
1377
1535
|
|
|
1378
1536
|
/**
|
|
1379
1537
|
* Checks that current url is equal to provided one.
|
|
1380
|
-
If a relative url provided, a configured url will be prepended to it.
|
|
1381
|
-
So both examples will work:
|
|
1382
|
-
|
|
1383
|
-
```js
|
|
1384
|
-
I.seeCurrentUrlEquals('/register');
|
|
1385
|
-
I.seeCurrentUrlEquals('http://my.site.com/register');
|
|
1386
|
-
```
|
|
1387
|
-
|
|
1388
|
-
@param url value to check.
|
|
1538
|
+
* If a relative url provided, a configured url will be prepended to it.
|
|
1539
|
+
* So both examples will work:
|
|
1540
|
+
*
|
|
1541
|
+
* ```js
|
|
1542
|
+
* I.seeCurrentUrlEquals('/register');
|
|
1543
|
+
* I.seeCurrentUrlEquals('http://my.site.com/register');
|
|
1544
|
+
* ```
|
|
1545
|
+
*
|
|
1546
|
+
* @param {string} url value to check.
|
|
1547
|
+
* {--end--}
|
|
1389
1548
|
*/
|
|
1390
1549
|
async seeCurrentUrlEquals(url) {
|
|
1391
1550
|
urlEquals(this.options.url).assert(url, await this._getPageUrl());
|
|
@@ -1393,9 +1552,15 @@ I.seeCurrentUrlEquals('http://my.site.com/register');
|
|
|
1393
1552
|
|
|
1394
1553
|
/**
|
|
1395
1554
|
* Checks that current url is not equal to provided one.
|
|
1396
|
-
If a relative url provided, a configured url will be prepended to it.
|
|
1397
|
-
|
|
1398
|
-
|
|
1555
|
+
* If a relative url provided, a configured url will be prepended to it.
|
|
1556
|
+
*
|
|
1557
|
+
* ```js
|
|
1558
|
+
* I.dontSeeCurrentUrlEquals('/login'); // relative url are ok
|
|
1559
|
+
* I.dontSeeCurrentUrlEquals('http://mysite.com/login'); // absolute urls are also ok
|
|
1560
|
+
* ```
|
|
1561
|
+
*
|
|
1562
|
+
* @param {string} url value to check.
|
|
1563
|
+
* {--end--}
|
|
1399
1564
|
*/
|
|
1400
1565
|
async dontSeeCurrentUrlEquals(url) {
|
|
1401
1566
|
urlEquals(this.options.url).negate(url, await this._getPageUrl());
|
|
@@ -1403,15 +1568,18 @@ If a relative url provided, a configured url will be prepended to it.
|
|
|
1403
1568
|
|
|
1404
1569
|
/**
|
|
1405
1570
|
* Checks that a page contains a visible text.
|
|
1406
|
-
Use context parameter to narrow down the search.
|
|
1407
|
-
|
|
1408
|
-
```js
|
|
1409
|
-
I.see('Welcome'); // text welcome on a page
|
|
1410
|
-
I.see('Welcome', '.content'); // text inside .content div
|
|
1411
|
-
I.see('Register', {css: 'form.register'}); // use strict locator
|
|
1412
|
-
```
|
|
1413
|
-
@param text expected on page.
|
|
1414
|
-
@param context (optional) element located by CSS|Xpath|strict locator in which to search for text.
|
|
1571
|
+
* Use context parameter to narrow down the search.
|
|
1572
|
+
*
|
|
1573
|
+
* ```js
|
|
1574
|
+
* I.see('Welcome'); // text welcome on a page
|
|
1575
|
+
* I.see('Welcome', '.content'); // text inside .content div
|
|
1576
|
+
* I.see('Register', {css: 'form.register'}); // use strict locator
|
|
1577
|
+
* ```
|
|
1578
|
+
* @param {string} text expected on page.
|
|
1579
|
+
* @param {string|object} context (optional, `null` by default) element located by CSS|Xpath|strict locator in which to search for text.
|
|
1580
|
+
* {--end--}
|
|
1581
|
+
*
|
|
1582
|
+
* {{ react }}
|
|
1415
1583
|
*/
|
|
1416
1584
|
async see(text, context = null) {
|
|
1417
1585
|
return proceedSee.call(this, 'assert', text, context);
|
|
@@ -1430,13 +1598,19 @@ I.see('Register', {css: 'form.register'}); // use strict locator
|
|
|
1430
1598
|
|
|
1431
1599
|
/**
|
|
1432
1600
|
* Opposite to `see`. Checks that a text is not present on a page.
|
|
1433
|
-
Use context parameter to narrow down the search.
|
|
1434
|
-
|
|
1435
|
-
```js
|
|
1436
|
-
I.dontSee('Login'); // assume we are already logged in
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1601
|
+
* Use context parameter to narrow down the search.
|
|
1602
|
+
*
|
|
1603
|
+
* ```js
|
|
1604
|
+
* I.dontSee('Login'); // assume we are already logged in.
|
|
1605
|
+
* I.dontSee('Login', '.nav'); // no login inside .nav element
|
|
1606
|
+
* ```
|
|
1607
|
+
*
|
|
1608
|
+
* @param {string} text which is not present.
|
|
1609
|
+
* @param {string|object} context (optional) element located by CSS|XPath|strict locator in which to perfrom search.
|
|
1610
|
+
*
|
|
1611
|
+
* {--end--}
|
|
1612
|
+
*
|
|
1613
|
+
* {{ react }}
|
|
1440
1614
|
*/
|
|
1441
1615
|
async dontSee(text, context = null) {
|
|
1442
1616
|
return proceedSee.call(this, 'negate', text, context);
|
|
@@ -1444,11 +1618,14 @@ I.dontSee('Login'); // assume we are already logged in
|
|
|
1444
1618
|
|
|
1445
1619
|
/**
|
|
1446
1620
|
* Retrieves page source and returns it to test.
|
|
1447
|
-
Resumes test execution, so should be used inside an async function.
|
|
1448
|
-
|
|
1449
|
-
```js
|
|
1450
|
-
let pageSource = await I.grabSource();
|
|
1451
|
-
```
|
|
1621
|
+
* Resumes test execution, so should be used inside an async function.
|
|
1622
|
+
*
|
|
1623
|
+
* ```js
|
|
1624
|
+
* let pageSource = await I.grabSource();
|
|
1625
|
+
* ```
|
|
1626
|
+
*
|
|
1627
|
+
* @returns {Promise<string>} source code
|
|
1628
|
+
* {--end--}
|
|
1452
1629
|
*/
|
|
1453
1630
|
async grabSource() {
|
|
1454
1631
|
return this.page.content();
|
|
@@ -1470,12 +1647,15 @@ let pageSource = await I.grabSource();
|
|
|
1470
1647
|
|
|
1471
1648
|
/**
|
|
1472
1649
|
* Get current URL from browser.
|
|
1473
|
-
Resumes test execution, so should be used inside an async function.
|
|
1474
|
-
|
|
1475
|
-
```js
|
|
1476
|
-
let url = await I.grabCurrentUrl();
|
|
1477
|
-
console.log(`Current URL is [${url}]`);
|
|
1478
|
-
```
|
|
1650
|
+
* Resumes test execution, so should be used inside an async function.
|
|
1651
|
+
*
|
|
1652
|
+
* ```js
|
|
1653
|
+
* let url = await I.grabCurrentUrl();
|
|
1654
|
+
* console.log(`Current URL is [${url}]`);
|
|
1655
|
+
* ```
|
|
1656
|
+
*
|
|
1657
|
+
* @returns {Promise<string>} current URL
|
|
1658
|
+
* {--end--}
|
|
1479
1659
|
*/
|
|
1480
1660
|
async grabCurrentUrl() {
|
|
1481
1661
|
return this._getPageUrl();
|
|
@@ -1483,11 +1663,12 @@ console.log(`Current URL is [${url}]`);
|
|
|
1483
1663
|
|
|
1484
1664
|
/**
|
|
1485
1665
|
* Checks that the current page contains the given string in its raw source code.
|
|
1486
|
-
|
|
1487
|
-
```js
|
|
1488
|
-
I.seeInSource('<h1>Green eggs & ham</h1>');
|
|
1489
|
-
```
|
|
1490
|
-
@param text value to check.
|
|
1666
|
+
*
|
|
1667
|
+
* ```js
|
|
1668
|
+
* I.seeInSource('<h1>Green eggs & ham</h1>');
|
|
1669
|
+
* ```
|
|
1670
|
+
* @param {string} text value to check.
|
|
1671
|
+
* {--end--}
|
|
1491
1672
|
*/
|
|
1492
1673
|
async seeInSource(text) {
|
|
1493
1674
|
const source = await this.page.content();
|
|
@@ -1496,9 +1677,13 @@ I.seeInSource('<h1>Green eggs & ham</h1>');
|
|
|
1496
1677
|
|
|
1497
1678
|
/**
|
|
1498
1679
|
* Checks that the current page does not contains the given string in its raw source code.
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1680
|
+
*
|
|
1681
|
+
* ```js
|
|
1682
|
+
* I.dontSeeInSource('<!--'); // no comments in source
|
|
1683
|
+
* ```
|
|
1684
|
+
*
|
|
1685
|
+
* @param {string} value to check.
|
|
1686
|
+
* {--end--}
|
|
1502
1687
|
*/
|
|
1503
1688
|
async dontSeeInSource(text) {
|
|
1504
1689
|
const source = await this.page.content();
|
|
@@ -1507,28 +1692,38 @@ I.seeInSource('<h1>Green eggs & ham</h1>');
|
|
|
1507
1692
|
|
|
1508
1693
|
|
|
1509
1694
|
/**
|
|
1510
|
-
*
|
|
1695
|
+
* Asserts that an element appears a given number of times in the DOM.
|
|
1511
1696
|
* Element is located by label or name or CSS or XPath.
|
|
1512
|
-
*
|
|
1697
|
+
*
|
|
1698
|
+
*
|
|
1513
1699
|
* ```js
|
|
1514
1700
|
* I.seeNumberOfElements('#submitBtn', 1);
|
|
1515
1701
|
* ```
|
|
1702
|
+
*
|
|
1703
|
+
* @param {string|object} locator element located by CSS|XPath|strict locator.
|
|
1704
|
+
* @param {number} num number of elements.
|
|
1705
|
+
* {--end--}
|
|
1706
|
+
*
|
|
1707
|
+
* {{ react }}
|
|
1516
1708
|
*/
|
|
1517
|
-
async seeNumberOfElements(
|
|
1518
|
-
const elements = await this._locate(
|
|
1519
|
-
return equals(`expected number of elements (${
|
|
1709
|
+
async seeNumberOfElements(locator, num) {
|
|
1710
|
+
const elements = await this._locate(locator);
|
|
1711
|
+
return equals(`expected number of elements (${locator}) is ${num}, but found ${elements.length}`).assert(elements.length, num);
|
|
1520
1712
|
}
|
|
1521
1713
|
|
|
1522
1714
|
/**
|
|
1523
1715
|
* Asserts that an element is visible a given number of times.
|
|
1524
|
-
Element is located by CSS or XPath.
|
|
1525
|
-
|
|
1526
|
-
```js
|
|
1527
|
-
I.seeNumberOfVisibleElements('.buttons', 3);
|
|
1528
|
-
```
|
|
1529
|
-
|
|
1530
|
-
@param locator element located by CSS|XPath|strict locator.
|
|
1531
|
-
@param num number of elements.
|
|
1716
|
+
* Element is located by CSS or XPath.
|
|
1717
|
+
*
|
|
1718
|
+
* ```js
|
|
1719
|
+
* I.seeNumberOfVisibleElements('.buttons', 3);
|
|
1720
|
+
* ```
|
|
1721
|
+
*
|
|
1722
|
+
* @param {string|object} locator element located by CSS|XPath|strict locator.
|
|
1723
|
+
* @param {number} num number of elements.
|
|
1724
|
+
* {--end--}
|
|
1725
|
+
*
|
|
1726
|
+
* {{ react }}
|
|
1532
1727
|
*/
|
|
1533
1728
|
async seeNumberOfVisibleElements(locator, num) {
|
|
1534
1729
|
const res = await this.grabNumberOfVisibleElements(locator);
|
|
@@ -1537,12 +1732,13 @@ I.seeNumberOfVisibleElements('.buttons', 3);
|
|
|
1537
1732
|
|
|
1538
1733
|
/**
|
|
1539
1734
|
* Sets a cookie.
|
|
1540
|
-
|
|
1541
|
-
```js
|
|
1542
|
-
I.setCookie({name: 'auth', value: true});
|
|
1543
|
-
```
|
|
1544
|
-
|
|
1545
|
-
@param cookie cookie
|
|
1735
|
+
*
|
|
1736
|
+
* ```js
|
|
1737
|
+
* I.setCookie({name: 'auth', value: true});
|
|
1738
|
+
* ```
|
|
1739
|
+
*
|
|
1740
|
+
* @param {object} cookie a cookie object.
|
|
1741
|
+
* {--end--}
|
|
1546
1742
|
*/
|
|
1547
1743
|
async setCookie(cookie) {
|
|
1548
1744
|
if (Array.isArray(cookie)) {
|
|
@@ -1553,12 +1749,13 @@ I.setCookie({name: 'auth', value: true});
|
|
|
1553
1749
|
|
|
1554
1750
|
/**
|
|
1555
1751
|
* Checks that cookie with given name exists.
|
|
1556
|
-
|
|
1557
|
-
```js
|
|
1558
|
-
I.seeCookie('Auth');
|
|
1559
|
-
```
|
|
1560
|
-
|
|
1561
|
-
@param name cookie name.
|
|
1752
|
+
*
|
|
1753
|
+
* ```js
|
|
1754
|
+
* I.seeCookie('Auth');
|
|
1755
|
+
* ```
|
|
1756
|
+
*
|
|
1757
|
+
* @param {string} name cookie name.
|
|
1758
|
+
* {--end--}
|
|
1562
1759
|
*
|
|
1563
1760
|
*/
|
|
1564
1761
|
async seeCookie(name) {
|
|
@@ -1568,8 +1765,13 @@ I.seeCookie('Auth');
|
|
|
1568
1765
|
|
|
1569
1766
|
/**
|
|
1570
1767
|
* Checks that cookie with given name does not exist.
|
|
1571
|
-
|
|
1572
|
-
|
|
1768
|
+
*
|
|
1769
|
+
* ```js
|
|
1770
|
+
* I.dontSeeCookie('auth'); // no auth cookie
|
|
1771
|
+
* ```
|
|
1772
|
+
*
|
|
1773
|
+
* @param {string} name cookie name.
|
|
1774
|
+
* {--end--}
|
|
1573
1775
|
*/
|
|
1574
1776
|
async dontSeeCookie(name) {
|
|
1575
1777
|
const cookies = await this.page.cookies();
|
|
@@ -1578,15 +1780,17 @@ I.seeCookie('Auth');
|
|
|
1578
1780
|
|
|
1579
1781
|
/**
|
|
1580
1782
|
* Gets a cookie object by name.
|
|
1581
|
-
If none provided gets all cookies.
|
|
1582
|
-
* Resumes test execution, so **should be used inside async with `await`** operator.
|
|
1583
|
-
|
|
1584
|
-
```js
|
|
1585
|
-
let cookie = await I.grabCookie('auth');
|
|
1586
|
-
assert(cookie.value, '123456');
|
|
1587
|
-
```
|
|
1588
|
-
|
|
1589
|
-
@param name
|
|
1783
|
+
* If none provided gets all cookies.
|
|
1784
|
+
* * Resumes test execution, so **should be used inside async with `await`** operator.
|
|
1785
|
+
*
|
|
1786
|
+
* ```js
|
|
1787
|
+
* let cookie = await I.grabCookie('auth');
|
|
1788
|
+
* assert(cookie.value, '123456');
|
|
1789
|
+
* ```
|
|
1790
|
+
*
|
|
1791
|
+
* @param [name=null] cookie name.
|
|
1792
|
+
* @returns {Promise<string>} attribute value
|
|
1793
|
+
* {--end--}
|
|
1590
1794
|
*
|
|
1591
1795
|
* Returns cookie in JSON format. If name not passed returns all cookies for this domain.
|
|
1592
1796
|
*/
|
|
@@ -1599,14 +1803,15 @@ assert(cookie.value, '123456');
|
|
|
1599
1803
|
|
|
1600
1804
|
/**
|
|
1601
1805
|
* Clears a cookie by name,
|
|
1602
|
-
if none provided clears all cookies.
|
|
1603
|
-
|
|
1604
|
-
```js
|
|
1605
|
-
I.clearCookie();
|
|
1606
|
-
I.clearCookie('test');
|
|
1607
|
-
```
|
|
1608
|
-
|
|
1609
|
-
@param cookie (optional) cookie name
|
|
1806
|
+
* if none provided clears all cookies.
|
|
1807
|
+
*
|
|
1808
|
+
* ```js
|
|
1809
|
+
* I.clearCookie();
|
|
1810
|
+
* I.clearCookie('test');
|
|
1811
|
+
* ```
|
|
1812
|
+
*
|
|
1813
|
+
* @param {string} cookie (optional, `null` by default) cookie name
|
|
1814
|
+
* {--end--}
|
|
1610
1815
|
*/
|
|
1611
1816
|
async clearCookie(name) {
|
|
1612
1817
|
const cookies = await this.page.cookies();
|
|
@@ -1620,30 +1825,31 @@ I.clearCookie('test');
|
|
|
1620
1825
|
|
|
1621
1826
|
/**
|
|
1622
1827
|
* Executes sync script on a page.
|
|
1623
|
-
Pass arguments to function as additional parameters.
|
|
1624
|
-
Will return execution result to a test.
|
|
1625
|
-
In this case you should use async function and await to receive results.
|
|
1626
|
-
|
|
1627
|
-
Example with jQuery DatePicker:
|
|
1628
|
-
|
|
1629
|
-
```js
|
|
1630
|
-
// change date of jQuery DatePicker
|
|
1631
|
-
I.executeScript(function() {
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
});
|
|
1635
|
-
```
|
|
1636
|
-
Can return values. Don't forget to use `await` to get them.
|
|
1637
|
-
|
|
1638
|
-
```js
|
|
1639
|
-
let date = await I.executeScript(function(el) {
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
}, '#date'); // passing jquery selector
|
|
1643
|
-
```
|
|
1644
|
-
|
|
1645
|
-
@param fn function to be executed in browser context.
|
|
1646
|
-
@param ...args args to be passed to function.
|
|
1828
|
+
* Pass arguments to function as additional parameters.
|
|
1829
|
+
* Will return execution result to a test.
|
|
1830
|
+
* In this case you should use async function and await to receive results.
|
|
1831
|
+
*
|
|
1832
|
+
* Example with jQuery DatePicker:
|
|
1833
|
+
*
|
|
1834
|
+
* ```js
|
|
1835
|
+
* // change date of jQuery DatePicker
|
|
1836
|
+
* I.executeScript(function() {
|
|
1837
|
+
* // now we are inside browser context
|
|
1838
|
+
* $('date').datetimepicker('setDate', new Date());
|
|
1839
|
+
* });
|
|
1840
|
+
* ```
|
|
1841
|
+
* Can return values. Don't forget to use `await` to get them.
|
|
1842
|
+
*
|
|
1843
|
+
* ```js
|
|
1844
|
+
* let date = await I.executeScript(function(el) {
|
|
1845
|
+
* // only basic types can be returned
|
|
1846
|
+
* return $(el).datetimepicker('getDate').toString();
|
|
1847
|
+
* }, '#date'); // passing jquery selector
|
|
1848
|
+
* ```
|
|
1849
|
+
*
|
|
1850
|
+
* @param {string|function} fn function to be executed in browser context.
|
|
1851
|
+
* @param ...args args to be passed to function.
|
|
1852
|
+
* {--end--}
|
|
1647
1853
|
*
|
|
1648
1854
|
* If a function returns a Promise It will wait for it resolution.
|
|
1649
1855
|
*/
|
|
@@ -1657,28 +1863,29 @@ let date = await I.executeScript(function(el) {
|
|
|
1657
1863
|
|
|
1658
1864
|
/**
|
|
1659
1865
|
* Executes async script on page.
|
|
1660
|
-
Provided function should execute a passed callback (as first argument) to signal it is finished.
|
|
1661
|
-
|
|
1662
|
-
Example: In Vue.js to make components completely rendered we are waiting for [nextTick](https://vuejs.org/v2/api/#Vue-nextTick).
|
|
1663
|
-
|
|
1664
|
-
```js
|
|
1665
|
-
I.executeAsyncScript(function(done) {
|
|
1666
|
-
|
|
1667
|
-
});
|
|
1668
|
-
```
|
|
1669
|
-
|
|
1670
|
-
By passing value to `done()` function you can return values.
|
|
1671
|
-
Additional arguments can be passed as well, while `done` function is always last parameter in arguments list.
|
|
1672
|
-
|
|
1673
|
-
```js
|
|
1674
|
-
let val = await I.executeAsyncScript(function(url, done) {
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
}, 'http://ajax.callback.url/');
|
|
1678
|
-
```
|
|
1679
|
-
|
|
1680
|
-
@param fn function to be executed in browser context.
|
|
1681
|
-
@param ...args args to be passed to function.
|
|
1866
|
+
* Provided function should execute a passed callback (as first argument) to signal it is finished.
|
|
1867
|
+
*
|
|
1868
|
+
* Example: In Vue.js to make components completely rendered we are waiting for [nextTick](https://vuejs.org/v2/api/#Vue-nextTick).
|
|
1869
|
+
*
|
|
1870
|
+
* ```js
|
|
1871
|
+
* I.executeAsyncScript(function(done) {
|
|
1872
|
+
* Vue.nextTick(done); // waiting for next tick
|
|
1873
|
+
* });
|
|
1874
|
+
* ```
|
|
1875
|
+
*
|
|
1876
|
+
* By passing value to `done()` function you can return values.
|
|
1877
|
+
* Additional arguments can be passed as well, while `done` function is always last parameter in arguments list.
|
|
1878
|
+
*
|
|
1879
|
+
* ```js
|
|
1880
|
+
* let val = await I.executeAsyncScript(function(url, done) {
|
|
1881
|
+
* // in browser context
|
|
1882
|
+
* $.ajax(url, { success: (data) => done(data); }
|
|
1883
|
+
* }, 'http://ajax.callback.url/');
|
|
1884
|
+
* ```
|
|
1885
|
+
*
|
|
1886
|
+
* @param {string|function} fn function to be executed in browser context.
|
|
1887
|
+
* @param ...args args to be passed to function.
|
|
1888
|
+
* {--end--}
|
|
1682
1889
|
*
|
|
1683
1890
|
* Asynchronous scripts can also be executed with `executeScript` if a function returns a Promise.
|
|
1684
1891
|
*/
|
|
@@ -1700,14 +1907,17 @@ let val = await I.executeAsyncScript(function(url, done) {
|
|
|
1700
1907
|
|
|
1701
1908
|
/**
|
|
1702
1909
|
* Retrieves a text from an element located by CSS or XPath and returns it to test.
|
|
1703
|
-
Resumes test execution, so **should be used inside async with `await`** operator.
|
|
1704
|
-
|
|
1705
|
-
```js
|
|
1706
|
-
let pin = await I.grabTextFrom('#pin');
|
|
1707
|
-
```
|
|
1708
|
-
If multiple elements found returns an array of texts.
|
|
1709
|
-
|
|
1710
|
-
@param locator element located by CSS|XPath|strict locator.
|
|
1910
|
+
* Resumes test execution, so **should be used inside async with `await`** operator.
|
|
1911
|
+
*
|
|
1912
|
+
* ```js
|
|
1913
|
+
* let pin = await I.grabTextFrom('#pin');
|
|
1914
|
+
* ```
|
|
1915
|
+
* If multiple elements found returns an array of texts.
|
|
1916
|
+
*
|
|
1917
|
+
* @param locator element located by CSS|XPath|strict locator.
|
|
1918
|
+
* @returns {Promise<string>} attribute value
|
|
1919
|
+
* {--end--}
|
|
1920
|
+
* {{ react }}
|
|
1711
1921
|
*/
|
|
1712
1922
|
async grabTextFrom(locator) {
|
|
1713
1923
|
const els = await this._locate(locator);
|
|
@@ -1722,12 +1932,14 @@ If multiple elements found returns an array of texts.
|
|
|
1722
1932
|
|
|
1723
1933
|
/**
|
|
1724
1934
|
* Retrieves a value from a form element located by CSS or XPath and returns it to test.
|
|
1725
|
-
Resumes test execution, so **should be used inside async function with `await`** operator.
|
|
1726
|
-
|
|
1727
|
-
```js
|
|
1728
|
-
let email = await I.grabValueFrom('input[name=email]');
|
|
1729
|
-
```
|
|
1730
|
-
@param locator field located by label|name|CSS|XPath|strict locator.
|
|
1935
|
+
* Resumes test execution, so **should be used inside async function with `await`** operator.
|
|
1936
|
+
*
|
|
1937
|
+
* ```js
|
|
1938
|
+
* let email = await I.grabValueFrom('input[name=email]');
|
|
1939
|
+
* ```
|
|
1940
|
+
* @param {string|object} locator field located by label|name|CSS|XPath|strict locator.
|
|
1941
|
+
* @returns {Promise<string>} attribute value
|
|
1942
|
+
* {--end--}
|
|
1731
1943
|
*/
|
|
1732
1944
|
async grabValueFrom(locator) {
|
|
1733
1945
|
const els = await findFields.call(this, locator);
|
|
@@ -1737,14 +1949,16 @@ let email = await I.grabValueFrom('input[name=email]');
|
|
|
1737
1949
|
|
|
1738
1950
|
/**
|
|
1739
1951
|
* Retrieves the innerHTML from an element located by CSS or XPath and returns it to test.
|
|
1740
|
-
Resumes test execution, so **should be used inside async function with `await`** operator.
|
|
1741
|
-
If more than one element is found - an array of HTMLs returned.
|
|
1742
|
-
|
|
1743
|
-
```js
|
|
1744
|
-
let postHTML = await I.grabHTMLFrom('#post');
|
|
1745
|
-
```
|
|
1746
|
-
|
|
1747
|
-
@param locator element located by CSS|XPath|strict locator.
|
|
1952
|
+
* Resumes test execution, so **should be used inside async function with `await`** operator.
|
|
1953
|
+
* If more than one element is found - an array of HTMLs returned.
|
|
1954
|
+
*
|
|
1955
|
+
* ```js
|
|
1956
|
+
* let postHTML = await I.grabHTMLFrom('#post');
|
|
1957
|
+
* ```
|
|
1958
|
+
*
|
|
1959
|
+
* @param locator element located by CSS|XPath|strict locator.
|
|
1960
|
+
* @returns {Promise<string>} HTML code for an element
|
|
1961
|
+
* {--end--}
|
|
1748
1962
|
*/
|
|
1749
1963
|
async grabHTMLFrom(locator) {
|
|
1750
1964
|
const els = await this._locate(locator);
|
|
@@ -1758,14 +1972,17 @@ let postHTML = await I.grabHTMLFrom('#post');
|
|
|
1758
1972
|
|
|
1759
1973
|
/**
|
|
1760
1974
|
* Grab CSS property for given locator
|
|
1761
|
-
Resumes test execution, so **should be used inside an async function with `await`** operator.
|
|
1762
|
-
|
|
1763
|
-
```js
|
|
1764
|
-
const value = await I.grabCssPropertyFrom('h3', 'font-weight');
|
|
1765
|
-
```
|
|
1766
|
-
|
|
1767
|
-
@param locator element located by CSS|XPath|strict locator.
|
|
1768
|
-
@param cssProperty CSS property name.
|
|
1975
|
+
* Resumes test execution, so **should be used inside an async function with `await`** operator.
|
|
1976
|
+
*
|
|
1977
|
+
* ```js
|
|
1978
|
+
* const value = await I.grabCssPropertyFrom('h3', 'font-weight');
|
|
1979
|
+
* ```
|
|
1980
|
+
*
|
|
1981
|
+
* @param {string|object} locator element located by CSS|XPath|strict locator.
|
|
1982
|
+
* @param {string} cssProperty CSS property name.
|
|
1983
|
+
* @returns {Promise<string>} CSS value
|
|
1984
|
+
* {--end--}
|
|
1985
|
+
* {{ react }}
|
|
1769
1986
|
*/
|
|
1770
1987
|
async grabCssPropertyFrom(locator, cssProperty) {
|
|
1771
1988
|
const els = await this._locate(locator);
|
|
@@ -1780,13 +1997,15 @@ const value = await I.grabCssPropertyFrom('h3', 'font-weight');
|
|
|
1780
1997
|
|
|
1781
1998
|
/**
|
|
1782
1999
|
* Checks that all elements with given locator have given CSS properties.
|
|
1783
|
-
|
|
1784
|
-
```js
|
|
1785
|
-
I.seeCssPropertiesOnElements('h3', { 'font-weight': "bold"});
|
|
1786
|
-
```
|
|
1787
|
-
|
|
1788
|
-
@param locator located by CSS|XPath|strict locator.
|
|
1789
|
-
@param cssProperties object with CSS properties and their values to check.
|
|
2000
|
+
*
|
|
2001
|
+
* ```js
|
|
2002
|
+
* I.seeCssPropertiesOnElements('h3', { 'font-weight': "bold"});
|
|
2003
|
+
* ```
|
|
2004
|
+
*
|
|
2005
|
+
* @param {string|object} locator located by CSS|XPath|strict locator.
|
|
2006
|
+
* @param {object} cssProperties object with CSS properties and their values to check.
|
|
2007
|
+
* {--end--}
|
|
2008
|
+
* {{ react }}
|
|
1790
2009
|
*/
|
|
1791
2010
|
async seeCssPropertiesOnElements(locator, cssProperties) {
|
|
1792
2011
|
const res = await this._locate(locator);
|
|
@@ -1825,13 +2044,15 @@ I.seeCssPropertiesOnElements('h3', { 'font-weight': "bold"});
|
|
|
1825
2044
|
|
|
1826
2045
|
/**
|
|
1827
2046
|
* Checks that all elements with given locator have given attributes.
|
|
1828
|
-
|
|
1829
|
-
```js
|
|
1830
|
-
I.seeAttributesOnElements('//form', {
|
|
1831
|
-
```
|
|
1832
|
-
|
|
1833
|
-
@param locator located by CSS|XPath|strict locator.
|
|
1834
|
-
@param
|
|
2047
|
+
*
|
|
2048
|
+
* ```js
|
|
2049
|
+
* I.seeAttributesOnElements('//form', { method: "post"});
|
|
2050
|
+
* ```
|
|
2051
|
+
*
|
|
2052
|
+
* @param {string|object} locator located by CSS|XPath|strict locator.
|
|
2053
|
+
* @param {object} attributes attributes and their values to check.
|
|
2054
|
+
* {--end--}
|
|
2055
|
+
* {{ react }}
|
|
1835
2056
|
*/
|
|
1836
2057
|
async seeAttributesOnElements(locator, attributes) {
|
|
1837
2058
|
const res = await this._locate(locator);
|
|
@@ -1862,15 +2083,17 @@ I.seeAttributesOnElements('//form', {'method': "post"});
|
|
|
1862
2083
|
|
|
1863
2084
|
/**
|
|
1864
2085
|
* Drag the scrubber of a slider to a given position
|
|
1865
|
-
For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and XPath.
|
|
1866
|
-
|
|
1867
|
-
```js
|
|
1868
|
-
I.dragSlider('#slider', 30);
|
|
1869
|
-
I.dragSlider('#slider', -70);
|
|
1870
|
-
```
|
|
1871
|
-
|
|
1872
|
-
@param locator located by label|name|CSS|XPath|strict locator.
|
|
1873
|
-
@param offsetX position to drag.
|
|
2086
|
+
* For fuzzy locators, fields are matched by label text, the "name" attribute, CSS, and XPath.
|
|
2087
|
+
*
|
|
2088
|
+
* ```js
|
|
2089
|
+
* I.dragSlider('#slider', 30);
|
|
2090
|
+
* I.dragSlider('#slider', -70);
|
|
2091
|
+
* ```
|
|
2092
|
+
*
|
|
2093
|
+
* @param {string|object} locator located by label|name|CSS|XPath|strict locator.
|
|
2094
|
+
* @param {number} offsetX position to drag.
|
|
2095
|
+
* {--end--}
|
|
2096
|
+
* {{ react }}
|
|
1874
2097
|
*/
|
|
1875
2098
|
async dragSlider(locator, offsetX = 0) {
|
|
1876
2099
|
const src = await this._locate(locator);
|
|
@@ -1892,14 +2115,17 @@ I.dragSlider('#slider', -70);
|
|
|
1892
2115
|
|
|
1893
2116
|
/**
|
|
1894
2117
|
* Retrieves an attribute from an element located by CSS or XPath and returns it to test.
|
|
1895
|
-
An array as a result will be returned if there are more than one matched element.
|
|
1896
|
-
Resumes test execution, so **should be used inside async with `await`** operator.
|
|
1897
|
-
|
|
1898
|
-
```js
|
|
1899
|
-
let hint = await I.grabAttributeFrom('#tooltip', 'title');
|
|
1900
|
-
```
|
|
1901
|
-
@param locator element located by CSS|XPath|strict locator.
|
|
1902
|
-
@param attr attribute name.
|
|
2118
|
+
* An array as a result will be returned if there are more than one matched element.
|
|
2119
|
+
* Resumes test execution, so **should be used inside async with `await`** operator.
|
|
2120
|
+
*
|
|
2121
|
+
* ```js
|
|
2122
|
+
* let hint = await I.grabAttributeFrom('#tooltip', 'title');
|
|
2123
|
+
* ```
|
|
2124
|
+
* @param {string|object} locator element located by CSS|XPath|strict locator.
|
|
2125
|
+
* @param {string} attr attribute name.
|
|
2126
|
+
* @returns {Promise<string>} attribute value
|
|
2127
|
+
* {--end--}
|
|
2128
|
+
* {{ react }}
|
|
1903
2129
|
*/
|
|
1904
2130
|
async grabAttributeFrom(locator, attr) {
|
|
1905
2131
|
const els = await this._locate(locator);
|
|
@@ -1916,16 +2142,17 @@ let hint = await I.grabAttributeFrom('#tooltip', 'title');
|
|
|
1916
2142
|
|
|
1917
2143
|
/**
|
|
1918
2144
|
* Saves a screenshot to ouput folder (set in codecept.json or codecept.conf.js).
|
|
1919
|
-
Filename is relative to output folder.
|
|
1920
|
-
Optionally resize the window to the full available page `scrollHeight` and `scrollWidth` to capture the entire page by passing `true` in as the second argument.
|
|
1921
|
-
|
|
1922
|
-
```js
|
|
1923
|
-
I.saveScreenshot('debug.png');
|
|
1924
|
-
I.saveScreenshot('debug.png', true) //resizes to available scrollHeight and scrollWidth before taking screenshot
|
|
1925
|
-
```
|
|
1926
|
-
|
|
1927
|
-
@param fileName file name to save.
|
|
1928
|
-
@param fullPage (optional) flag to enable fullscreen screenshot mode.
|
|
2145
|
+
* Filename is relative to output folder.
|
|
2146
|
+
* Optionally resize the window to the full available page `scrollHeight` and `scrollWidth` to capture the entire page by passing `true` in as the second argument.
|
|
2147
|
+
*
|
|
2148
|
+
* ```js
|
|
2149
|
+
* I.saveScreenshot('debug.png');
|
|
2150
|
+
* I.saveScreenshot('debug.png', true) //resizes to available scrollHeight and scrollWidth before taking screenshot
|
|
2151
|
+
* ```
|
|
2152
|
+
*
|
|
2153
|
+
* @param {string} fileName file name to save.
|
|
2154
|
+
* @param {boolean} fullPage (optional, `false` by default) flag to enable fullscreen screenshot mode.
|
|
2155
|
+
* {--end--}
|
|
1929
2156
|
*/
|
|
1930
2157
|
async saveScreenshot(fileName, fullPage) {
|
|
1931
2158
|
const fullPageOption = fullPage || this.options.fullPageScreenshots;
|
|
@@ -1945,13 +2172,13 @@ I.saveScreenshot('debug.png', true) //resizes to available scrollHeight and scro
|
|
|
1945
2172
|
|
|
1946
2173
|
/**
|
|
1947
2174
|
* Pauses execution for a number of seconds.
|
|
1948
|
-
|
|
1949
|
-
```js
|
|
1950
|
-
I.wait(2); // wait 2 secs
|
|
1951
|
-
```
|
|
1952
|
-
|
|
1953
|
-
@param sec number of second to wait.
|
|
1954
|
-
|
|
2175
|
+
*
|
|
2176
|
+
* ```js
|
|
2177
|
+
* I.wait(2); // wait 2 secs
|
|
2178
|
+
* ```
|
|
2179
|
+
*
|
|
2180
|
+
* @param {number} sec number of second to wait.
|
|
2181
|
+
* {--end--}
|
|
1955
2182
|
*/
|
|
1956
2183
|
async wait(sec) {
|
|
1957
2184
|
return new Promise(((done) => {
|
|
@@ -1961,10 +2188,11 @@ I.wait(2); // wait 2 secs
|
|
|
1961
2188
|
|
|
1962
2189
|
/**
|
|
1963
2190
|
* Waits for element to become enabled (by default waits for 1sec).
|
|
1964
|
-
Element can be located by CSS or XPath.
|
|
1965
|
-
|
|
1966
|
-
@param locator element located by CSS|XPath|strict locator.
|
|
1967
|
-
@param sec (optional) time in seconds to wait, 1 by default.
|
|
2191
|
+
* Element can be located by CSS or XPath.
|
|
2192
|
+
*
|
|
2193
|
+
* @param {string|object} locator element located by CSS|XPath|strict locator.
|
|
2194
|
+
* @param sec (optional) time in seconds to wait, 1 by default.
|
|
2195
|
+
* {--end--}
|
|
1968
2196
|
*/
|
|
1969
2197
|
async waitForEnabled(locator, sec) {
|
|
1970
2198
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -1995,14 +2223,15 @@ Element can be located by CSS or XPath.
|
|
|
1995
2223
|
|
|
1996
2224
|
/**
|
|
1997
2225
|
* Waits for the specified value to be in value attribute.
|
|
1998
|
-
|
|
1999
|
-
```js
|
|
2000
|
-
I.waitForValue('//input', "GoodValue");
|
|
2001
|
-
```
|
|
2002
|
-
|
|
2003
|
-
@param field input field.
|
|
2004
|
-
@param value expected value.
|
|
2005
|
-
@param sec (optional) time in seconds to wait
|
|
2226
|
+
*
|
|
2227
|
+
* ```js
|
|
2228
|
+
* I.waitForValue('//input', "GoodValue");
|
|
2229
|
+
* ```
|
|
2230
|
+
*
|
|
2231
|
+
* @param {string|object} field input field.
|
|
2232
|
+
* @param {string }value expected value.
|
|
2233
|
+
* @param {number} sec (optional, `1` by default) time in seconds to wait
|
|
2234
|
+
* {--end--}
|
|
2006
2235
|
*/
|
|
2007
2236
|
async waitForValue(field, value, sec) {
|
|
2008
2237
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -2034,14 +2263,16 @@ I.waitForValue('//input', "GoodValue");
|
|
|
2034
2263
|
|
|
2035
2264
|
/**
|
|
2036
2265
|
* Waits for a specified number of elements on the page.
|
|
2037
|
-
|
|
2038
|
-
```js
|
|
2039
|
-
I.waitNumberOfVisibleElements('a', 3);
|
|
2040
|
-
```
|
|
2041
|
-
|
|
2042
|
-
@param locator element located by CSS|XPath|strict locator.
|
|
2043
|
-
@param num number of elements.
|
|
2044
|
-
@param sec (optional) time in seconds to wait
|
|
2266
|
+
*
|
|
2267
|
+
* ```js
|
|
2268
|
+
* I.waitNumberOfVisibleElements('a', 3);
|
|
2269
|
+
* ```
|
|
2270
|
+
*
|
|
2271
|
+
* @param {string|object} locator element located by CSS|XPath|strict locator.
|
|
2272
|
+
* @param {number} num number of elements.
|
|
2273
|
+
* @param {number} sec (optional, `1` by default) time in seconds to wait
|
|
2274
|
+
* {--end--}
|
|
2275
|
+
* {{ react }}
|
|
2045
2276
|
*/
|
|
2046
2277
|
async waitNumberOfVisibleElements(locator, num, sec) {
|
|
2047
2278
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -2072,15 +2303,17 @@ I.waitNumberOfVisibleElements('a', 3);
|
|
|
2072
2303
|
|
|
2073
2304
|
/**
|
|
2074
2305
|
* Waits for element to be present on page (by default waits for 1sec).
|
|
2075
|
-
Element can be located by CSS or XPath.
|
|
2076
|
-
|
|
2077
|
-
```js
|
|
2078
|
-
I.waitForElement('.btn.continue');
|
|
2079
|
-
I.waitForElement('.btn.continue', 5); // wait for 5 secs
|
|
2080
|
-
```
|
|
2081
|
-
|
|
2082
|
-
@param locator element located by CSS|XPath|strict locator.
|
|
2083
|
-
@param sec (optional) time in seconds to wait
|
|
2306
|
+
* Element can be located by CSS or XPath.
|
|
2307
|
+
*
|
|
2308
|
+
* ```js
|
|
2309
|
+
* I.waitForElement('.btn.continue');
|
|
2310
|
+
* I.waitForElement('.btn.continue', 5); // wait for 5 secs
|
|
2311
|
+
* ```
|
|
2312
|
+
*
|
|
2313
|
+
* @param {string|object} locator element located by CSS|XPath|strict locator.
|
|
2314
|
+
* @param {number} sec (optional, `1` by default) time in seconds to wait
|
|
2315
|
+
* {--end--}
|
|
2316
|
+
* {{ react }}
|
|
2084
2317
|
*/
|
|
2085
2318
|
async waitForElement(locator, sec) {
|
|
2086
2319
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -2100,14 +2333,17 @@ I.waitForElement('.btn.continue', 5); // wait for 5 secs
|
|
|
2100
2333
|
|
|
2101
2334
|
/**
|
|
2102
2335
|
* Waits for an element to become visible on a page (by default waits for 1sec).
|
|
2103
|
-
Element can be located by CSS or XPath.
|
|
2104
|
-
|
|
2105
|
-
```
|
|
2106
|
-
I.waitForVisible('#popup');
|
|
2107
|
-
```
|
|
2108
|
-
|
|
2109
|
-
@param locator element located by CSS|XPath|strict locator.
|
|
2110
|
-
@param sec (optional) time in seconds to wait
|
|
2336
|
+
* Element can be located by CSS or XPath.
|
|
2337
|
+
*
|
|
2338
|
+
* ```js
|
|
2339
|
+
* I.waitForVisible('#popup');
|
|
2340
|
+
* ```
|
|
2341
|
+
*
|
|
2342
|
+
* @param {string|object} locator element located by CSS|XPath|strict locator.
|
|
2343
|
+
* @param {number} sec (optional, `1` by default) time in seconds to wait
|
|
2344
|
+
* {--end--}
|
|
2345
|
+
*
|
|
2346
|
+
* This method accepts [React selectors](https://codecept.io/react).
|
|
2111
2347
|
*/
|
|
2112
2348
|
async waitForVisible(locator, sec) {
|
|
2113
2349
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -2131,14 +2367,15 @@ I.waitForVisible('#popup');
|
|
|
2131
2367
|
|
|
2132
2368
|
/**
|
|
2133
2369
|
* Waits for an element to be removed or become invisible on a page (by default waits for 1sec).
|
|
2134
|
-
Element can be located by CSS or XPath.
|
|
2135
|
-
|
|
2136
|
-
```
|
|
2137
|
-
I.waitForInvisible('#popup');
|
|
2138
|
-
```
|
|
2139
|
-
|
|
2140
|
-
@param locator element located by CSS|XPath|strict locator.
|
|
2141
|
-
@param sec (optional) time in seconds to wait
|
|
2370
|
+
* Element can be located by CSS or XPath.
|
|
2371
|
+
*
|
|
2372
|
+
* ```js
|
|
2373
|
+
* I.waitForInvisible('#popup');
|
|
2374
|
+
* ```
|
|
2375
|
+
*
|
|
2376
|
+
* @param {string|object} locator element located by CSS|XPath|strict locator.
|
|
2377
|
+
* @param {number} sec (optional, `1` by default) time in seconds to wait
|
|
2378
|
+
* {--end--}
|
|
2142
2379
|
*/
|
|
2143
2380
|
async waitForInvisible(locator, sec) {
|
|
2144
2381
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -2163,14 +2400,15 @@ I.waitForInvisible('#popup');
|
|
|
2163
2400
|
|
|
2164
2401
|
/**
|
|
2165
2402
|
* Waits for an element to hide (by default waits for 1sec).
|
|
2166
|
-
Element can be located by CSS or XPath.
|
|
2167
|
-
|
|
2168
|
-
```
|
|
2169
|
-
I.waitToHide('#popup');
|
|
2170
|
-
```
|
|
2171
|
-
|
|
2172
|
-
@param locator element located by CSS|XPath|strict locator.
|
|
2173
|
-
@param sec (optional) time in seconds to wait
|
|
2403
|
+
* Element can be located by CSS or XPath.
|
|
2404
|
+
*
|
|
2405
|
+
* ```js
|
|
2406
|
+
* I.waitToHide('#popup');
|
|
2407
|
+
* ```
|
|
2408
|
+
*
|
|
2409
|
+
* @param {string|object} locator element located by CSS|XPath|strict locator.
|
|
2410
|
+
* @param {number} sec (optional, `1` by default) time in seconds to wait
|
|
2411
|
+
* {--end--}
|
|
2174
2412
|
*/
|
|
2175
2413
|
async waitToHide(locator, sec) {
|
|
2176
2414
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -2200,13 +2438,14 @@ I.waitToHide('#popup');
|
|
|
2200
2438
|
|
|
2201
2439
|
/**
|
|
2202
2440
|
* Waiting for the part of the URL to match the expected. Useful for SPA to understand that page was changed.
|
|
2203
|
-
|
|
2204
|
-
```js
|
|
2205
|
-
I.waitInUrl('/info', 2);
|
|
2206
|
-
```
|
|
2207
|
-
|
|
2208
|
-
@param urlPart value to check.
|
|
2209
|
-
@param sec (optional) time in seconds to wait
|
|
2441
|
+
*
|
|
2442
|
+
* ```js
|
|
2443
|
+
* I.waitInUrl('/info', 2);
|
|
2444
|
+
* ```
|
|
2445
|
+
*
|
|
2446
|
+
* @param {string} urlPart value to check.
|
|
2447
|
+
* @param {number} sec (optional, `1` by default) time in seconds to wait
|
|
2448
|
+
* {--end--}
|
|
2210
2449
|
*/
|
|
2211
2450
|
async waitInUrl(urlPart, sec = null) {
|
|
2212
2451
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -2226,14 +2465,15 @@ I.waitInUrl('/info', 2);
|
|
|
2226
2465
|
|
|
2227
2466
|
/**
|
|
2228
2467
|
* Waits for the entire URL to match the expected
|
|
2229
|
-
|
|
2230
|
-
```js
|
|
2231
|
-
I.waitUrlEquals('/info', 2);
|
|
2232
|
-
I.waitUrlEquals('http://127.0.0.1:8000/info');
|
|
2233
|
-
```
|
|
2234
|
-
|
|
2235
|
-
@param urlPart value to check.
|
|
2236
|
-
@param sec (optional) time in seconds to wait
|
|
2468
|
+
*
|
|
2469
|
+
* ```js
|
|
2470
|
+
* I.waitUrlEquals('/info', 2);
|
|
2471
|
+
* I.waitUrlEquals('http://127.0.0.1:8000/info');
|
|
2472
|
+
* ```
|
|
2473
|
+
*
|
|
2474
|
+
* @param {string} urlPart value to check.
|
|
2475
|
+
* @param {number} sec (optional, `1` by default) time in seconds to wait
|
|
2476
|
+
* {--end--}
|
|
2237
2477
|
*/
|
|
2238
2478
|
async waitUrlEquals(urlPart, sec = null) {
|
|
2239
2479
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -2258,17 +2498,18 @@ I.waitUrlEquals('http://127.0.0.1:8000/info');
|
|
|
2258
2498
|
|
|
2259
2499
|
/**
|
|
2260
2500
|
* Waits for a text to appear (by default waits for 1sec).
|
|
2261
|
-
Element can be located by CSS or XPath.
|
|
2262
|
-
Narrow down search results by providing context.
|
|
2263
|
-
|
|
2264
|
-
```js
|
|
2265
|
-
I.waitForText('Thank you, form has been submitted');
|
|
2266
|
-
I.waitForText('Thank you, form has been submitted', 5, '#modal');
|
|
2267
|
-
```
|
|
2268
|
-
|
|
2269
|
-
@param text to wait for.
|
|
2270
|
-
@param sec (optional) time in seconds to wait
|
|
2271
|
-
@param context (optional) element located by CSS|XPath|strict locator.
|
|
2501
|
+
* Element can be located by CSS or XPath.
|
|
2502
|
+
* Narrow down search results by providing context.
|
|
2503
|
+
*
|
|
2504
|
+
* ```js
|
|
2505
|
+
* I.waitForText('Thank you, form has been submitted');
|
|
2506
|
+
* I.waitForText('Thank you, form has been submitted', 5, '#modal');
|
|
2507
|
+
* ```
|
|
2508
|
+
*
|
|
2509
|
+
* @param {string }text to wait for.
|
|
2510
|
+
* @param {number} sec (optional, `1` by default) time in seconds to wait
|
|
2511
|
+
* @param {string|object} context (optional) element located by CSS|XPath|strict locator.
|
|
2512
|
+
* {--end--}
|
|
2272
2513
|
*/
|
|
2273
2514
|
async waitForText(text, sec = null, context = null) {
|
|
2274
2515
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -2310,8 +2551,8 @@ I.waitForText('Thank you, form has been submitted', 5, '#modal');
|
|
|
2310
2551
|
* I.waitForRequest(request => request.url() === 'http://example.com' && request.method() === 'GET');
|
|
2311
2552
|
* ```
|
|
2312
2553
|
*
|
|
2313
|
-
* @param {
|
|
2314
|
-
* @param {
|
|
2554
|
+
* @param {string|function} urlOrPredicate
|
|
2555
|
+
* @param {number?} [sec=null] seconds to wait
|
|
2315
2556
|
*/
|
|
2316
2557
|
async waitForRequest(urlOrPredicate, sec = null) {
|
|
2317
2558
|
const timeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -2326,8 +2567,8 @@ I.waitForText('Thank you, form has been submitted', 5, '#modal');
|
|
|
2326
2567
|
* I.waitForResponse(request => request.url() === 'http://example.com' && request.method() === 'GET');
|
|
2327
2568
|
* ```
|
|
2328
2569
|
*
|
|
2329
|
-
* @param {
|
|
2330
|
-
* @param {
|
|
2570
|
+
* @param {string|function} urlOrPredicate
|
|
2571
|
+
* @param {number?} [sec=null] number of seconds to wait
|
|
2331
2572
|
*/
|
|
2332
2573
|
async waitForResponse(urlOrPredicate, sec = null) {
|
|
2333
2574
|
const timeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -2336,8 +2577,14 @@ I.waitForText('Thank you, form has been submitted', 5, '#modal');
|
|
|
2336
2577
|
|
|
2337
2578
|
/**
|
|
2338
2579
|
* Switches frame or in case of null locator reverts to parent.
|
|
2339
|
-
|
|
2340
|
-
|
|
2580
|
+
*
|
|
2581
|
+
* ```js
|
|
2582
|
+
* I.switchTo('iframe'); // switch to first iframe
|
|
2583
|
+
* I.switchTo(); // switch back to main page
|
|
2584
|
+
* ```
|
|
2585
|
+
*
|
|
2586
|
+
* @param {string|object} locator (optional, `null` by default) element located by CSS|XPath|strict locator.
|
|
2587
|
+
* {--end--}
|
|
2341
2588
|
*/
|
|
2342
2589
|
async switchTo(locator) {
|
|
2343
2590
|
if (Number.isInteger(locator)) {
|
|
@@ -2382,21 +2629,22 @@ I.waitForText('Thank you, form has been submitted', 5, '#modal');
|
|
|
2382
2629
|
|
|
2383
2630
|
/**
|
|
2384
2631
|
* Waits for a function to return true (waits for 1 sec by default).
|
|
2385
|
-
Running in browser context.
|
|
2386
|
-
|
|
2387
|
-
```js
|
|
2388
|
-
I.waitForFunction(fn[, [args[, timeout]])
|
|
2389
|
-
```
|
|
2390
|
-
|
|
2391
|
-
```js
|
|
2392
|
-
I.waitForFunction(() => window.requests == 0);
|
|
2393
|
-
I.waitForFunction(() => window.requests == 0, 5); // waits for 5 sec
|
|
2394
|
-
I.waitForFunction((count) => window.requests == count, [3], 5) // pass args and wait for 5 sec
|
|
2395
|
-
```
|
|
2396
|
-
|
|
2397
|
-
@param fn to be executed in browser context.
|
|
2398
|
-
@param argsOrSec (optional) arguments for function or seconds.
|
|
2399
|
-
@param sec (optional) time in seconds to wait
|
|
2632
|
+
* Running in browser context.
|
|
2633
|
+
*
|
|
2634
|
+
* ```js
|
|
2635
|
+
* I.waitForFunction(fn[, [args[, timeout]])
|
|
2636
|
+
* ```
|
|
2637
|
+
*
|
|
2638
|
+
* ```js
|
|
2639
|
+
* I.waitForFunction(() => window.requests == 0);
|
|
2640
|
+
* I.waitForFunction(() => window.requests == 0, 5); // waits for 5 sec
|
|
2641
|
+
* I.waitForFunction((count) => window.requests == count, [3], 5) // pass args and wait for 5 sec
|
|
2642
|
+
* ```
|
|
2643
|
+
*
|
|
2644
|
+
* @param {string|function} fn to be executed in browser context.
|
|
2645
|
+
* @param {array|number} argsOrSec (optional, `1` by default) arguments for function or seconds.
|
|
2646
|
+
* @param {number} sec (optional, `1` by default) time in seconds to wait
|
|
2647
|
+
* {--end--}
|
|
2400
2648
|
*/
|
|
2401
2649
|
async waitForFunction(fn, argsOrSec = null, sec = null) {
|
|
2402
2650
|
let args = [];
|
|
@@ -2426,15 +2674,16 @@ I.waitForFunction((count) => window.requests == count, [3], 5) // pass args and
|
|
|
2426
2674
|
|
|
2427
2675
|
/**
|
|
2428
2676
|
* Waits for a function to return true (waits for 1sec by default).
|
|
2429
|
-
|
|
2430
|
-
```js
|
|
2431
|
-
I.waitUntil(() => window.requests == 0);
|
|
2432
|
-
I.waitUntil(() => window.requests == 0, 5);
|
|
2433
|
-
```
|
|
2434
|
-
|
|
2435
|
-
@param fn function which is executed in browser context.
|
|
2436
|
-
@param sec (optional) time in seconds to wait
|
|
2437
|
-
@param timeoutMsg
|
|
2677
|
+
*
|
|
2678
|
+
* ```js
|
|
2679
|
+
* I.waitUntil(() => window.requests == 0);
|
|
2680
|
+
* I.waitUntil(() => window.requests == 0, 5);
|
|
2681
|
+
* ```
|
|
2682
|
+
*
|
|
2683
|
+
* @param {function|string} fn function which is executed in browser context.
|
|
2684
|
+
* @param {number} sec (optional, `1` by default) time in seconds to wait
|
|
2685
|
+
* @param {string} [timeoutMsg=''] message to show in case of timeout fail.
|
|
2686
|
+
* {--end--}
|
|
2438
2687
|
*/
|
|
2439
2688
|
async waitUntil(fn, sec = null) {
|
|
2440
2689
|
console.log('This method will remove in CodeceptJS 1.4; use `waitForFunction` instead!');
|
|
@@ -2452,14 +2701,15 @@ I.waitUntil(() => window.requests == 0, 5);
|
|
|
2452
2701
|
|
|
2453
2702
|
/**
|
|
2454
2703
|
* Waits for an element to become not attached to the DOM on a page (by default waits for 1sec).
|
|
2455
|
-
Element can be located by CSS or XPath.
|
|
2456
|
-
|
|
2457
|
-
```
|
|
2458
|
-
I.waitForDetached('#popup');
|
|
2459
|
-
```
|
|
2460
|
-
|
|
2461
|
-
@param locator element located by CSS|XPath|strict locator.
|
|
2462
|
-
@param sec (optional) time in seconds to wait
|
|
2704
|
+
* Element can be located by CSS or XPath.
|
|
2705
|
+
*
|
|
2706
|
+
* ```js
|
|
2707
|
+
* I.waitForDetached('#popup');
|
|
2708
|
+
* ```
|
|
2709
|
+
*
|
|
2710
|
+
* @param {string|object} locator element located by CSS|XPath|strict locator.
|
|
2711
|
+
* @param {number} sec (optional, `1` by default) time in seconds to wait
|
|
2712
|
+
* {--end--}
|
|
2463
2713
|
*/
|
|
2464
2714
|
async waitForDetached(locator, sec) {
|
|
2465
2715
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -2487,6 +2737,32 @@ I.waitForDetached('#popup');
|
|
|
2487
2737
|
async _waitForAction() {
|
|
2488
2738
|
return this.wait(this.options.waitForAction / 1000);
|
|
2489
2739
|
}
|
|
2740
|
+
|
|
2741
|
+
/**
|
|
2742
|
+
* Grab the data from performance timing using Navigation Timing API.
|
|
2743
|
+
* The returned data will contain following things in ms:
|
|
2744
|
+
* - responseEnd,
|
|
2745
|
+
* - domInteractive,
|
|
2746
|
+
* - domContentLoadedEventEnd,
|
|
2747
|
+
* - loadEventEnd
|
|
2748
|
+
* Resumes test execution, so **should be used inside an async function with `await`** operator.
|
|
2749
|
+
*
|
|
2750
|
+
* ```js
|
|
2751
|
+
* await I.amOnPage('https://example.com');
|
|
2752
|
+
* let data = await I.grabDataFromPerformanceTiming();
|
|
2753
|
+
* //Returned data
|
|
2754
|
+
* { // all results are in [ms]
|
|
2755
|
+
* responseEnd: 23,
|
|
2756
|
+
* domInteractive: 44,
|
|
2757
|
+
* domContentLoadedEventEnd: 196,
|
|
2758
|
+
* loadEventEnd: 241
|
|
2759
|
+
* }
|
|
2760
|
+
* ```
|
|
2761
|
+
* {--end--}
|
|
2762
|
+
*/
|
|
2763
|
+
async grabDataFromPerformanceTiming() {
|
|
2764
|
+
return perfTiming;
|
|
2765
|
+
}
|
|
2490
2766
|
}
|
|
2491
2767
|
|
|
2492
2768
|
module.exports = Puppeteer;
|
|
@@ -2511,9 +2787,9 @@ async function findFrame(context, name, url) {
|
|
|
2511
2787
|
}
|
|
2512
2788
|
|
|
2513
2789
|
async function findElements(matcher, locator) {
|
|
2790
|
+
if (locator.react) return findReact(matcher, locator);
|
|
2514
2791
|
locator = new Locator(locator, 'css');
|
|
2515
2792
|
if (!locator.isXPath()) return matcher.$$(locator.simplify());
|
|
2516
|
-
|
|
2517
2793
|
return matcher.$x(locator.value);
|
|
2518
2794
|
}
|
|
2519
2795
|
|
|
@@ -2540,6 +2816,7 @@ async function proceedClick(locator, context = null, options = {}) {
|
|
|
2540
2816
|
}
|
|
2541
2817
|
|
|
2542
2818
|
async function findClickable(matcher, locator) {
|
|
2819
|
+
if (locator.react) return findReact(matcher, locator);
|
|
2543
2820
|
locator = new Locator(locator);
|
|
2544
2821
|
if (!locator.isFuzzy()) return findElements.call(this, matcher, locator);
|
|
2545
2822
|
|
|
@@ -2781,7 +3058,11 @@ function $XPath(element, selector) {
|
|
|
2781
3058
|
function targetCreatedHandler(page) {
|
|
2782
3059
|
if (!page) return;
|
|
2783
3060
|
this.withinLocator = null;
|
|
2784
|
-
page.on('load', frame =>
|
|
3061
|
+
page.on('load', (frame) => {
|
|
3062
|
+
page.$('body')
|
|
3063
|
+
.catch(() => null)
|
|
3064
|
+
.then(context => this.context = context);
|
|
3065
|
+
});
|
|
2785
3066
|
page.on('console', (msg) => {
|
|
2786
3067
|
this.debugSection(`Browser:${ucfirst(msg.type())}`, (msg._text || '') + msg.args().join(' '));
|
|
2787
3068
|
consoleLogStore.add(msg);
|