codeceptjs 3.0.6 → 3.0.7
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 +34 -8
- package/bin/codecept.js +1 -0
- package/docs/build/Appium.js +1 -0
- package/docs/build/GraphQL.js +9 -10
- package/docs/build/Playwright.js +123 -22
- package/docs/build/REST.js +4 -3
- package/docs/build/WebDriver.js +82 -14
- package/docs/changelog.md +35 -9
- package/docs/email.md +8 -8
- package/docs/examples.md +3 -3
- package/docs/helpers/MockRequest.md +3 -3
- package/docs/helpers/Playwright.md +10 -1
- package/docs/helpers/WebDriver.md +1 -0
- package/docs/locators.md +27 -0
- package/docs/nightmare.md +0 -5
- package/docs/parallel.md +14 -7
- package/docs/playwright.md +6 -6
- package/docs/reports.md +5 -4
- package/lib/command/interactive.js +4 -2
- package/lib/helper/GraphQL.js +9 -10
- package/lib/helper/Playwright.js +46 -5
- package/lib/helper/WebDriver.js +82 -14
- package/lib/output.js +3 -0
- package/lib/plugin/screenshotOnFail.js +5 -0
- package/lib/ui.js +6 -2
- package/package.json +2 -2
- package/typings/index.d.ts +44 -21
- package/typings/types.d.ts +17 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,36 @@
|
|
|
1
|
+
## 3.0.7
|
|
2
|
+
|
|
3
|
+
Documentation fixes:
|
|
4
|
+
* Remove broken link from `Nightmare helper`. See #2860 by @Arhell
|
|
5
|
+
* Fixed broken links in `playwright.md`. See #2848 by @johnhoodjr
|
|
6
|
+
* Fix mocha-multi config example. See #2881 by @rimesc
|
|
7
|
+
* Fix small errors in email documentation file. See #2884 by @mkrtchian
|
|
8
|
+
* Improve documentation for `Sharing Data Between Workers` section. See #2891 by @ngraf
|
|
9
|
+
|
|
10
|
+
Features:
|
|
11
|
+
* [WebDriver] Shadow DOM Support for `Webdriver`. See #2741 by @gkushang
|
|
12
|
+
* [Release management] Introduce the versioning automatically, it follows the semantics versioning. See #2883 by @PeterNgTr
|
|
13
|
+
* Adding opts into `Scenario.skip` that it would be useful for building reports. See #2867 by @AlexKo4
|
|
14
|
+
* Added support for attaching screenshots to [cucumberJsonReporter](https://github.com/ktryniszewski-mdsol/codeceptjs-cucumber-json-reporter) See #2888 by @fijijavis
|
|
15
|
+
* Supported config file for `codeceptjs shell` command. See #2895 by @PeterNgTr:
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
npx codeceptjs shell -c foo.conf.js
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Bug fixes:
|
|
22
|
+
* [GraphQL] Use a helper-specific instance of Axios to avoid contaminating global defaults. See #2868 by @vanvoljg
|
|
23
|
+
* A default system color is used when passing non supported system color when using I.say(). See #2874 by @PeterNgTr
|
|
24
|
+
* [Playwright] Avoid the timout due to calling the click on invisible elements. See #2875 by cbayer97
|
|
25
|
+
|
|
26
|
+
|
|
1
27
|
## 3.0.6
|
|
2
28
|
|
|
3
|
-
* [Playwright] Added `electron` as a browser to config. See #2834 by @cbayer97
|
|
29
|
+
* [Playwright] Added `electron` as a browser to config. See #2834 by @cbayer97
|
|
4
30
|
* [Playwright] Implemented `launchPersistentContext` to be able to launch persistent remote browsers. See #2817 by @brunoqueiros. Fixes #2376.
|
|
5
31
|
* Fixed printing logs and stack traces for `run-workers`. See #2857 by @haveac1gar. Fixes #2621, #2852
|
|
6
|
-
* Emit custom messages from worker to the main thread. See #2824 by @jccguimaraes
|
|
7
|
-
* Improved workers processes output. See #2804 by @drfiresign
|
|
32
|
+
* Emit custom messages from worker to the main thread. See #2824 by @jccguimaraes
|
|
33
|
+
* Improved workers processes output. See #2804 by @drfiresign
|
|
8
34
|
* BDD. Added ability to use an array of feature files inside config in `gherkin.features`. See #2814 by @jbergeronjr
|
|
9
35
|
|
|
10
36
|
```js
|
|
@@ -13,8 +39,8 @@
|
|
|
13
39
|
"./features/api_features/*.feature"
|
|
14
40
|
],
|
|
15
41
|
```
|
|
16
|
-
* Added `getQueueId` to reporter to rerun a specific promise. See #2837 by @jonatask
|
|
17
|
-
* **Added `fakerTransform` plugin** to use faker data in Gherkin scenarios. See #2854 by @adrielcodeco
|
|
42
|
+
* Added `getQueueId` to reporter to rerun a specific promise. See #2837 by @jonatask
|
|
43
|
+
* **Added `fakerTransform` plugin** to use faker data in Gherkin scenarios. See #2854 by @adrielcodeco
|
|
18
44
|
|
|
19
45
|
```feature
|
|
20
46
|
Scenario Outline: ...
|
|
@@ -26,7 +52,7 @@ Scenario Outline: ...
|
|
|
26
52
|
| productName | customer | email | anythingMore |
|
|
27
53
|
| {{commerce.product}} | Dr. {{name.findName}} | {{internet.email}} | staticData |
|
|
28
54
|
```
|
|
29
|
-
* [REST] Use class instance of axios, not the global instance, to avoid contaminating global configuration. #2846 by @vanvoljg
|
|
55
|
+
* [REST] Use class instance of axios, not the global instance, to avoid contaminating global configuration. #2846 by @vanvoljg
|
|
30
56
|
* [Appium] Added `tunnelIdentifier` config option to provide tunnel for SauceLabs. See #2832 by @gurjeetbains
|
|
31
57
|
|
|
32
58
|
## 3.0.5
|
|
@@ -34,9 +60,9 @@ Scenario Outline: ...
|
|
|
34
60
|
|
|
35
61
|
Features:
|
|
36
62
|
|
|
37
|
-
* **[Official Docker image for CodeceptJS v3](https://hub.docker.com/r/codeceptjs/codeceptjs)**. New Docker image is based on official Playwright image and supports Playwright, Puppeteer, WebDriver engines. Thanks @VikentyShevyrin
|
|
63
|
+
* **[Official Docker image for CodeceptJS v3](https://hub.docker.com/r/codeceptjs/codeceptjs)**. New Docker image is based on official Playwright image and supports Playwright, Puppeteer, WebDriver engines. Thanks @VikentyShevyrin
|
|
38
64
|
* Better support for Typescript `codecept.conf.ts` configuration files. See #2750 by @elaichenkov
|
|
39
|
-
* Propagate more events for custom parallel script. See #2796 by @jccguimaraes
|
|
65
|
+
* Propagate more events for custom parallel script. See #2796 by @jccguimaraes
|
|
40
66
|
* [mocha-junit-reporter] Now supports attachments, see documentation for details. See #2675 by @Shard
|
|
41
67
|
* CustomLocators interface for TypeScript to extend from LocatorOrString. See #2798 by @danielrentz
|
|
42
68
|
* [REST] Mask sensitive data from log messages.
|
package/bin/codecept.js
CHANGED
|
@@ -27,6 +27,7 @@ program.command('shell [path]')
|
|
|
27
27
|
.description('Interactive shell')
|
|
28
28
|
.option('--verbose', 'output internal logging information')
|
|
29
29
|
.option('--profile [value]', 'configuration profile to be used')
|
|
30
|
+
.option('-c, --config [file]', 'configuration file to be used')
|
|
30
31
|
.action(require('../lib/command/interactive'));
|
|
31
32
|
|
|
32
33
|
program.command('list [path]')
|
package/docs/build/Appium.js
CHANGED
|
@@ -183,6 +183,7 @@ class Appium extends Webdriver {
|
|
|
183
183
|
config.capabilities.browserName = config.browser || config.capabilities.browserName;
|
|
184
184
|
config.capabilities.app = config.app || config.capabilities.app;
|
|
185
185
|
config.capabilities.platformName = config.platform || config.capabilities.platformName;
|
|
186
|
+
config.capabilities.tunnelIdentifier = config.tunnelIdentifier || config.capabilities.tunnelIdentifier; // Adding the code to connect to sauce labs via sauce tunnel
|
|
186
187
|
config.waitForTimeout /= 1000; // convert to seconds
|
|
187
188
|
|
|
188
189
|
// [CodeceptJS compatible] transform host to hostname
|
package/docs/build/GraphQL.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
const axios = require('axios').default;
|
|
2
2
|
const Helper = require('../helper');
|
|
3
3
|
|
|
4
|
-
let headers = {};
|
|
5
|
-
|
|
6
4
|
/**
|
|
7
5
|
* GraphQL helper allows to send additional requests to a GraphQl endpoint during acceptance tests.
|
|
8
6
|
* [Axios](https://github.com/axios/axios) library is used to perform requests.
|
|
@@ -41,15 +39,16 @@ let headers = {};
|
|
|
41
39
|
class GraphQL extends Helper {
|
|
42
40
|
constructor(config) {
|
|
43
41
|
super(config);
|
|
44
|
-
axios =
|
|
42
|
+
this.axios = axios.create();
|
|
43
|
+
this.headers = {};
|
|
45
44
|
this.options = {
|
|
46
45
|
timeout: 10000,
|
|
47
46
|
defaultHeaders: {},
|
|
48
47
|
endpoint: '',
|
|
49
48
|
};
|
|
50
49
|
this.options = Object.assign(this.options, config);
|
|
51
|
-
headers = { ...this.options.defaultHeaders };
|
|
52
|
-
axios.defaults.headers = this.options.defaultHeaders;
|
|
50
|
+
this.headers = { ...this.options.defaultHeaders };
|
|
51
|
+
this.axios.defaults.headers = this.options.defaultHeaders;
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
static _checkRequirements() {
|
|
@@ -66,10 +65,10 @@ class GraphQL extends Helper {
|
|
|
66
65
|
* @param {object} request
|
|
67
66
|
*/
|
|
68
67
|
async _executeQuery(request) {
|
|
69
|
-
axios.defaults.timeout = request.timeout || this.options.timeout;
|
|
68
|
+
this.axios.defaults.timeout = request.timeout || this.options.timeout;
|
|
70
69
|
|
|
71
|
-
if (headers && headers.auth) {
|
|
72
|
-
request.auth = headers.auth;
|
|
70
|
+
if (this.headers && this.headers.auth) {
|
|
71
|
+
request.auth = this.headers.auth;
|
|
73
72
|
}
|
|
74
73
|
|
|
75
74
|
request.headers = Object.assign(request.headers, {
|
|
@@ -84,7 +83,7 @@ class GraphQL extends Helper {
|
|
|
84
83
|
|
|
85
84
|
let response;
|
|
86
85
|
try {
|
|
87
|
-
response = await axios(request);
|
|
86
|
+
response = await this.axios(request);
|
|
88
87
|
} catch (err) {
|
|
89
88
|
if (!err.response) throw err;
|
|
90
89
|
this.debugSection(
|
package/docs/build/Playwright.js
CHANGED
|
@@ -35,9 +35,10 @@ let defaultSelectorEnginesInitialized = false;
|
|
|
35
35
|
|
|
36
36
|
const popupStore = new Popup();
|
|
37
37
|
const consoleLogStore = new Console();
|
|
38
|
-
const availableBrowsers = ['chromium', 'webkit', 'firefox'];
|
|
38
|
+
const availableBrowsers = ['chromium', 'webkit', 'firefox', 'electron'];
|
|
39
39
|
|
|
40
40
|
const { createValueEngine, createDisabledEngine } = require('./extras/PlaywrightPropEngine');
|
|
41
|
+
|
|
41
42
|
/**
|
|
42
43
|
* Uses [Playwright](https://github.com/microsoft/playwright) library to run tests inside:
|
|
43
44
|
*
|
|
@@ -58,7 +59,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
|
|
|
58
59
|
* This helper should be configured in codecept.json or codecept.conf.js
|
|
59
60
|
*
|
|
60
61
|
* * `url`: base url of website to be tested
|
|
61
|
-
* * `browser`: a browser to test on, either: `chromium`, `firefox`, `webkit`. Default: chromium.
|
|
62
|
+
* * `browser`: a browser to test on, either: `chromium`, `firefox`, `webkit`, `electron`. Default: chromium.
|
|
62
63
|
* * `show`: (optional, default: false) - show browser window.
|
|
63
64
|
* * `restart`: (optional, default: true) - restart browser between tests.
|
|
64
65
|
* * `disableScreenshots`: (optional, default: false) - don't save screenshot on failure.
|
|
@@ -77,6 +78,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
|
|
|
77
78
|
* * `userAgent`: (optional) user-agent string.
|
|
78
79
|
* * `manualStart`: (optional, default: false) - do not start browser before a test, start it manually inside a helper with `this.helpers["Playwright"]._startBrowser()`.
|
|
79
80
|
* * `chromium`: (optional) pass additional chromium options
|
|
81
|
+
* * `electron`: (optional) pass additional electron options
|
|
80
82
|
*
|
|
81
83
|
* #### Example #1: Wait for 0 network connections.
|
|
82
84
|
*
|
|
@@ -121,7 +123,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
|
|
|
121
123
|
* }
|
|
122
124
|
* ```
|
|
123
125
|
*
|
|
124
|
-
* #### Example #4: Connect to remote browser by specifying [websocket endpoint](https://
|
|
126
|
+
* #### Example #4: Connect to remote browser by specifying [websocket endpoint](https://playwright.dev/docs/api/class-browsertype#browsertypeconnectparams)
|
|
125
127
|
*
|
|
126
128
|
* ```js
|
|
127
129
|
* {
|
|
@@ -129,7 +131,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
|
|
|
129
131
|
* Playwright: {
|
|
130
132
|
* url: "http://localhost",
|
|
131
133
|
* chromium: {
|
|
132
|
-
* browserWSEndpoint:
|
|
134
|
+
* browserWSEndpoint: { wsEndpoint: 'ws://localhost:9222/devtools/browser/c5aa6160-b5bc-4d53-bb49-6ecb36cd2e0a' }
|
|
133
135
|
* }
|
|
134
136
|
* }
|
|
135
137
|
* }
|
|
@@ -147,6 +149,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
|
|
|
147
149
|
* url: "http://localhost",
|
|
148
150
|
* show: true // headless mode not supported for extensions
|
|
149
151
|
* chromium: {
|
|
152
|
+
* userDataDir: '/tmp/playwright-tmp', // necessary to launch the browser in normal mode instead of incognito,
|
|
150
153
|
* args: [
|
|
151
154
|
* `--disable-extensions-except=${pathToExtension}`,
|
|
152
155
|
* `--load-extension=${pathToExtension}`
|
|
@@ -206,6 +209,8 @@ class Playwright extends Helper {
|
|
|
206
209
|
this.isAuthenticated = false;
|
|
207
210
|
this.sessionPages = {};
|
|
208
211
|
this.activeSessionName = '';
|
|
212
|
+
this.isElectron = false;
|
|
213
|
+
this.electronSessions = [];
|
|
209
214
|
|
|
210
215
|
// override defaults with config
|
|
211
216
|
this._setConfig(config);
|
|
@@ -257,6 +262,8 @@ class Playwright extends Helper {
|
|
|
257
262
|
...this._getOptionsForBrowser(config),
|
|
258
263
|
};
|
|
259
264
|
this.isRemoteBrowser = !!this.playwrightOptions.browserWSEndpoint;
|
|
265
|
+
this.isElectron = this.options.browser === 'electron';
|
|
266
|
+
this.userDataDir = this.playwrightOptions.userDataDir;
|
|
260
267
|
popupStore.defaultAction = this.options.defaultPopupAction;
|
|
261
268
|
}
|
|
262
269
|
|
|
@@ -268,7 +275,7 @@ class Playwright extends Helper {
|
|
|
268
275
|
},
|
|
269
276
|
{
|
|
270
277
|
name: 'browser',
|
|
271
|
-
message: 'Browser in which testing will be performed. Possible options: chromium, firefox or
|
|
278
|
+
message: 'Browser in which testing will be performed. Possible options: chromium, firefox, webkit or electron',
|
|
272
279
|
default: 'chromium',
|
|
273
280
|
},
|
|
274
281
|
];
|
|
@@ -320,11 +327,21 @@ class Playwright extends Helper {
|
|
|
320
327
|
async _after() {
|
|
321
328
|
if (!this.isRunning) return;
|
|
322
329
|
|
|
330
|
+
if (this.isElectron) {
|
|
331
|
+
this.browser.close();
|
|
332
|
+
this.electronSessions.forEach(session => session.close());
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
|
|
323
336
|
// close other sessions
|
|
324
|
-
|
|
325
|
-
|
|
337
|
+
try {
|
|
338
|
+
const contexts = await this.browser.contexts();
|
|
339
|
+
contexts.shift();
|
|
326
340
|
|
|
327
|
-
|
|
341
|
+
await Promise.all(contexts.map(c => c.close()));
|
|
342
|
+
} catch (e) {
|
|
343
|
+
console.log(e);
|
|
344
|
+
}
|
|
328
345
|
|
|
329
346
|
if (this.options.restart) {
|
|
330
347
|
this.isRunning = false;
|
|
@@ -371,12 +388,22 @@ class Playwright extends Helper {
|
|
|
371
388
|
this.debugSection('New Context', config ? JSON.stringify(config) : 'opened');
|
|
372
389
|
this.activeSessionName = sessionName;
|
|
373
390
|
|
|
374
|
-
|
|
375
|
-
|
|
391
|
+
let browserContext;
|
|
392
|
+
let page;
|
|
393
|
+
if (this.isElectron) {
|
|
394
|
+
const browser = await playwright._electron.launch(this.playwrightOptions);
|
|
395
|
+
this.electronSessions.push(browser);
|
|
396
|
+
browserContext = browser.context();
|
|
397
|
+
page = await browser.firstWindow();
|
|
398
|
+
} else {
|
|
399
|
+
browserContext = await this.browser.newContext(config);
|
|
400
|
+
page = await browserContext.newPage();
|
|
401
|
+
}
|
|
402
|
+
|
|
376
403
|
targetCreatedHandler.call(this, page);
|
|
377
404
|
this._setPage(page);
|
|
378
405
|
// Create a new page inside context.
|
|
379
|
-
return
|
|
406
|
+
return browserContext;
|
|
380
407
|
},
|
|
381
408
|
stop: async () => {
|
|
382
409
|
// is closed by _after
|
|
@@ -496,6 +523,7 @@ class Playwright extends Helper {
|
|
|
496
523
|
if (!page) return;
|
|
497
524
|
page.setDefaultNavigationTimeout(this.options.getPageTimeout);
|
|
498
525
|
this.context = await this.page;
|
|
526
|
+
this.contextLocator = null;
|
|
499
527
|
if (this.config.browser === 'chrome') {
|
|
500
528
|
await page.bringToFront();
|
|
501
529
|
}
|
|
@@ -554,15 +582,19 @@ class Playwright extends Helper {
|
|
|
554
582
|
}
|
|
555
583
|
|
|
556
584
|
async _startBrowser() {
|
|
557
|
-
if (this.
|
|
585
|
+
if (this.isElectron) {
|
|
586
|
+
this.browser = await playwright._electron.launch(this.playwrightOptions);
|
|
587
|
+
} else if (this.isRemoteBrowser) {
|
|
558
588
|
try {
|
|
559
|
-
this.browser = await playwright[this.options.browser].connect(this.playwrightOptions);
|
|
589
|
+
this.browser = await playwright[this.options.browser].connect(this.playwrightOptions.browserWSEndpoint);
|
|
560
590
|
} catch (err) {
|
|
561
591
|
if (err.toString().indexOf('ECONNREFUSED')) {
|
|
562
592
|
throw new RemoteBrowserConnectionRefused(err);
|
|
563
593
|
}
|
|
564
594
|
throw err;
|
|
565
595
|
}
|
|
596
|
+
} else if (this.userDataDir) {
|
|
597
|
+
this.browser = await playwright[this.options.browser].launchPersistentContext(this.userDataDir, this.playwrightOptions);
|
|
566
598
|
} else {
|
|
567
599
|
this.browser = await playwright[this.options.browser].launch(this.playwrightOptions);
|
|
568
600
|
}
|
|
@@ -571,11 +603,22 @@ class Playwright extends Helper {
|
|
|
571
603
|
this.browser.on('targetchanged', (target) => {
|
|
572
604
|
this.debugSection('Url', target.url());
|
|
573
605
|
});
|
|
574
|
-
this.browserContext = await this.browser.newContext({ ignoreHTTPSErrors: this.options.ignoreHTTPSErrors, acceptDownloads: true, ...this.options.emulate });// Adding the HTTPSError ignore in the context so that we can ignore those errors
|
|
575
606
|
|
|
576
|
-
|
|
607
|
+
if (this.isElectron) {
|
|
608
|
+
this.browserContext = this.browser.context();
|
|
609
|
+
} else if (this.userDataDir) {
|
|
610
|
+
this.browserContext = this.browser;
|
|
611
|
+
} else {
|
|
612
|
+
this.browserContext = await this.browser.newContext({ ignoreHTTPSErrors: this.options.ignoreHTTPSErrors, acceptDownloads: true, ...this.options.emulate });// Adding the HTTPSError ignore in the context so that we can ignore those errors
|
|
613
|
+
}
|
|
577
614
|
|
|
578
|
-
|
|
615
|
+
let mainPage;
|
|
616
|
+
if (this.isElectron) {
|
|
617
|
+
mainPage = await this.browser.firstWindow();
|
|
618
|
+
} else {
|
|
619
|
+
const existingPages = await this.browserContext.pages();
|
|
620
|
+
mainPage = existingPages[0] || await this.browserContext.newPage();
|
|
621
|
+
}
|
|
579
622
|
targetCreatedHandler.call(this, mainPage);
|
|
580
623
|
|
|
581
624
|
await this._setPage(mainPage);
|
|
@@ -584,6 +627,10 @@ class Playwright extends Helper {
|
|
|
584
627
|
this.isRunning = true;
|
|
585
628
|
}
|
|
586
629
|
|
|
630
|
+
_getType() {
|
|
631
|
+
return this.browser._type;
|
|
632
|
+
}
|
|
633
|
+
|
|
587
634
|
async _stopBrowser() {
|
|
588
635
|
this.withinLocator = null;
|
|
589
636
|
this._setPage(null);
|
|
@@ -618,6 +665,7 @@ class Playwright extends Helper {
|
|
|
618
665
|
const els = await this._locate(locator);
|
|
619
666
|
assertElementExists(els, locator);
|
|
620
667
|
this.context = els[0];
|
|
668
|
+
this.contextLocator = locator;
|
|
621
669
|
|
|
622
670
|
this.withinLocator = new Locator(locator);
|
|
623
671
|
}
|
|
@@ -625,6 +673,7 @@ class Playwright extends Helper {
|
|
|
625
673
|
async _withinEnd() {
|
|
626
674
|
this.withinLocator = null;
|
|
627
675
|
this.context = await this.page;
|
|
676
|
+
this.contextLocator = null;
|
|
628
677
|
}
|
|
629
678
|
|
|
630
679
|
_extractDataFromPerformanceTiming(timing, ...dataNames) {
|
|
@@ -651,6 +700,9 @@ class Playwright extends Helper {
|
|
|
651
700
|
* @param {string} url url path or global url.
|
|
652
701
|
*/
|
|
653
702
|
async amOnPage(url) {
|
|
703
|
+
if (this.isElectron) {
|
|
704
|
+
throw new Error('Cannot open pages inside an Electron container');
|
|
705
|
+
}
|
|
654
706
|
if (!(/^\w+\:\/\//.test(url))) {
|
|
655
707
|
url = this.options.url + url;
|
|
656
708
|
}
|
|
@@ -984,6 +1036,9 @@ class Playwright extends Helper {
|
|
|
984
1036
|
* @param {number} [num=1]
|
|
985
1037
|
*/
|
|
986
1038
|
async switchToNextTab(num = 1) {
|
|
1039
|
+
if (this.isElectron) {
|
|
1040
|
+
throw new Error('Cannot switch tabs inside an Electron container');
|
|
1041
|
+
}
|
|
987
1042
|
const pages = await this.browserContext.pages();
|
|
988
1043
|
|
|
989
1044
|
const index = pages.indexOf(this.page);
|
|
@@ -1007,6 +1062,9 @@ class Playwright extends Helper {
|
|
|
1007
1062
|
* @param {number} [num=1]
|
|
1008
1063
|
*/
|
|
1009
1064
|
async switchToPreviousTab(num = 1) {
|
|
1065
|
+
if (this.isElectron) {
|
|
1066
|
+
throw new Error('Cannot switch tabs inside an Electron container');
|
|
1067
|
+
}
|
|
1010
1068
|
const pages = await this.browserContext.pages();
|
|
1011
1069
|
const index = pages.indexOf(this.page);
|
|
1012
1070
|
this.withinLocator = null;
|
|
@@ -1028,6 +1086,9 @@ class Playwright extends Helper {
|
|
|
1028
1086
|
* ```
|
|
1029
1087
|
*/
|
|
1030
1088
|
async closeCurrentTab() {
|
|
1089
|
+
if (this.isElectron) {
|
|
1090
|
+
throw new Error('Cannot close current tab inside an Electron container');
|
|
1091
|
+
}
|
|
1031
1092
|
const oldPage = this.page;
|
|
1032
1093
|
await this.switchToPreviousTab();
|
|
1033
1094
|
await oldPage.close();
|
|
@@ -1066,6 +1127,9 @@ class Playwright extends Helper {
|
|
|
1066
1127
|
* ```
|
|
1067
1128
|
*/
|
|
1068
1129
|
async openNewTab(options) {
|
|
1130
|
+
if (this.isElectron) {
|
|
1131
|
+
throw new Error('Cannot open new tabs inside an Electron container');
|
|
1132
|
+
}
|
|
1069
1133
|
await this._setPage(await this.browserContext.newPage(options));
|
|
1070
1134
|
return this._waitForAction();
|
|
1071
1135
|
}
|
|
@@ -2079,6 +2143,22 @@ class Playwright extends Helper {
|
|
|
2079
2143
|
return context.evaluate.apply(context, [fn, arg]);
|
|
2080
2144
|
}
|
|
2081
2145
|
|
|
2146
|
+
/**
|
|
2147
|
+
* Grab Locator if called within Context
|
|
2148
|
+
*
|
|
2149
|
+
* @param {*} locator
|
|
2150
|
+
*/
|
|
2151
|
+
_contextLocator(locator) {
|
|
2152
|
+
locator = buildLocatorString(new Locator(locator, 'css'));
|
|
2153
|
+
|
|
2154
|
+
if (this.contextLocator) {
|
|
2155
|
+
const contextLocator = buildLocatorString(new Locator(this.contextLocator, 'css'));
|
|
2156
|
+
locator = `${contextLocator} >> ${locator}`;
|
|
2157
|
+
}
|
|
2158
|
+
|
|
2159
|
+
return locator;
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2082
2162
|
/**
|
|
2083
2163
|
* Retrieves a text from an element located by CSS or XPath and returns it to test.
|
|
2084
2164
|
* Resumes test execution, so **should be used inside async with `await`** operator.
|
|
@@ -2094,10 +2174,11 @@ class Playwright extends Helper {
|
|
|
2094
2174
|
*
|
|
2095
2175
|
*/
|
|
2096
2176
|
async grabTextFrom(locator) {
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2177
|
+
locator = this._contextLocator(locator);
|
|
2178
|
+
const text = await this.page.textContent(locator);
|
|
2179
|
+
assertElementExists(text, locator);
|
|
2180
|
+
this.debugSection('Text', text);
|
|
2181
|
+
return text;
|
|
2101
2182
|
}
|
|
2102
2183
|
|
|
2103
2184
|
/**
|
|
@@ -2850,6 +2931,7 @@ class Playwright extends Helper {
|
|
|
2850
2931
|
|
|
2851
2932
|
if (locator >= 0 && locator < childFrames.length) {
|
|
2852
2933
|
this.context = childFrames[locator];
|
|
2934
|
+
this.contextLocator = locator;
|
|
2853
2935
|
} else {
|
|
2854
2936
|
throw new Error('Element #invalidIframeSelector was not found by text|CSS|XPath');
|
|
2855
2937
|
}
|
|
@@ -2857,6 +2939,7 @@ class Playwright extends Helper {
|
|
|
2857
2939
|
}
|
|
2858
2940
|
if (!locator) {
|
|
2859
2941
|
this.context = this.page;
|
|
2942
|
+
this.contextLocator = null;
|
|
2860
2943
|
return;
|
|
2861
2944
|
}
|
|
2862
2945
|
|
|
@@ -2867,8 +2950,10 @@ class Playwright extends Helper {
|
|
|
2867
2950
|
|
|
2868
2951
|
if (contentFrame) {
|
|
2869
2952
|
this.context = contentFrame;
|
|
2953
|
+
this.contextLocator = null;
|
|
2870
2954
|
} else {
|
|
2871
2955
|
this.context = els[0];
|
|
2956
|
+
this.contextLocator = locator;
|
|
2872
2957
|
}
|
|
2873
2958
|
}
|
|
2874
2959
|
|
|
@@ -3057,6 +3142,19 @@ async function findElements(matcher, locator) {
|
|
|
3057
3142
|
return matcher.$$(buildLocatorString(locator));
|
|
3058
3143
|
}
|
|
3059
3144
|
|
|
3145
|
+
async function getVisibleElements(elements) {
|
|
3146
|
+
const visibleElements = [];
|
|
3147
|
+
for (const element of elements) {
|
|
3148
|
+
if (await element.isVisible()) {
|
|
3149
|
+
visibleElements.push(element);
|
|
3150
|
+
}
|
|
3151
|
+
}
|
|
3152
|
+
if (visibleElements.length === 0) {
|
|
3153
|
+
return elements;
|
|
3154
|
+
}
|
|
3155
|
+
return visibleElements;
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3060
3158
|
async function proceedClick(locator, context = null, options = {}) {
|
|
3061
3159
|
let matcher = await this._getContext();
|
|
3062
3160
|
if (context) {
|
|
@@ -3076,7 +3174,8 @@ async function proceedClick(locator, context = null, options = {}) {
|
|
|
3076
3174
|
if (options.force) {
|
|
3077
3175
|
await els[0].dispatchEvent('click');
|
|
3078
3176
|
} else {
|
|
3079
|
-
await els[0]
|
|
3177
|
+
const element = els.length > 1 ? (await getVisibleElements(els))[0] : els[0];
|
|
3178
|
+
await element.click(options);
|
|
3080
3179
|
}
|
|
3081
3180
|
const promises = [];
|
|
3082
3181
|
if (options.waitForNavigation) {
|
|
@@ -3334,11 +3433,13 @@ async function targetCreatedHandler(page) {
|
|
|
3334
3433
|
// we are inside iframe?
|
|
3335
3434
|
const frameEl = await this.context.frameElement();
|
|
3336
3435
|
this.context = await frameEl.contentFrame();
|
|
3436
|
+
this.contextLocator = null;
|
|
3337
3437
|
return;
|
|
3338
3438
|
}
|
|
3339
3439
|
// if context element was in iframe - keep it
|
|
3340
3440
|
// if (await this.context.ownerFrame()) return;
|
|
3341
3441
|
this.context = page;
|
|
3442
|
+
this.contextLocator = null;
|
|
3342
3443
|
});
|
|
3343
3444
|
});
|
|
3344
3445
|
page.on('console', (msg) => {
|
|
@@ -3349,7 +3450,7 @@ async function targetCreatedHandler(page) {
|
|
|
3349
3450
|
if (this.options.userAgent) {
|
|
3350
3451
|
await page.setUserAgent(this.options.userAgent);
|
|
3351
3452
|
}
|
|
3352
|
-
if (this.options.windowSize && this.options.windowSize.indexOf('x') > 0) {
|
|
3453
|
+
if (this.options.windowSize && this.options.windowSize.indexOf('x') > 0 && this._getType() === 'Browser') {
|
|
3353
3454
|
const dimensions = this.options.windowSize.split('x');
|
|
3354
3455
|
const width = parseInt(dimensions[0], 10);
|
|
3355
3456
|
const height = parseInt(dimensions[1], 10);
|
package/docs/build/REST.js
CHANGED
|
@@ -59,7 +59,8 @@ class REST extends Helper {
|
|
|
59
59
|
|
|
60
60
|
this.options = { ...this.options, ...config };
|
|
61
61
|
this.headers = { ...this.options.defaultHeaders };
|
|
62
|
-
axios
|
|
62
|
+
this.axios = axios.create();
|
|
63
|
+
this.axios.defaults.headers = this.options.defaultHeaders;
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
static _checkRequirements() {
|
|
@@ -77,7 +78,7 @@ class REST extends Helper {
|
|
|
77
78
|
*/
|
|
78
79
|
async _executeRequest(request) {
|
|
79
80
|
const _debugRequest = { ...request };
|
|
80
|
-
axios.defaults.timeout = request.timeout || this.options.timeout;
|
|
81
|
+
this.axios.defaults.timeout = request.timeout || this.options.timeout;
|
|
81
82
|
|
|
82
83
|
if (this.headers && this.headers.auth) {
|
|
83
84
|
request.auth = this.headers.auth;
|
|
@@ -102,7 +103,7 @@ class REST extends Helper {
|
|
|
102
103
|
|
|
103
104
|
let response;
|
|
104
105
|
try {
|
|
105
|
-
response = await axios(request);
|
|
106
|
+
response = await this.axios(request);
|
|
106
107
|
} catch (err) {
|
|
107
108
|
if (!err.response) throw err;
|
|
108
109
|
this.debugSection('Response', `Response error. Status code: ${err.response.status}`);
|