codeceptjs 2.3.4 → 2.4.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 +52 -0
- package/README.md +28 -6
- package/bin/codecept.js +42 -0
- package/docs/advanced.md +45 -1
- package/docs/angular.md +3 -3
- package/docs/basics.md +162 -118
- package/docs/bdd.md +30 -5
- package/docs/best.md +8 -6
- package/docs/books.md +6 -1
- package/docs/build/Appium.js +95 -85
- package/docs/build/FileSystem.js +48 -3
- package/docs/build/GraphQL.js +3 -2
- package/docs/build/GraphQLDataFactory.js +1 -0
- package/docs/build/Mochawesome.js +3 -2
- package/docs/build/MockRequest.js +23 -5
- package/docs/build/Nightmare.js +87 -128
- package/docs/build/Protractor.js +107 -155
- package/docs/build/Puppeteer.js +190 -174
- package/docs/build/REST.js +13 -9
- package/docs/build/SeleniumWebdriver.js +0 -17
- package/docs/build/TestCafe.js +164 -158
- package/docs/build/WebDriver.js +236 -211
- package/docs/build/WebDriverIO.js +218 -187
- package/docs/changelog.md +57 -1
- package/docs/commands.md +41 -2
- package/docs/community-helpers.md +12 -1
- package/docs/configuration.md +5 -2
- package/docs/continuous-integration.md +22 -0
- package/docs/{helpers.md → custom-helpers.md} +16 -10
- package/docs/data.md +7 -6
- package/docs/detox.md +6 -6
- package/docs/email.md +4 -2
- package/docs/examples.md +22 -3
- package/docs/helpers/ApiDataFactory.md +15 -13
- package/docs/helpers/Appium.md +1011 -468
- package/docs/helpers/Detox.md +33 -26
- package/docs/helpers/FileSystem.md +43 -13
- package/docs/helpers/GraphQL.md +17 -15
- package/docs/helpers/GraphQLDataFactory.md +15 -13
- package/docs/helpers/Mochawesome.md +3 -1
- package/docs/helpers/MockRequest.md +37 -19
- package/docs/helpers/Nightmare.md +129 -240
- package/docs/helpers/Polly.md +1 -1
- package/docs/helpers/Protractor.md +157 -298
- package/docs/helpers/Puppeteer.md +216 -335
- package/docs/helpers/REST.md +29 -24
- package/docs/helpers/TestCafe.md +137 -235
- package/docs/helpers/WebDriver.md +250 -347
- package/docs/hooks.md +14 -10
- package/docs/index.md +112 -0
- package/docs/installation.md +3 -1
- package/docs/locators.md +19 -8
- package/docs/mobile-react-native-locators.md +2 -2
- package/docs/mobile.md +5 -3
- package/docs/nightmare.md +2 -1
- package/docs/pageobjects.md +4 -2
- package/docs/parallel.md +4 -2
- package/docs/plugins.md +41 -15
- package/docs/puppeteer.md +8 -6
- package/docs/quickstart.md +130 -0
- package/docs/react.md +4 -2
- package/docs/reports.md +6 -4
- package/docs/testcafe.md +10 -8
- package/docs/translation.md +4 -2
- package/docs/ui.md +56 -0
- package/docs/videos.md +11 -2
- package/docs/visual.md +7 -5
- package/docs/vue.md +121 -0
- package/docs/webapi/appendField.mustache +1 -1
- package/docs/webapi/attachFile.mustache +1 -1
- package/docs/webapi/checkOption.mustache +2 -2
- package/docs/webapi/clearCookie.mustache +1 -1
- package/docs/webapi/click.mustache +2 -2
- package/docs/webapi/clickLink.mustache +2 -2
- package/docs/webapi/dontSee.mustache +1 -2
- package/docs/webapi/dontSeeCheckboxIsChecked.mustache +1 -1
- package/docs/webapi/dontSeeElement.mustache +1 -1
- package/docs/webapi/dontSeeElementInDOM.mustache +1 -1
- package/docs/webapi/dontSeeInField.mustache +1 -1
- package/docs/webapi/doubleClick.mustache +2 -2
- package/docs/webapi/downloadFile.mustache +1 -1
- package/docs/webapi/dragSlider.mustache +1 -1
- package/docs/webapi/executeAsyncScript.mustache +2 -1
- package/docs/webapi/executeScript.mustache +2 -1
- package/docs/webapi/fillField.mustache +1 -1
- package/docs/webapi/grabAttributeFrom.mustache +1 -1
- package/docs/webapi/grabBrowserLogs.mustache +1 -1
- package/docs/webapi/grabCookie.mustache +2 -2
- package/docs/webapi/grabCssPropertyFrom.mustache +1 -1
- package/docs/webapi/grabHTMLFrom.mustache +1 -1
- package/docs/webapi/grabNumberOfVisibleElements.mustache +1 -1
- package/docs/webapi/grabPageScrollPosition.mustache +1 -1
- package/docs/webapi/grabTextFrom.mustache +2 -2
- package/docs/webapi/grabValueFrom.mustache +1 -1
- package/docs/webapi/moveCursorTo.mustache +3 -3
- package/docs/webapi/pressKey.mustache +1 -1
- package/docs/webapi/pressKeyWithKeyNormalization.mustache +1 -1
- package/docs/webapi/rightClick.mustache +2 -2
- package/docs/webapi/saveScreenshot.mustache +1 -1
- package/docs/webapi/scrollIntoView.mustache +10 -0
- package/docs/webapi/scrollTo.mustache +3 -3
- package/docs/webapi/see.mustache +1 -1
- package/docs/webapi/seeAttributesOnElements.mustache +1 -1
- package/docs/webapi/seeCheckboxIsChecked.mustache +1 -1
- package/docs/webapi/seeCssPropertiesOnElements.mustache +1 -1
- package/docs/webapi/seeElement.mustache +1 -1
- package/docs/webapi/seeElementInDOM.mustache +1 -1
- package/docs/webapi/seeInField.mustache +1 -1
- package/docs/webapi/seeNumberOfElements.mustache +1 -1
- package/docs/webapi/seeNumberOfVisibleElements.mustache +1 -1
- package/docs/webapi/seeTextEquals.mustache +8 -0
- package/docs/webapi/selectOption.mustache +2 -2
- package/docs/webapi/switchTo.mustache +1 -1
- package/docs/webapi/uncheckOption.mustache +2 -2
- package/docs/webapi/waitForClickable.mustache +10 -0
- package/docs/webapi/waitForDetached.mustache +2 -2
- package/docs/webapi/waitForElement.mustache +2 -2
- package/docs/webapi/waitForEnabled.mustache +2 -2
- package/docs/webapi/waitForFunction.mustache +2 -2
- package/docs/webapi/waitForInvisible.mustache +2 -2
- package/docs/webapi/waitForText.mustache +2 -2
- package/docs/webapi/waitForValue.mustache +1 -1
- package/docs/webapi/waitForVisible.mustache +2 -2
- package/docs/webapi/waitInUrl.mustache +1 -1
- package/docs/webapi/waitNumberOfVisibleElements.mustache +2 -2
- package/docs/webapi/waitToHide.mustache +2 -2
- package/docs/webapi/waitUntil.mustache +3 -2
- package/docs/webapi/waitUrlEquals.mustache +1 -1
- package/docs/webdriver.md +20 -18
- package/docs/wiki/.git/FETCH_HEAD +1 -0
- package/docs/wiki/.git/HEAD +1 -0
- package/docs/wiki/.git/ORIG_HEAD +1 -0
- package/docs/wiki/.git/config +11 -0
- package/docs/wiki/.git/description +1 -0
- package/docs/wiki/.git/hooks/applypatch-msg.sample +15 -0
- package/docs/wiki/.git/hooks/commit-msg.sample +24 -0
- package/docs/wiki/.git/hooks/fsmonitor-watchman.sample +114 -0
- package/docs/wiki/.git/hooks/post-update.sample +8 -0
- package/docs/wiki/.git/hooks/pre-applypatch.sample +14 -0
- package/docs/wiki/.git/hooks/pre-commit.sample +49 -0
- package/docs/wiki/.git/hooks/pre-push.sample +53 -0
- package/docs/wiki/.git/hooks/pre-rebase.sample +169 -0
- package/docs/wiki/.git/hooks/pre-receive.sample +24 -0
- package/docs/wiki/.git/hooks/prepare-commit-msg.sample +42 -0
- package/docs/wiki/.git/hooks/update.sample +128 -0
- package/docs/wiki/.git/index +0 -0
- package/docs/wiki/.git/info/exclude +6 -0
- package/docs/wiki/.git/logs/HEAD +4 -0
- package/docs/wiki/.git/logs/refs/heads/master +4 -0
- package/docs/wiki/.git/logs/refs/remotes/origin/HEAD +1 -0
- package/docs/wiki/.git/logs/refs/remotes/origin/master +3 -0
- package/docs/wiki/.git/objects/00/d216b0774d15db2d0a2a0d4ce249b5251acc55 +3 -0
- package/docs/wiki/.git/objects/09/01d87c5241905fdfe3493cfe8f04df4a2685ea +0 -0
- package/docs/wiki/.git/objects/0d/bdd0c20c4deb6a8cc81dbbf32ecf8c09238983 +2 -0
- package/docs/wiki/.git/objects/1a/c29e4fa82422c52392f22f0f2b8d1a759535bf +0 -0
- package/docs/wiki/.git/objects/27/12f92898d3e8f68e229b6cda76570d6c66d781 +0 -0
- package/docs/wiki/.git/objects/2d/dbe22c257166b648928eeb9460ecfb71ba702d +0 -0
- package/docs/wiki/.git/objects/2f/c942ec3773efd2678d9ff98035c61fcded81a1 +0 -0
- package/docs/wiki/.git/objects/40/a2856342c67796b48911a256b764fb06888b94 +5 -0
- package/docs/wiki/.git/objects/47/53181844fc4dc563cf3aa5e80462243cb58d38 +0 -0
- package/docs/wiki/.git/objects/4e/24a95fb2e4f8ffef51f19b694451a205c06f10 +3 -0
- package/docs/wiki/.git/objects/73/31ebd96f3c7e08a9f63f05a25f939afa0d4de1 +0 -0
- package/docs/wiki/.git/objects/86/19cbb2289caa502e33fccf0ed14eecf6ba2ba0 +0 -0
- package/docs/wiki/.git/objects/a4/72f797d9d74b87c9f71a2b1539d75bb07d1e35 +0 -0
- package/docs/wiki/.git/objects/c9/9f3e4bd227d6b050b2e416f9876df49583dbf6 +0 -0
- package/docs/wiki/.git/objects/ca/e609b4ef3e0ef85fcbe0d68d1a58246584b915 +0 -0
- package/docs/wiki/.git/objects/d5/8386ca72f6d550548f3d71d74e3ac73d5ad488 +0 -0
- package/docs/wiki/.git/objects/d9/c6874a6de524bdafeb563a20d847f4fdd59a86 +0 -0
- package/docs/wiki/.git/objects/f1/c944675bb38b40ae553b0be36c14674c79af54 +0 -0
- package/docs/wiki/.git/objects/pack/pack-28da0fc7e6c08d4c5350717bfbb7b1c53e8198ad.idx +0 -0
- package/docs/wiki/.git/objects/pack/pack-28da0fc7e6c08d4c5350717bfbb7b1c53e8198ad.pack +0 -0
- package/docs/wiki/.git/packed-refs +2 -0
- package/docs/wiki/.git/refs/heads/master +1 -0
- package/docs/wiki/.git/refs/remotes/origin/HEAD +1 -0
- package/docs/wiki/.git/refs/remotes/origin/master +1 -0
- package/docs/wiki/Books-&-Posts.md +27 -0
- package/docs/wiki/Community-Helpers.md +41 -0
- package/docs/wiki/Examples.md +138 -0
- package/docs/wiki/Home.md +11 -0
- package/docs/wiki/Release-process.md +25 -0
- package/docs/wiki/Roadmap.md +23 -0
- package/docs/wiki/Videos.md +19 -0
- package/lib/actor.js +18 -1
- package/lib/assert/error.js +3 -3
- package/lib/codecept.js +9 -6
- package/lib/command/configMigrate.js +7 -6
- package/lib/command/definitions.js +98 -350
- package/lib/command/generate.js +22 -17
- package/lib/command/gherkin/init.js +2 -1
- package/lib/command/gherkin/snippets.js +6 -6
- package/lib/command/gherkin/steps.js +0 -1
- package/lib/command/info.js +40 -0
- package/lib/command/init.js +54 -41
- package/lib/command/run-multiple.js +5 -4
- package/lib/command/run-rerun.js +39 -0
- package/lib/command/run-workers.js +4 -6
- package/lib/command/run.js +8 -18
- package/lib/command/utils.js +23 -2
- package/lib/command/workers/runTests.js +1 -2
- package/lib/config.js +10 -4
- package/lib/container.js +31 -6
- package/lib/data/dataTableArgument.js +31 -0
- package/lib/data/table.js +4 -0
- package/lib/event.js +65 -1
- package/lib/helper/Appium.js +52 -38
- package/lib/helper/FileSystem.js +48 -3
- package/lib/helper/GraphQL.js +3 -2
- package/lib/helper/GraphQLDataFactory.js +1 -0
- package/lib/helper/Mochawesome.js +3 -2
- package/lib/helper/MockRequest.js +23 -5
- package/lib/helper/Nightmare.js +5 -6
- package/lib/helper/Protractor.js +7 -8
- package/lib/helper/Puppeteer.js +76 -20
- package/lib/helper/REST.js +13 -9
- package/lib/helper/SeleniumWebdriver.js +0 -17
- package/lib/helper/TestCafe.js +84 -36
- package/lib/helper/WebDriver.js +113 -59
- package/lib/helper/WebDriverIO.js +43 -59
- package/lib/helper/clientscripts/nightmare.js +66 -4
- package/lib/helper/scripts/isElementClickable.js +24 -0
- package/lib/helper.js +34 -10
- package/lib/history.js +1 -1
- package/lib/hooks.js +2 -1
- package/lib/index.js +19 -0
- package/lib/interfaces/bdd.js +4 -0
- package/lib/interfaces/featureConfig.js +10 -3
- package/lib/interfaces/gherkin.js +6 -2
- package/lib/interfaces/scenarioConfig.js +17 -6
- package/lib/listener/config.js +1 -1
- package/lib/listener/exit.js +6 -0
- package/lib/listener/steps.js +0 -1
- package/lib/listener/trace.js +0 -1
- package/lib/locator.js +67 -2
- package/lib/output.js +53 -0
- package/lib/parser.js +2 -71
- package/lib/pause.js +3 -2
- package/lib/plugin/allure.js +41 -22
- package/lib/plugin/autoLogin.js +4 -1
- package/lib/plugin/pauseOnFail.js +38 -0
- package/lib/plugin/puppeteerCoverage.js +8 -7
- package/lib/plugin/screenshotOnFail.js +13 -8
- package/lib/plugin/stepByStepReport.js +7 -6
- package/lib/plugin/wdio.js +2 -1
- package/lib/recorder.js +85 -7
- package/lib/rerun.js +81 -0
- package/lib/secret.js +6 -0
- package/lib/session.js +9 -2
- package/lib/step.js +37 -2
- package/lib/store.js +5 -1
- package/lib/ui.js +34 -8
- package/lib/utils.js +6 -13
- package/lib/within.js +5 -0
- package/package.json +49 -29
- package/typings/Mocha.d.ts +21 -0
- package/typings/Protractor.d.ts +16 -0
- package/typings/index.d.ts +169 -0
- package/typings/jsdoc.conf.js +34 -0
- package/typings/jsdoc.namespace.js +29 -0
- package/typings/types.d.ts +9827 -0
- package/typings/utils.d.ts +7 -0
- package/docs/acceptance.md +0 -409
- package/docs/api/codecept.md +0 -75
- package/docs/api/config.md +0 -49
- package/docs/api/container.md +0 -66
- package/docs/api/helper.md +0 -116
- package/docs/api/output.md +0 -67
- package/docs/api/recorder.md +0 -63
- package/docs/helpers/SeleniumWebdriver.md +0 -92
- package/docs/helpers/WebDriverIO.md +0 -1671
package/lib/helper/Puppeteer.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const fsExtra = require('fs-extra');
|
|
1
4
|
const requireg = require('requireg');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
2
7
|
const Helper = require('../helper');
|
|
3
8
|
const Locator = require('../locator');
|
|
4
9
|
const recorder = require('../recorder');
|
|
@@ -7,11 +12,13 @@ const { urlEquals } = require('../assert/equal');
|
|
|
7
12
|
const { equals } = require('../assert/equal');
|
|
8
13
|
const { empty } = require('../assert/empty');
|
|
9
14
|
const { truth } = require('../assert/truth');
|
|
15
|
+
const isElementClickable = require('./scripts/isElementClickable');
|
|
10
16
|
const {
|
|
11
17
|
xpathLocator,
|
|
12
18
|
ucfirst,
|
|
13
19
|
fileExists,
|
|
14
20
|
chunkArray,
|
|
21
|
+
toCamelCase,
|
|
15
22
|
convertCssPropertiesToCamelCase,
|
|
16
23
|
screenshotOutputFolder,
|
|
17
24
|
getNormalizedKeyAttributeValue,
|
|
@@ -21,18 +28,15 @@ const {
|
|
|
21
28
|
isColorProperty,
|
|
22
29
|
convertColorToRGBA,
|
|
23
30
|
} = require('../colorUtils');
|
|
24
|
-
const path = require('path');
|
|
25
31
|
const ElementNotFound = require('./errors/ElementNotFound');
|
|
26
32
|
const RemoteBrowserConnectionRefused = require('./errors/RemoteBrowserConnectionRefused');
|
|
27
33
|
const Popup = require('./extras/Popup');
|
|
28
34
|
const Console = require('./extras/Console');
|
|
29
35
|
const findReact = require('./extras/React');
|
|
30
|
-
const axios = require('axios');
|
|
31
|
-
const fs = require('fs');
|
|
32
|
-
const fsExtra = require('fs-extra');
|
|
33
36
|
|
|
34
37
|
let puppeteer;
|
|
35
38
|
let perfTiming;
|
|
39
|
+
let isAuthenticated = false;
|
|
36
40
|
const popupStore = new Popup();
|
|
37
41
|
const consoleLogStore = new Console();
|
|
38
42
|
|
|
@@ -50,6 +54,7 @@ const consoleLogStore = new Console();
|
|
|
50
54
|
* This helper should be configured in codecept.json or codecept.conf.js
|
|
51
55
|
*
|
|
52
56
|
* * `url`: base url of website to be tested
|
|
57
|
+
* * `basicAuth`: (optional) the basic authentication to pass to base url. Example: {username: 'username', password: 'password'}
|
|
53
58
|
* * `show`: (optional, default: false) - show Google Chrome window for debug.
|
|
54
59
|
* * `restart`: (optional, default: true) - restart browser between tests.
|
|
55
60
|
* * `disableScreenshots`: (optional, default: false) - don't save screenshot on failure.
|
|
@@ -127,6 +132,22 @@ const consoleLogStore = new Console();
|
|
|
127
132
|
* }
|
|
128
133
|
* ```
|
|
129
134
|
*
|
|
135
|
+
* #### Example #5: Target URL with provided basic authentication
|
|
136
|
+
*
|
|
137
|
+
* ```js
|
|
138
|
+
* {
|
|
139
|
+
* helpers: {
|
|
140
|
+
* Puppeteer : {
|
|
141
|
+
* url: 'http://localhost',
|
|
142
|
+
* basicAuth: {username: 'username', password: 'password'},
|
|
143
|
+
* show: true
|
|
144
|
+
* }
|
|
145
|
+
* }
|
|
146
|
+
* }
|
|
147
|
+
* ```
|
|
148
|
+
*
|
|
149
|
+
*
|
|
150
|
+
*
|
|
130
151
|
* Note: When connecting to remote browser `show` and specific `chrome` options (e.g. `headless` or `devtools`) are ignored.
|
|
131
152
|
*
|
|
132
153
|
* ## Access From Helpers
|
|
@@ -185,7 +206,10 @@ class Puppeteer extends Helper {
|
|
|
185
206
|
|
|
186
207
|
_setConfig(config) {
|
|
187
208
|
this.options = this._validateConfig(config);
|
|
188
|
-
this.puppeteerOptions =
|
|
209
|
+
this.puppeteerOptions = {
|
|
210
|
+
headless: !this.options.show,
|
|
211
|
+
...this._getOptions(config),
|
|
212
|
+
};
|
|
189
213
|
this.isRemoteBrowser = !!this.puppeteerOptions.browserWSEndpoint;
|
|
190
214
|
popupStore.defaultAction = this.options.defaultPopupAction;
|
|
191
215
|
}
|
|
@@ -247,9 +271,13 @@ class Puppeteer extends Helper {
|
|
|
247
271
|
this.debugSection('Session', 'cleaning cookies and localStorage');
|
|
248
272
|
await this.clearCookie();
|
|
249
273
|
}
|
|
250
|
-
await this.
|
|
251
|
-
|
|
252
|
-
|
|
274
|
+
const currentUrl = await this.grabCurrentUrl();
|
|
275
|
+
|
|
276
|
+
if (currentUrl.startsWith('http')) {
|
|
277
|
+
await this.executeScript('localStorage.clear();').catch((err) => {
|
|
278
|
+
if (!(err.message.indexOf("Storage is disabled inside 'data:' URLs.") > -1)) throw err;
|
|
279
|
+
});
|
|
280
|
+
}
|
|
253
281
|
await this.closeOtherTabs();
|
|
254
282
|
return this.browser;
|
|
255
283
|
}
|
|
@@ -401,6 +429,7 @@ class Puppeteer extends Helper {
|
|
|
401
429
|
* ```js
|
|
402
430
|
* await I.grabPopupText();
|
|
403
431
|
* ```
|
|
432
|
+
* @return {Promise<string | null>}
|
|
404
433
|
*/
|
|
405
434
|
async grabPopupText() {
|
|
406
435
|
if (popupStore.popup) {
|
|
@@ -513,6 +542,14 @@ class Puppeteer extends Helper {
|
|
|
513
542
|
if (!(/^\w+\:\/\//.test(url))) {
|
|
514
543
|
url = this.options.url + url;
|
|
515
544
|
}
|
|
545
|
+
|
|
546
|
+
if (this.config.basicAuth && (isAuthenticated !== true)) {
|
|
547
|
+
if (url.includes(this.options.url)) {
|
|
548
|
+
this.page.authenticate(this.config.basicAuth);
|
|
549
|
+
isAuthenticated = true;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
516
553
|
await this.page.goto(url, { waitUntil: this.options.waitForNavigation });
|
|
517
554
|
|
|
518
555
|
const performanceTiming = JSON.parse(await this.page.evaluate(() => JSON.stringify(window.performance.timing)));
|
|
@@ -1241,11 +1278,7 @@ class Puppeteer extends Helper {
|
|
|
1241
1278
|
}
|
|
1242
1279
|
|
|
1243
1280
|
/**
|
|
1244
|
-
*
|
|
1245
|
-
*
|
|
1246
|
-
* ```js
|
|
1247
|
-
* I.seeTextEquals('text', 'h1');
|
|
1248
|
-
* ```
|
|
1281
|
+
* {{> seeTextEquals }}
|
|
1249
1282
|
*/
|
|
1250
1283
|
async seeTextEquals(text, context = null) {
|
|
1251
1284
|
return proceedSee.call(this, 'assert', text, context, true);
|
|
@@ -1274,6 +1307,7 @@ class Puppeteer extends Helper {
|
|
|
1274
1307
|
* let logs = await I.grabBrowserLogs();
|
|
1275
1308
|
* console.log(JSON.stringify(logs))
|
|
1276
1309
|
* ```
|
|
1310
|
+
* @return {Promise<any[]>}
|
|
1277
1311
|
*/
|
|
1278
1312
|
async grabBrowserLogs() {
|
|
1279
1313
|
const logs = consoleLogStore.entries;
|
|
@@ -1441,7 +1475,7 @@ class Puppeteer extends Helper {
|
|
|
1441
1475
|
async grabHTMLFrom(locator) {
|
|
1442
1476
|
const els = await this._locate(locator);
|
|
1443
1477
|
assertElementExists(els, locator);
|
|
1444
|
-
const values = await Promise.all(els.map(el =>
|
|
1478
|
+
const values = await Promise.all(els.map(el => el.executionContext().evaluate(element => element.innerHTML, el)));
|
|
1445
1479
|
if (Array.isArray(values) && values.length === 1) {
|
|
1446
1480
|
return values[0];
|
|
1447
1481
|
}
|
|
@@ -1455,7 +1489,7 @@ class Puppeteer extends Helper {
|
|
|
1455
1489
|
async grabCssPropertyFrom(locator, cssProperty) {
|
|
1456
1490
|
const els = await this._locate(locator);
|
|
1457
1491
|
const res = await Promise.all(els.map(el => el.executionContext().evaluate(el => JSON.parse(JSON.stringify(getComputedStyle(el))), el)));
|
|
1458
|
-
const cssValues = res.map(props => props[cssProperty]);
|
|
1492
|
+
const cssValues = res.map(props => props[toCamelCase(cssProperty)]);
|
|
1459
1493
|
|
|
1460
1494
|
if (res.length > 0) {
|
|
1461
1495
|
return cssValues;
|
|
@@ -1692,6 +1726,22 @@ class Puppeteer extends Helper {
|
|
|
1692
1726
|
});
|
|
1693
1727
|
}
|
|
1694
1728
|
|
|
1729
|
+
/**
|
|
1730
|
+
* {{> waitForClickable }}
|
|
1731
|
+
*/
|
|
1732
|
+
async waitForClickable(locator, waitTimeout) {
|
|
1733
|
+
const els = await this._locate(locator);
|
|
1734
|
+
assertElementExists(els, locator);
|
|
1735
|
+
|
|
1736
|
+
return this.waitForFunction(isElementClickable, [els[0]], waitTimeout).catch(async (e) => {
|
|
1737
|
+
if (/failed: timeout/i.test(e.message)) {
|
|
1738
|
+
throw new Error(`element ${new Locator(locator).toString()} still not clickable after ${waitTimeout || this.options.waitForTimeout / 1000} sec`);
|
|
1739
|
+
} else {
|
|
1740
|
+
throw e;
|
|
1741
|
+
}
|
|
1742
|
+
});
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1695
1745
|
/**
|
|
1696
1746
|
* {{> waitForElement }}
|
|
1697
1747
|
* {{ react }}
|
|
@@ -1841,10 +1891,11 @@ class Puppeteer extends Helper {
|
|
|
1841
1891
|
|
|
1842
1892
|
if (locator.isXPath()) {
|
|
1843
1893
|
waiter = contextObject.waitForFunction((locator, text, $XPath) => {
|
|
1894
|
+
eval($XPath); // eslint-disable-line no-eval
|
|
1844
1895
|
const el = $XPath(null, locator);
|
|
1845
1896
|
if (!el.length) return false;
|
|
1846
1897
|
return el[0].innerText.indexOf(text) > -1;
|
|
1847
|
-
}, { timeout: waitTimeout }, locator.value, text, $XPath);
|
|
1898
|
+
}, { timeout: waitTimeout }, locator.value, text, $XPath.toString());
|
|
1848
1899
|
}
|
|
1849
1900
|
} else {
|
|
1850
1901
|
waiter = contextObject.waitForFunction(text => document.body.innerText.indexOf(text) > -1, { timeout: waitTimeout }, text);
|
|
@@ -1864,7 +1915,7 @@ class Puppeteer extends Helper {
|
|
|
1864
1915
|
* ```
|
|
1865
1916
|
*
|
|
1866
1917
|
* @param {string|function} urlOrPredicate
|
|
1867
|
-
* @param {number
|
|
1918
|
+
* @param {?number} [sec=null] seconds to wait
|
|
1868
1919
|
*/
|
|
1869
1920
|
async waitForRequest(urlOrPredicate, sec = null) {
|
|
1870
1921
|
const timeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -1880,7 +1931,7 @@ class Puppeteer extends Helper {
|
|
|
1880
1931
|
* ```
|
|
1881
1932
|
*
|
|
1882
1933
|
* @param {string|function} urlOrPredicate
|
|
1883
|
-
* @param {number
|
|
1934
|
+
* @param {?number} [sec=null] number of seconds to wait
|
|
1884
1935
|
*/
|
|
1885
1936
|
async waitForResponse(urlOrPredicate, sec = null) {
|
|
1886
1937
|
const timeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -1907,7 +1958,8 @@ class Puppeteer extends Helper {
|
|
|
1907
1958
|
throw new Error('Element #invalidIframeSelector was not found by text|CSS|XPath');
|
|
1908
1959
|
}
|
|
1909
1960
|
return;
|
|
1910
|
-
}
|
|
1961
|
+
}
|
|
1962
|
+
if (!locator) {
|
|
1911
1963
|
this.context = await this.page.mainFrame().$('body');
|
|
1912
1964
|
return;
|
|
1913
1965
|
}
|
|
@@ -1949,7 +2001,11 @@ class Puppeteer extends Helper {
|
|
|
1949
2001
|
* @param {*} opts
|
|
1950
2002
|
*/
|
|
1951
2003
|
async waitForNavigation(opts = {}) {
|
|
1952
|
-
opts =
|
|
2004
|
+
opts = {
|
|
2005
|
+
timeout: this.options.getPageTimeout,
|
|
2006
|
+
waitUntil: this.options.waitForNavigation,
|
|
2007
|
+
...opts,
|
|
2008
|
+
};
|
|
1953
2009
|
return this.page.waitForNavigation(opts);
|
|
1954
2010
|
}
|
|
1955
2011
|
|
package/lib/helper/REST.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
const Helper = require('../helper');
|
|
2
|
-
const requireg = require('requireg');
|
|
3
1
|
const axios = require('axios').default;
|
|
2
|
+
const requireg = require('requireg');
|
|
3
|
+
|
|
4
|
+
const Helper = require('../helper');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* REST helper allows to send additional requests to the REST API during acceptance tests.
|
|
@@ -16,12 +17,15 @@ const axios = require('axios').default;
|
|
|
16
17
|
* ## Example
|
|
17
18
|
*
|
|
18
19
|
* ```js
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
20
|
+
*{
|
|
21
|
+
* helpers: {
|
|
22
|
+
* REST: {
|
|
23
|
+
* endpoint: 'http://site.com/api',
|
|
24
|
+
* onRequest: (request) => {
|
|
25
|
+
* request.headers.auth = '123';
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
*}
|
|
25
29
|
* ```
|
|
26
30
|
*
|
|
27
31
|
* ## Access From Helpers
|
|
@@ -46,7 +50,7 @@ class REST extends Helper {
|
|
|
46
50
|
endpoint: '',
|
|
47
51
|
};
|
|
48
52
|
this.options = Object.assign(this.options, config);
|
|
49
|
-
this.headers =
|
|
53
|
+
this.headers = { ...this.options.defaultHeaders };
|
|
50
54
|
axios.defaults.headers = this.options.defaultHeaders;
|
|
51
55
|
}
|
|
52
56
|
|
|
@@ -1,21 +1,4 @@
|
|
|
1
|
-
const requireg = require('requireg');
|
|
2
|
-
const Locator = require('../locator');
|
|
3
1
|
const Helper = require('../helper');
|
|
4
|
-
const stringIncludes = require('../assert/include').includes;
|
|
5
|
-
const urlEquals = require('../assert/equal').urlEquals;
|
|
6
|
-
const equals = require('../assert/equal').equals;
|
|
7
|
-
const empty = require('../assert/empty').empty;
|
|
8
|
-
const truth = require('../assert/truth').truth;
|
|
9
|
-
const xpathLocator = require('../utils').xpathLocator;
|
|
10
|
-
const fileExists = require('../utils').fileExists;
|
|
11
|
-
const clearString = require('../utils').clearString;
|
|
12
|
-
const co = require('co');
|
|
13
|
-
const path = require('path');
|
|
14
|
-
const recorder = require('../recorder');
|
|
15
|
-
const ElementNotFound = require('./errors/ElementNotFound');
|
|
16
|
-
const Protractor = require('./Protractor');
|
|
17
|
-
|
|
18
|
-
const withinStore = {};
|
|
19
2
|
|
|
20
3
|
/**
|
|
21
4
|
* SeleniumWebdriver helper is based on the official [Selenium Webdriver JS](https://www.npmjs.com/package/selenium-webdriver)
|
package/lib/helper/TestCafe.js
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const assert = require('assert');
|
|
4
4
|
const path = require('path');
|
|
5
|
+
const qrcode = require('qrcode-terminal');
|
|
5
6
|
const requireg = require('requireg');
|
|
6
7
|
const createTestCafe = require('testcafe');
|
|
7
8
|
const { Selector, ClientFunction } = require('testcafe');
|
|
8
|
-
const ElementNotFound = require('./errors/ElementNotFound');
|
|
9
9
|
|
|
10
|
+
const ElementNotFound = require('./errors/ElementNotFound');
|
|
10
11
|
const testControllerHolder = require('./testcafe/testControllerHolder');
|
|
11
12
|
const {
|
|
12
13
|
mapError,
|
|
@@ -67,6 +68,21 @@ const getHtmlSource = t => ClientFunction(() => document.getElementsByTagName('h
|
|
|
67
68
|
* }
|
|
68
69
|
* ```
|
|
69
70
|
*
|
|
71
|
+
* To use remote device you can provide 'remote' as browser parameter this will display a link with QR Code
|
|
72
|
+
* See https://devexpress.github.io/testcafe/documentation/recipes/test-on-remote-computers-and-mobile-devices.html
|
|
73
|
+
* #### Example #2: Remote browser connection
|
|
74
|
+
*
|
|
75
|
+
* ```js
|
|
76
|
+
* {
|
|
77
|
+
* helpers: {
|
|
78
|
+
* TestCafe : {
|
|
79
|
+
* url: "http://localhost",
|
|
80
|
+
* waitForTimeout: 15000,
|
|
81
|
+
* browser: "remote"
|
|
82
|
+
* }
|
|
83
|
+
* }
|
|
84
|
+
* }
|
|
85
|
+
* ```
|
|
70
86
|
*
|
|
71
87
|
* ## Access From Helpers
|
|
72
88
|
*
|
|
@@ -96,7 +112,7 @@ class TestCafe extends Helper {
|
|
|
96
112
|
this.context = undefined; // TODO Not sure if this applies to testcafe
|
|
97
113
|
|
|
98
114
|
|
|
99
|
-
this.options =
|
|
115
|
+
this.options = {
|
|
100
116
|
url: 'http://localhost',
|
|
101
117
|
show: false,
|
|
102
118
|
browser: 'chrome',
|
|
@@ -108,7 +124,8 @@ class TestCafe extends Helper {
|
|
|
108
124
|
fullPageScreenshots: false,
|
|
109
125
|
disableScreenshots: false,
|
|
110
126
|
windowSize: undefined,
|
|
111
|
-
|
|
127
|
+
...config,
|
|
128
|
+
};
|
|
112
129
|
}
|
|
113
130
|
|
|
114
131
|
// TOOD Do a requirements check
|
|
@@ -130,12 +147,12 @@ class TestCafe extends Helper {
|
|
|
130
147
|
];
|
|
131
148
|
}
|
|
132
149
|
|
|
133
|
-
async
|
|
150
|
+
async _configureAndStartBrowser() {
|
|
134
151
|
this.dummyTestcafeFile = createTestFile(global.output_dir); // create a dummy test file to get hold of the test controller
|
|
135
152
|
|
|
136
153
|
this.iteration += 2; // Use different ports for each test run
|
|
137
154
|
// @ts-ignore
|
|
138
|
-
this.testcafe = await createTestCafe('
|
|
155
|
+
this.testcafe = await createTestCafe('', null, null);
|
|
139
156
|
|
|
140
157
|
this.debugSection('_before', 'Starting testcafe browser...');
|
|
141
158
|
|
|
@@ -143,6 +160,19 @@ class TestCafe extends Helper {
|
|
|
143
160
|
|
|
144
161
|
// TODO Do we have to cleanup the runner?
|
|
145
162
|
const runner = this.testcafe.createRunner();
|
|
163
|
+
|
|
164
|
+
this.options.browser !== 'remote' ? this._startBrowser(runner) : this._startRemoteBrowser(runner);
|
|
165
|
+
|
|
166
|
+
this.t = await testControllerHolder.get();
|
|
167
|
+
assert(this.t, 'Expected to have the testcafe test controller');
|
|
168
|
+
|
|
169
|
+
if (this.options.windowSize && this.options.windowSize.indexOf('x') > 0) {
|
|
170
|
+
const dimensions = this.options.windowSize.split('x');
|
|
171
|
+
await this.t.resizeWindow(parseInt(dimensions[0], 10), parseInt(dimensions[1], 10));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async _startBrowser(runner) {
|
|
146
176
|
runner
|
|
147
177
|
.src(this.dummyTestcafeFile)
|
|
148
178
|
.screenshots(global.output_dir, !this.options.disableScreenshots)
|
|
@@ -166,16 +196,31 @@ class TestCafe extends Helper {
|
|
|
166
196
|
this.isRunning = false;
|
|
167
197
|
this.testcafe.close();
|
|
168
198
|
});
|
|
199
|
+
}
|
|
169
200
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
201
|
+
async _startRemoteBrowser(runner) {
|
|
202
|
+
const remoteConnection = await this.testcafe.createBrowserConnection();
|
|
203
|
+
console.log('Connect your device to the following URL or scan QR Code: ', remoteConnection.url);
|
|
204
|
+
qrcode.generate(remoteConnection.url);
|
|
205
|
+
remoteConnection.once('ready', () => {
|
|
206
|
+
runner
|
|
207
|
+
.src(this.dummyTestcafeFile)
|
|
208
|
+
.browsers(remoteConnection)
|
|
209
|
+
.reporter('minimal')
|
|
210
|
+
.run({
|
|
211
|
+
selectorTimeout: this.options.waitForTimeout,
|
|
212
|
+
skipJsErrors: true,
|
|
213
|
+
skipUncaughtErrors: true,
|
|
214
|
+
})
|
|
215
|
+
.catch((err) => {
|
|
216
|
+
this.debugSection('_before', `Error ${err.toString()}`);
|
|
217
|
+
this.isRunning = false;
|
|
218
|
+
this.testcafe.close();
|
|
219
|
+
});
|
|
220
|
+
});
|
|
177
221
|
}
|
|
178
222
|
|
|
223
|
+
|
|
179
224
|
async _stopBrowser() {
|
|
180
225
|
this.debugSection('_after', 'Stopping testcafe browser...');
|
|
181
226
|
|
|
@@ -190,19 +235,20 @@ class TestCafe extends Helper {
|
|
|
190
235
|
this.isRunning = false;
|
|
191
236
|
}
|
|
192
237
|
|
|
193
|
-
_init() {
|
|
238
|
+
_init() {
|
|
239
|
+
}
|
|
194
240
|
|
|
195
241
|
async _beforeSuite() {
|
|
196
242
|
if (!this.options.restart && !this.options.manualStart && !this.isRunning) {
|
|
197
243
|
this.debugSection('Session', 'Starting singleton browser session');
|
|
198
|
-
return this.
|
|
244
|
+
return this._configureAndStartBrowser();
|
|
199
245
|
}
|
|
200
246
|
}
|
|
201
247
|
|
|
202
248
|
|
|
203
249
|
async _before() {
|
|
204
|
-
if (this.options.restart && !this.options.manualStart) return this.
|
|
205
|
-
if (!this.isRunning && !this.options.manualStart) return this.
|
|
250
|
+
if (this.options.restart && !this.options.manualStart) return this._configureAndStartBrowser();
|
|
251
|
+
if (!this.isRunning && !this.options.manualStart) return this._configureAndStartBrowser();
|
|
206
252
|
this.context = null;
|
|
207
253
|
}
|
|
208
254
|
|
|
@@ -331,9 +377,10 @@ class TestCafe extends Helper {
|
|
|
331
377
|
assertElementExists(els, field, 'Field');
|
|
332
378
|
const el = await els.nth(0);
|
|
333
379
|
|
|
334
|
-
|
|
335
|
-
.
|
|
336
|
-
.pressKey('
|
|
380
|
+
const res = await this.t
|
|
381
|
+
.selectText(el)
|
|
382
|
+
.pressKey('delete');
|
|
383
|
+
return res;
|
|
337
384
|
}
|
|
338
385
|
|
|
339
386
|
/**
|
|
@@ -494,8 +541,9 @@ class TestCafe extends Helper {
|
|
|
494
541
|
await this.t.click(optEl, clickOpts).catch(mapError);
|
|
495
542
|
continue;
|
|
496
543
|
}
|
|
497
|
-
|
|
498
|
-
} catch (err) {
|
|
544
|
+
// eslint-disable-next-line no-empty
|
|
545
|
+
} catch (err) {
|
|
546
|
+
}
|
|
499
547
|
|
|
500
548
|
try {
|
|
501
549
|
const sel = `[value="${opt}"]`;
|
|
@@ -503,8 +551,9 @@ class TestCafe extends Helper {
|
|
|
503
551
|
if (await optEl.count) {
|
|
504
552
|
await this.t.click(optEl, clickOpts).catch(mapError);
|
|
505
553
|
}
|
|
506
|
-
|
|
507
|
-
} catch (err) {
|
|
554
|
+
// eslint-disable-next-line no-empty
|
|
555
|
+
} catch (err) {
|
|
556
|
+
}
|
|
508
557
|
}
|
|
509
558
|
}
|
|
510
559
|
|
|
@@ -516,22 +565,22 @@ class TestCafe extends Helper {
|
|
|
516
565
|
}
|
|
517
566
|
|
|
518
567
|
/**
|
|
519
|
-
|
|
520
|
-
|
|
568
|
+
* {{> dontSeeInCurrentUrl }}
|
|
569
|
+
*/
|
|
521
570
|
async dontSeeInCurrentUrl(url) {
|
|
522
571
|
stringIncludes('url').negate(url, await getPageUrl(this.t)().catch(mapError));
|
|
523
572
|
}
|
|
524
573
|
|
|
525
574
|
/**
|
|
526
|
-
|
|
527
|
-
|
|
575
|
+
* {{> seeCurrentUrlEquals }}
|
|
576
|
+
*/
|
|
528
577
|
async seeCurrentUrlEquals(url) {
|
|
529
578
|
urlEquals(this.options.url).assert(url, await getPageUrl(this.t)().catch(mapError));
|
|
530
579
|
}
|
|
531
580
|
|
|
532
581
|
/**
|
|
533
|
-
|
|
534
|
-
|
|
582
|
+
* {{> dontSeeCurrentUrlEquals }}
|
|
583
|
+
*/
|
|
535
584
|
async dontSeeCurrentUrlEquals(url) {
|
|
536
585
|
urlEquals(this.options.url).negate(url, await getPageUrl(this.t)().catch(mapError));
|
|
537
586
|
}
|
|
@@ -746,14 +795,16 @@ class TestCafe extends Helper {
|
|
|
746
795
|
async grabAttributeFrom(locator, attr) {
|
|
747
796
|
const sel = await findElements.call(this, this.context, locator);
|
|
748
797
|
assertElementExists(sel);
|
|
749
|
-
return (await sel.nth(0)).
|
|
798
|
+
return (await sel.nth(0)).getAttribute(attr);
|
|
750
799
|
}
|
|
751
800
|
|
|
752
801
|
/**
|
|
753
802
|
* {{> grabValueFrom }}
|
|
754
803
|
*/
|
|
755
804
|
async grabValueFrom(locator) {
|
|
756
|
-
|
|
805
|
+
const sel = await findElements.call(this, this.context, locator);
|
|
806
|
+
assertElementExists(sel);
|
|
807
|
+
return (await sel.nth(0)).value;
|
|
757
808
|
}
|
|
758
809
|
|
|
759
810
|
/**
|
|
@@ -990,10 +1041,7 @@ class TestCafe extends Helper {
|
|
|
990
1041
|
}
|
|
991
1042
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
992
1043
|
|
|
993
|
-
const clientFn = createClientFunction((
|
|
994
|
-
const currUrl = decodeURIComponent(decodeURIComponent(decodeURIComponent(window.location.href)));
|
|
995
|
-
return currUrl.indexOf(urlPart) > -1;
|
|
996
|
-
}, args);
|
|
1044
|
+
const clientFn = createClientFunction(fn, args).with({ boundTestRun: this.t });
|
|
997
1045
|
|
|
998
1046
|
return waitForFunction(clientFn, waitTimeout);
|
|
999
1047
|
}
|
|
@@ -1076,7 +1124,7 @@ async function waitForFunction(browserFn, waitTimeout) {
|
|
|
1076
1124
|
let result;
|
|
1077
1125
|
try {
|
|
1078
1126
|
result = await browserFn();
|
|
1079
|
-
|
|
1127
|
+
// eslint-disable-next-line no-empty
|
|
1080
1128
|
} catch (err) {
|
|
1081
1129
|
throw new Error(`Error running function ${err.toString()}`);
|
|
1082
1130
|
}
|