codeceptjs 3.2.0 → 3.3.0-beta.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 +78 -2
- package/docs/advanced.md +3 -3
- package/docs/api.md +227 -188
- package/docs/basics.md +26 -1
- package/docs/bdd.md +2 -2
- package/docs/build/ApiDataFactory.js +13 -6
- package/docs/build/Appium.js +98 -36
- package/docs/build/FileSystem.js +11 -1
- package/docs/build/GraphQL.js +11 -0
- package/docs/build/JSONResponse.js +297 -0
- package/docs/build/Nightmare.js +48 -48
- package/docs/build/Playwright.js +277 -151
- package/docs/build/Puppeteer.js +77 -68
- package/docs/build/REST.js +36 -0
- package/docs/build/TestCafe.js +44 -44
- package/docs/build/WebDriver.js +70 -70
- package/docs/changelog.md +28 -2
- package/docs/configuration.md +8 -8
- package/docs/custom-helpers.md +1 -1
- package/docs/data.md +9 -9
- package/docs/helpers/ApiDataFactory.md +7 -0
- package/docs/helpers/Appium.md +240 -198
- package/docs/helpers/FileSystem.md +11 -1
- package/docs/helpers/JSONResponse.md +230 -0
- package/docs/helpers/Playwright.md +283 -216
- package/docs/helpers/Puppeteer.md +9 -1
- package/docs/helpers/REST.md +30 -9
- package/docs/installation.md +3 -1
- package/docs/internal-api.md +265 -0
- package/docs/mobile.md +11 -11
- package/docs/nightmare.md +3 -3
- package/docs/pageobjects.md +2 -0
- package/docs/playwright.md +73 -18
- package/docs/plugins.md +140 -40
- package/docs/puppeteer.md +28 -12
- package/docs/quickstart.md +2 -3
- package/docs/reports.md +44 -3
- package/docs/testcafe.md +1 -1
- package/docs/translation.md +2 -2
- package/docs/videos.md +2 -2
- package/docs/visual.md +2 -2
- package/docs/vue.md +1 -1
- package/docs/webdriver.md +92 -4
- package/lib/actor.js +2 -2
- package/lib/cli.js +25 -20
- package/lib/command/init.js +5 -15
- package/lib/command/workers/runTests.js +25 -7
- package/lib/config.js +17 -13
- package/lib/helper/ApiDataFactory.js +13 -6
- package/lib/helper/Appium.js +65 -3
- package/lib/helper/FileSystem.js +11 -1
- package/lib/helper/GraphQL.js +11 -0
- package/lib/helper/JSONResponse.js +297 -0
- package/lib/helper/Playwright.js +215 -89
- package/lib/helper/Puppeteer.js +13 -4
- package/lib/helper/REST.js +36 -0
- package/lib/helper/WebDriver.js +1 -1
- package/lib/helper/extras/Console.js +8 -0
- package/lib/helper/extras/PlaywrightRestartOpts.js +35 -0
- package/lib/interfaces/bdd.js +3 -1
- package/lib/listener/timeout.js +4 -3
- package/lib/plugin/allure.js +12 -0
- package/lib/plugin/autoLogin.js +1 -1
- package/lib/plugin/eachElement.js +127 -0
- package/lib/plugin/retryFailedStep.js +4 -3
- package/lib/plugin/stepTimeout.js +5 -4
- package/lib/plugin/tryTo.js +6 -0
- package/lib/recorder.js +2 -1
- package/lib/step.js +57 -2
- package/lib/utils.js +20 -0
- package/package.json +6 -4
- package/translations/pt-BR.js +8 -0
- package/typings/index.d.ts +4 -0
- package/typings/types.d.ts +345 -110
package/docs/build/Playwright.js
CHANGED
|
@@ -14,12 +14,12 @@ const {
|
|
|
14
14
|
ucfirst,
|
|
15
15
|
fileExists,
|
|
16
16
|
chunkArray,
|
|
17
|
-
toCamelCase,
|
|
18
17
|
convertCssPropertiesToCamelCase,
|
|
19
18
|
screenshotOutputFolder,
|
|
20
19
|
getNormalizedKeyAttributeValue,
|
|
21
20
|
isModifierKey,
|
|
22
21
|
clearString,
|
|
22
|
+
requireWithFallback,
|
|
23
23
|
} = require('../utils');
|
|
24
24
|
const {
|
|
25
25
|
isColorProperty,
|
|
@@ -39,6 +39,9 @@ const popupStore = new Popup();
|
|
|
39
39
|
const consoleLogStore = new Console();
|
|
40
40
|
const availableBrowsers = ['chromium', 'webkit', 'firefox', 'electron'];
|
|
41
41
|
|
|
42
|
+
const {
|
|
43
|
+
setRestartStrategy, restartsSession, restartsContext, restartsBrowser,
|
|
44
|
+
} = require('./extras/PlaywrightRestartOpts');
|
|
42
45
|
const { createValueEngine, createDisabledEngine } = require('./extras/PlaywrightPropEngine');
|
|
43
46
|
|
|
44
47
|
/**
|
|
@@ -50,12 +53,18 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
|
|
|
50
53
|
*
|
|
51
54
|
* This helper works with a browser out of the box with no additional tools required to install.
|
|
52
55
|
*
|
|
53
|
-
* Requires `playwright` package version ^1 to be installed:
|
|
56
|
+
* Requires `playwright` or `playwright-core` package version ^1 to be installed:
|
|
54
57
|
*
|
|
55
58
|
* ```
|
|
56
|
-
* npm i playwright@^1 --save
|
|
59
|
+
* npm i playwright@^1.18 --save
|
|
60
|
+
* ```
|
|
61
|
+
* or
|
|
62
|
+
* ```
|
|
63
|
+
* npm i playwright-core@^1.18 --save
|
|
57
64
|
* ```
|
|
58
65
|
*
|
|
66
|
+
* Using playwright-core package, will prevent the download of browser binaries and allow connecting to an existing browser installation or for connecting to a remote one.
|
|
67
|
+
*
|
|
59
68
|
* ## Configuration
|
|
60
69
|
*
|
|
61
70
|
* This helper should be configured in codecept.json or codecept.conf.js
|
|
@@ -63,17 +72,21 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
|
|
|
63
72
|
* * `url`: base url of website to be tested
|
|
64
73
|
* * `browser`: a browser to test on, either: `chromium`, `firefox`, `webkit`, `electron`. Default: chromium.
|
|
65
74
|
* * `show`: (optional, default: false) - show browser window.
|
|
66
|
-
* * `restart`: (optional, default:
|
|
75
|
+
* * `restart`: (optional, default: false) - restart strategy between tests. Possible values:
|
|
76
|
+
* * 'context' or **false** - restarts [browser context](https://playwright.dev/docs/api/class-browsercontext) but keeps running browser. Recommended by Playwright team to keep tests isolated.
|
|
77
|
+
* * 'browser' or **true** - closes browser and opens it again between tests.
|
|
78
|
+
* * 'session' or 'keep' - keeps browser context and session, but cleans up cookies and localStorage between tests. The fastest option when running tests in windowed mode. Works with `keepCookies` and `keepBrowserState` options. This behavior was default before CodeceptJS 3.1
|
|
79
|
+
* * `timeout`: (optional, default: 1000) - [timeout](https://playwright.dev/docs/api/class-page#page-set-default-timeout) in ms of all Playwright actions .
|
|
67
80
|
* * `disableScreenshots`: (optional, default: false) - don't save screenshot on failure.
|
|
68
81
|
* * `emulate`: (optional, default: {}) launch browser in device emulation mode.
|
|
69
82
|
* * `video`: (optional, default: false) enables video recording for failed tests; videos are saved into `output/videos` folder
|
|
70
83
|
* * `trace`: (optional, default: false) record [tracing information](https://playwright.dev/docs/trace-viewer) with screenshots and snapshots.
|
|
71
84
|
* * `fullPageScreenshots` (optional, default: false) - make full page screenshots on failure.
|
|
72
85
|
* * `uniqueScreenshotNames`: (optional, default: false) - option to prevent screenshot override if you have scenarios with the same name in different suites.
|
|
73
|
-
* * `keepBrowserState`: (optional, default: false) - keep browser state between tests when `restart` is set to
|
|
74
|
-
* * `keepCookies`: (optional, default: false) - keep cookies between tests when `restart` is set to
|
|
86
|
+
* * `keepBrowserState`: (optional, default: false) - keep browser state between tests when `restart` is set to 'session'.
|
|
87
|
+
* * `keepCookies`: (optional, default: false) - keep cookies between tests when `restart` is set to 'session'.
|
|
75
88
|
* * `waitForAction`: (optional) how long to wait after click, doubleClick or PressKey actions in ms. Default: 100.
|
|
76
|
-
* * `waitForNavigation`: (optional, default: 'load'). When to consider navigation succeeded. Possible options: `load`, `domcontentloaded`, `networkidle`. Choose one of those options is possible. See [Playwright API](https://github.com/microsoft/playwright/blob/
|
|
89
|
+
* * `waitForNavigation`: (optional, default: 'load'). When to consider navigation succeeded. Possible options: `load`, `domcontentloaded`, `networkidle`. Choose one of those options is possible. See [Playwright API](https://github.com/microsoft/playwright/blob/main/docs/api.md#pagewaitfornavigationoptions).
|
|
77
90
|
* * `pressKeyDelay`: (optional, default: '10'). Delay between key presses in ms. Used when calling Playwrights page.type(...) in fillField/appendField
|
|
78
91
|
* * `getPageTimeout` (optional, default: '0') config option to set maximum navigation time in milliseconds.
|
|
79
92
|
* * `waitForTimeout`: (optional) default wait* timeout in ms. Default: 1000.
|
|
@@ -84,6 +97,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
|
|
|
84
97
|
* * `manualStart`: (optional, default: false) - do not start browser before a test, start it manually inside a helper with `this.helpers["Playwright"]._startBrowser()`.
|
|
85
98
|
* * `chromium`: (optional) pass additional chromium options
|
|
86
99
|
* * `electron`: (optional) pass additional electron options
|
|
100
|
+
* * `channel`: (optional) While Playwright can operate against the stock Google Chrome and Microsoft Edge browsers available on the machine. In particular, current Playwright version will support Stable and Beta channels of these browsers. See [Google Chrome & Microsoft Edge](https://playwright.dev/docs/browsers/#google-chrome--microsoft-edge).
|
|
87
101
|
*
|
|
88
102
|
* #### Video Recording Customization
|
|
89
103
|
*
|
|
@@ -235,7 +249,7 @@ class Playwright extends Helper {
|
|
|
235
249
|
constructor(config) {
|
|
236
250
|
super(config);
|
|
237
251
|
|
|
238
|
-
playwright =
|
|
252
|
+
playwright = requireWithFallback('playwright', 'playwright-core');
|
|
239
253
|
|
|
240
254
|
// set defaults
|
|
241
255
|
this.isRemoteBrowser = false;
|
|
@@ -259,8 +273,10 @@ class Playwright extends Helper {
|
|
|
259
273
|
waitForAction: 100,
|
|
260
274
|
waitForTimeout: 1000,
|
|
261
275
|
pressKeyDelay: 10,
|
|
276
|
+
timeout: 1000,
|
|
262
277
|
fullPageScreenshots: false,
|
|
263
278
|
disableScreenshots: false,
|
|
279
|
+
ignoreLog: ['warning', 'log'],
|
|
264
280
|
uniqueScreenshotNames: false,
|
|
265
281
|
manualStart: false,
|
|
266
282
|
getPageTimeout: 0,
|
|
@@ -270,6 +286,7 @@ class Playwright extends Helper {
|
|
|
270
286
|
keepBrowserState: false,
|
|
271
287
|
show: false,
|
|
272
288
|
defaultPopupAction: 'accept',
|
|
289
|
+
use: { actionTimeout: 0 },
|
|
273
290
|
ignoreHTTPSErrors: false, // Adding it here o that context can be set up to ignore the SSL errors
|
|
274
291
|
};
|
|
275
292
|
|
|
@@ -297,10 +314,16 @@ class Playwright extends Helper {
|
|
|
297
314
|
|
|
298
315
|
_setConfig(config) {
|
|
299
316
|
this.options = this._validateConfig(config);
|
|
317
|
+
setRestartStrategy(this.options);
|
|
300
318
|
this.playwrightOptions = {
|
|
301
319
|
headless: !this.options.show,
|
|
302
320
|
...this._getOptionsForBrowser(config),
|
|
303
321
|
};
|
|
322
|
+
|
|
323
|
+
if (this.options.channel && this.options.browser === 'chromium') {
|
|
324
|
+
this.playwrightOptions.channel = this.options.channel;
|
|
325
|
+
}
|
|
326
|
+
|
|
304
327
|
if (this.options.video) {
|
|
305
328
|
this.options.recordVideo = { size: parseWindowSize(this.options.windowSize) };
|
|
306
329
|
}
|
|
@@ -329,9 +352,9 @@ class Playwright extends Helper {
|
|
|
329
352
|
|
|
330
353
|
static _checkRequirements() {
|
|
331
354
|
try {
|
|
332
|
-
|
|
355
|
+
requireWithFallback('playwright', 'playwright-core');
|
|
333
356
|
} catch (e) {
|
|
334
|
-
return ['playwright@^1'];
|
|
357
|
+
return ['playwright@^1.18'];
|
|
335
358
|
}
|
|
336
359
|
}
|
|
337
360
|
|
|
@@ -348,7 +371,7 @@ class Playwright extends Helper {
|
|
|
348
371
|
}
|
|
349
372
|
|
|
350
373
|
_beforeSuite() {
|
|
351
|
-
if (
|
|
374
|
+
if ((restartsSession() || restartsContext()) && !this.options.manualStart && !this.isRunning) {
|
|
352
375
|
this.debugSection('Session', 'Starting singleton browser session');
|
|
353
376
|
return this._startBrowser();
|
|
354
377
|
}
|
|
@@ -365,7 +388,8 @@ class Playwright extends Helper {
|
|
|
365
388
|
return err.message.includes('context');
|
|
366
389
|
},
|
|
367
390
|
});
|
|
368
|
-
|
|
391
|
+
|
|
392
|
+
if (restartsBrowser() && !this.options.manualStart) await this._startBrowser();
|
|
369
393
|
if (!this.isRunning && !this.options.manualStart) await this._startBrowser();
|
|
370
394
|
|
|
371
395
|
this.isAuthenticated = false;
|
|
@@ -387,7 +411,9 @@ class Playwright extends Helper {
|
|
|
387
411
|
if (this.storageState) contextOptions.storageState = this.storageState;
|
|
388
412
|
if (this.options.userAgent) contextOptions.userAgent = this.options.userAgent;
|
|
389
413
|
if (this.options.locale) contextOptions.locale = this.options.locale;
|
|
390
|
-
this.browserContext
|
|
414
|
+
if (!this.browserContext || !restartsSession()) {
|
|
415
|
+
this.browserContext = await this.browser.newContext(contextOptions); // Adding the HTTPSError ignore in the context so that we can ignore those errors
|
|
416
|
+
}
|
|
391
417
|
}
|
|
392
418
|
|
|
393
419
|
let mainPage;
|
|
@@ -415,7 +441,11 @@ class Playwright extends Helper {
|
|
|
415
441
|
return;
|
|
416
442
|
}
|
|
417
443
|
|
|
418
|
-
if (
|
|
444
|
+
if (restartsSession()) {
|
|
445
|
+
return refreshContextSession.bind(this)();
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (restartsBrowser()) {
|
|
419
449
|
this.isRunning = false;
|
|
420
450
|
return this._stopBrowser();
|
|
421
451
|
}
|
|
@@ -437,11 +467,10 @@ class Playwright extends Helper {
|
|
|
437
467
|
return this.browser;
|
|
438
468
|
}
|
|
439
469
|
|
|
440
|
-
_afterSuite() {
|
|
441
|
-
}
|
|
470
|
+
_afterSuite() {}
|
|
442
471
|
|
|
443
|
-
_finishTest() {
|
|
444
|
-
if (
|
|
472
|
+
async _finishTest() {
|
|
473
|
+
if ((restartsSession() || restartsContext()) && this.isRunning) return this._stopBrowser();
|
|
445
474
|
}
|
|
446
475
|
|
|
447
476
|
_session() {
|
|
@@ -500,16 +529,16 @@ class Playwright extends Helper {
|
|
|
500
529
|
* First argument is a description of an action.
|
|
501
530
|
* Second argument is async function that gets this helper as parameter.
|
|
502
531
|
*
|
|
503
|
-
* { [`page`](https://github.com/microsoft/playwright/blob/
|
|
532
|
+
* { [`page`](https://github.com/microsoft/playwright/blob/main/docs/src/api/class-page.md), [`browserContext`](https://github.com/microsoft/playwright/blob/main/docs/src/api/class-browsercontext.md) [`browser`](https://github.com/microsoft/playwright/blob/main/docs/src/api/class-browser.md) } objects from Playwright API are available.
|
|
504
533
|
*
|
|
505
534
|
* ```js
|
|
506
|
-
* I.usePlaywrightTo('emulate offline mode', async ({
|
|
507
|
-
* await
|
|
535
|
+
* I.usePlaywrightTo('emulate offline mode', async ({ browserContext }) => {
|
|
536
|
+
* await browserContext.setOffline(true);
|
|
508
537
|
* });
|
|
509
538
|
* ```
|
|
510
539
|
*
|
|
511
540
|
* @param {string} description used to show in logs.
|
|
512
|
-
* @param {function} fn async
|
|
541
|
+
* @param {function} fn async function that executed with Playwright helper as argument
|
|
513
542
|
*/
|
|
514
543
|
usePlaywrightTo(description, fn) {
|
|
515
544
|
return this._useTo(...arguments);
|
|
@@ -584,7 +613,14 @@ class Playwright extends Helper {
|
|
|
584
613
|
this._addPopupListener(page);
|
|
585
614
|
this.page = page;
|
|
586
615
|
if (!page) return;
|
|
616
|
+
this.browserContext.setDefaultTimeout(0);
|
|
587
617
|
page.setDefaultNavigationTimeout(this.options.getPageTimeout);
|
|
618
|
+
page.setDefaultTimeout(this.options.timeout);
|
|
619
|
+
|
|
620
|
+
page.on('crash', async () => {
|
|
621
|
+
console.log('ERROR: Page has crashed, closing page!');
|
|
622
|
+
await page.close();
|
|
623
|
+
});
|
|
588
624
|
this.context = await this.page;
|
|
589
625
|
this.contextLocator = null;
|
|
590
626
|
if (this.options.browser === 'chrome') {
|
|
@@ -680,7 +716,6 @@ class Playwright extends Helper {
|
|
|
680
716
|
this._setPage(null);
|
|
681
717
|
this.context = null;
|
|
682
718
|
popupStore.clear();
|
|
683
|
-
|
|
684
719
|
await this.browser.close();
|
|
685
720
|
}
|
|
686
721
|
|
|
@@ -828,7 +863,7 @@ class Playwright extends Helper {
|
|
|
828
863
|
* I.moveCursorTo('#submit', 5,5);
|
|
829
864
|
* ```
|
|
830
865
|
*
|
|
831
|
-
* @param {
|
|
866
|
+
* @param {string | object} locator located by CSS|XPath|strict locator.
|
|
832
867
|
* @param {number} [offsetX=0] (optional, `0` by default) X-axis offset.
|
|
833
868
|
* @param {number} [offsetY=0] (optional, `0` by default) Y-axis offset.
|
|
834
869
|
*
|
|
@@ -851,12 +886,24 @@ class Playwright extends Helper {
|
|
|
851
886
|
* I.dragAndDrop('#dragHandle', '#container');
|
|
852
887
|
* ```
|
|
853
888
|
*
|
|
854
|
-
* @param {
|
|
855
|
-
* @param {
|
|
889
|
+
* @param {string | object} srcElement located by CSS|XPath|strict locator.
|
|
890
|
+
* @param {string | object} destElement located by CSS|XPath|strict locator.
|
|
856
891
|
*
|
|
892
|
+
*
|
|
893
|
+
* [Additional options](https://playwright.dev/docs/api/class-page#page-drag-and-drop) can be passed as 3rd argument.
|
|
894
|
+
*
|
|
895
|
+
* ```js
|
|
896
|
+
* // specify coordinates for source position
|
|
897
|
+
* I.dragAndDrop('img.src', 'img.dst', { sourcePosition: {x: 10, y: 10} })
|
|
898
|
+
* ```
|
|
899
|
+
*
|
|
900
|
+
* > By default option `force: true` is set
|
|
857
901
|
*/
|
|
858
|
-
async dragAndDrop(srcElement, destElement) {
|
|
859
|
-
|
|
902
|
+
async dragAndDrop(srcElement, destElement, options = { force: true }) {
|
|
903
|
+
const src = new Locator(srcElement, 'css');
|
|
904
|
+
const dst = new Locator(destElement, 'css');
|
|
905
|
+
|
|
906
|
+
return this.page.dragAndDrop(buildLocatorString(src), buildLocatorString(dst), options);
|
|
860
907
|
}
|
|
861
908
|
|
|
862
909
|
/**
|
|
@@ -913,7 +960,7 @@ class Playwright extends Helper {
|
|
|
913
960
|
* I.scrollTo('#submit', 5, 5);
|
|
914
961
|
* ```
|
|
915
962
|
*
|
|
916
|
-
* @param {
|
|
963
|
+
* @param {string | object} locator located by CSS|XPath|strict locator.
|
|
917
964
|
* @param {number} [offsetX=0] (optional, `0` by default) X-axis offset.
|
|
918
965
|
* @param {number} [offsetY=0] (optional, `0` by default) Y-axis offset.
|
|
919
966
|
*/
|
|
@@ -1163,7 +1210,7 @@ class Playwright extends Helper {
|
|
|
1163
1210
|
* I.openNewTab();
|
|
1164
1211
|
* ```
|
|
1165
1212
|
*
|
|
1166
|
-
* You can pass in [page options](https://github.com/microsoft/playwright/blob/
|
|
1213
|
+
* You can pass in [page options](https://github.com/microsoft/playwright/blob/main/docs/api.md#browsernewpageoptions) to emulate device on this page
|
|
1167
1214
|
*
|
|
1168
1215
|
* ```js
|
|
1169
1216
|
* // enable mobile
|
|
@@ -1201,7 +1248,7 @@ class Playwright extends Helper {
|
|
|
1201
1248
|
* ```js
|
|
1202
1249
|
* I.seeElement('#modal');
|
|
1203
1250
|
* ```
|
|
1204
|
-
* @param {
|
|
1251
|
+
* @param {string | object} locator located by CSS|XPath|strict locator.
|
|
1205
1252
|
*
|
|
1206
1253
|
*/
|
|
1207
1254
|
async seeElement(locator) {
|
|
@@ -1217,7 +1264,7 @@ class Playwright extends Helper {
|
|
|
1217
1264
|
* I.dontSeeElement('.modal'); // modal is not shown
|
|
1218
1265
|
* ```
|
|
1219
1266
|
*
|
|
1220
|
-
* @param {
|
|
1267
|
+
* @param {string | object} locator located by CSS|XPath|Strict locator.
|
|
1221
1268
|
*
|
|
1222
1269
|
*/
|
|
1223
1270
|
async dontSeeElement(locator) {
|
|
@@ -1233,7 +1280,7 @@ class Playwright extends Helper {
|
|
|
1233
1280
|
* ```js
|
|
1234
1281
|
* I.seeElementInDOM('#modal');
|
|
1235
1282
|
* ```
|
|
1236
|
-
* @param {
|
|
1283
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
1237
1284
|
*
|
|
1238
1285
|
*/
|
|
1239
1286
|
async seeElementInDOM(locator) {
|
|
@@ -1248,7 +1295,7 @@ class Playwright extends Helper {
|
|
|
1248
1295
|
* I.dontSeeElementInDOM('.nav'); // checks that element is not on page visible or not
|
|
1249
1296
|
* ```
|
|
1250
1297
|
*
|
|
1251
|
-
* @param {
|
|
1298
|
+
* @param {string | object} locator located by CSS|XPath|Strict locator.
|
|
1252
1299
|
*/
|
|
1253
1300
|
async dontSeeElementInDOM(locator) {
|
|
1254
1301
|
const els = await this._locate(locator);
|
|
@@ -1308,14 +1355,25 @@ class Playwright extends Helper {
|
|
|
1308
1355
|
* I.click({css: 'nav a.login'});
|
|
1309
1356
|
* ```
|
|
1310
1357
|
*
|
|
1311
|
-
* @param {
|
|
1312
|
-
* @param {?
|
|
1358
|
+
* @param {string | object} locator clickable link or button located by text, or any element located by CSS|XPath|strict locator.
|
|
1359
|
+
* @param {?string | object} [context=null] (optional, `null` by default) element to search in CSS|XPath|Strict locator.
|
|
1313
1360
|
*
|
|
1314
1361
|
*
|
|
1362
|
+
* [Additional options](https://playwright.dev/docs/api/class-page#page-click) for click available as 3rd argument.
|
|
1363
|
+
*
|
|
1364
|
+
* Examples:
|
|
1365
|
+
*
|
|
1366
|
+
* ```js
|
|
1367
|
+
* // click on element at position
|
|
1368
|
+
* I.click('canvas', '.model', { position: { x: 20, y: 40 } })
|
|
1369
|
+
*
|
|
1370
|
+
* // make ctrl-click
|
|
1371
|
+
* I.click('.edit', null, { modifiers: ['Ctrl'] } )
|
|
1372
|
+
* ```
|
|
1315
1373
|
*
|
|
1316
1374
|
*/
|
|
1317
|
-
async click(locator, context = null) {
|
|
1318
|
-
return proceedClick.call(this, locator, context);
|
|
1375
|
+
async click(locator, context = null, opts = {}) {
|
|
1376
|
+
return proceedClick.call(this, locator, context, opts);
|
|
1319
1377
|
}
|
|
1320
1378
|
|
|
1321
1379
|
/**
|
|
@@ -1353,8 +1411,8 @@ class Playwright extends Helper {
|
|
|
1353
1411
|
* I.forceClick({css: 'nav a.login'});
|
|
1354
1412
|
* ```
|
|
1355
1413
|
*
|
|
1356
|
-
* @param {
|
|
1357
|
-
* @param {?
|
|
1414
|
+
* @param {string | object} locator clickable link or button located by text, or any element located by CSS|XPath|strict locator.
|
|
1415
|
+
* @param {?string | object} [context=null] (optional, `null` by default) element to search in CSS|XPath|Strict locator.
|
|
1358
1416
|
*
|
|
1359
1417
|
*/
|
|
1360
1418
|
async forceClick(locator, context = null) {
|
|
@@ -1372,8 +1430,8 @@ class Playwright extends Helper {
|
|
|
1372
1430
|
* I.doubleClick('.btn.edit');
|
|
1373
1431
|
* ```
|
|
1374
1432
|
*
|
|
1375
|
-
* @param {
|
|
1376
|
-
* @param {?
|
|
1433
|
+
* @param {string | object} locator clickable link or button located by text, or any element located by CSS|XPath|strict locator.
|
|
1434
|
+
* @param {?string | object} [context=null] (optional, `null` by default) element to search in CSS|XPath|Strict locator.
|
|
1377
1435
|
*
|
|
1378
1436
|
*
|
|
1379
1437
|
*
|
|
@@ -1394,8 +1452,8 @@ class Playwright extends Helper {
|
|
|
1394
1452
|
* I.rightClick('Click me', '.context');
|
|
1395
1453
|
* ```
|
|
1396
1454
|
*
|
|
1397
|
-
* @param {
|
|
1398
|
-
* @param {?
|
|
1455
|
+
* @param {string | object} locator clickable element located by CSS|XPath|strict locator.
|
|
1456
|
+
* @param {?string | object} [context=null] (optional, `null` by default) element located by CSS|XPath|strict locator.
|
|
1399
1457
|
*
|
|
1400
1458
|
*
|
|
1401
1459
|
*
|
|
@@ -1415,18 +1473,23 @@ class Playwright extends Helper {
|
|
|
1415
1473
|
* I.checkOption('I Agree to Terms and Conditions');
|
|
1416
1474
|
* I.checkOption('agree', '//form');
|
|
1417
1475
|
* ```
|
|
1418
|
-
* @param {
|
|
1419
|
-
* @param {?
|
|
1476
|
+
* @param {string | object} field checkbox located by label | name | CSS | XPath | strict locator.
|
|
1477
|
+
* @param {?string | object} [context=null] (optional, `null` by default) element located by CSS | XPath | strict locator.
|
|
1478
|
+
*
|
|
1479
|
+
* [Additional options](https://playwright.dev/docs/api/class-elementhandle#element-handle-check) for check available as 3rd argument.
|
|
1480
|
+
*
|
|
1481
|
+
* Examples:
|
|
1482
|
+
*
|
|
1483
|
+
* ```js
|
|
1484
|
+
* // click on element at position
|
|
1485
|
+
* I.checkOption('Agree', '.signup', { position: { x: 5, y: 5 } })
|
|
1486
|
+
* ```
|
|
1487
|
+
* > ⚠️ To avoid flakiness, option `force: true` is set by default
|
|
1420
1488
|
*/
|
|
1421
|
-
async checkOption(field, context = null) {
|
|
1489
|
+
async checkOption(field, context = null, options = { force: true }) {
|
|
1422
1490
|
const elm = await this._locateCheckable(field, context);
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
// Only check if NOT currently checked
|
|
1426
|
-
if (!curentlyChecked) {
|
|
1427
|
-
await elm.click();
|
|
1428
|
-
return this._waitForAction();
|
|
1429
|
-
}
|
|
1491
|
+
await elm.check(options);
|
|
1492
|
+
return this._waitForAction();
|
|
1430
1493
|
}
|
|
1431
1494
|
|
|
1432
1495
|
/**
|
|
@@ -1440,18 +1503,23 @@ class Playwright extends Helper {
|
|
|
1440
1503
|
* I.uncheckOption('I Agree to Terms and Conditions');
|
|
1441
1504
|
* I.uncheckOption('agree', '//form');
|
|
1442
1505
|
* ```
|
|
1443
|
-
* @param {
|
|
1444
|
-
* @param {?
|
|
1506
|
+
* @param {string | object} field checkbox located by label | name | CSS | XPath | strict locator.
|
|
1507
|
+
* @param {?string | object} [context=null] (optional, `null` by default) element located by CSS | XPath | strict locator.
|
|
1508
|
+
*
|
|
1509
|
+
* [Additional options](https://playwright.dev/docs/api/class-elementhandle#element-handle-uncheck) for uncheck available as 3rd argument.
|
|
1510
|
+
*
|
|
1511
|
+
* Examples:
|
|
1512
|
+
*
|
|
1513
|
+
* ```js
|
|
1514
|
+
* // click on element at position
|
|
1515
|
+
* I.uncheckOption('Agree', '.signup', { position: { x: 5, y: 5 } })
|
|
1516
|
+
* ```
|
|
1517
|
+
* > ⚠️ To avoid flakiness, option `force: true` is set by default
|
|
1445
1518
|
*/
|
|
1446
|
-
async uncheckOption(field, context = null) {
|
|
1519
|
+
async uncheckOption(field, context = null, options = { force: true }) {
|
|
1447
1520
|
const elm = await this._locateCheckable(field, context);
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
// Only uncheck if currently checked
|
|
1451
|
-
if (curentlyChecked) {
|
|
1452
|
-
await elm.click();
|
|
1453
|
-
return this._waitForAction();
|
|
1454
|
-
}
|
|
1521
|
+
await elm.uncheck(options);
|
|
1522
|
+
return this._waitForAction();
|
|
1455
1523
|
}
|
|
1456
1524
|
|
|
1457
1525
|
/**
|
|
@@ -1463,7 +1531,7 @@ class Playwright extends Helper {
|
|
|
1463
1531
|
* I.seeCheckboxIsChecked({css: '#signup_form input[type=checkbox]'});
|
|
1464
1532
|
* ```
|
|
1465
1533
|
*
|
|
1466
|
-
* @param {
|
|
1534
|
+
* @param {string | object} field located by label|name|CSS|XPath|strict locator.
|
|
1467
1535
|
*
|
|
1468
1536
|
*/
|
|
1469
1537
|
async seeCheckboxIsChecked(field) {
|
|
@@ -1479,7 +1547,7 @@ class Playwright extends Helper {
|
|
|
1479
1547
|
* I.dontSeeCheckboxIsChecked('agree'); // located by name
|
|
1480
1548
|
* ```
|
|
1481
1549
|
*
|
|
1482
|
-
* @param {
|
|
1550
|
+
* @param {string | object} field located by label|name|CSS|XPath|strict locator.
|
|
1483
1551
|
*
|
|
1484
1552
|
*/
|
|
1485
1553
|
async dontSeeCheckboxIsChecked(field) {
|
|
@@ -1660,8 +1728,8 @@ class Playwright extends Helper {
|
|
|
1660
1728
|
* // or by strict locator
|
|
1661
1729
|
* I.fillField({css: 'form#login input[name=username]'}, 'John');
|
|
1662
1730
|
* ```
|
|
1663
|
-
* @param {
|
|
1664
|
-
* @param {
|
|
1731
|
+
* @param {string | object} field located by label|name|CSS|XPath|strict locator.
|
|
1732
|
+
* @param {string | object} value text value to fill.
|
|
1665
1733
|
*
|
|
1666
1734
|
*
|
|
1667
1735
|
*/
|
|
@@ -1688,7 +1756,7 @@ class Playwright extends Helper {
|
|
|
1688
1756
|
* I.clearField('user[email]');
|
|
1689
1757
|
* I.clearField('#email');
|
|
1690
1758
|
* ```
|
|
1691
|
-
* @param {
|
|
1759
|
+
* @param {string | object} editable field located by label|name|CSS|XPath|strict locator.
|
|
1692
1760
|
*
|
|
1693
1761
|
*/
|
|
1694
1762
|
async clearField(field) {
|
|
@@ -1702,7 +1770,7 @@ class Playwright extends Helper {
|
|
|
1702
1770
|
* ```js
|
|
1703
1771
|
* I.appendField('#myTextField', 'appended');
|
|
1704
1772
|
* ```
|
|
1705
|
-
* @param {
|
|
1773
|
+
* @param {string | object} field located by label|name|CSS|XPath|strict locator
|
|
1706
1774
|
* @param {string} value text value to append.
|
|
1707
1775
|
*
|
|
1708
1776
|
*
|
|
@@ -1725,7 +1793,7 @@ class Playwright extends Helper {
|
|
|
1725
1793
|
* I.seeInField('form input[type=hidden]','hidden_value');
|
|
1726
1794
|
* I.seeInField('#searchform input','Search');
|
|
1727
1795
|
* ```
|
|
1728
|
-
* @param {
|
|
1796
|
+
* @param {string | object} field located by label|name|CSS|XPath|strict locator.
|
|
1729
1797
|
* @param {string} value value to check.
|
|
1730
1798
|
*
|
|
1731
1799
|
*/
|
|
@@ -1742,7 +1810,7 @@ class Playwright extends Helper {
|
|
|
1742
1810
|
* I.dontSeeInField({ css: 'form input.email' }, 'user@user.com'); // field by CSS
|
|
1743
1811
|
* ```
|
|
1744
1812
|
*
|
|
1745
|
-
* @param {
|
|
1813
|
+
* @param {string | object} field located by label|name|CSS|XPath|strict locator.
|
|
1746
1814
|
* @param {string} value value to check.
|
|
1747
1815
|
*/
|
|
1748
1816
|
async dontSeeInField(field, value) {
|
|
@@ -1759,7 +1827,7 @@ class Playwright extends Helper {
|
|
|
1759
1827
|
* I.attachFile('form input[name=avatar]', 'data/avatar.jpg');
|
|
1760
1828
|
* ```
|
|
1761
1829
|
*
|
|
1762
|
-
* @param {
|
|
1830
|
+
* @param {string | object} locator field located by label|name|CSS|XPath|strict locator.
|
|
1763
1831
|
* @param {string} pathToFile local file path relative to codecept.json config file.
|
|
1764
1832
|
*
|
|
1765
1833
|
*/
|
|
@@ -1794,7 +1862,7 @@ class Playwright extends Helper {
|
|
|
1794
1862
|
* ```js
|
|
1795
1863
|
* I.selectOption('Which OS do you use?', ['Android', 'iOS']);
|
|
1796
1864
|
* ```
|
|
1797
|
-
* @param {
|
|
1865
|
+
* @param {string | object} select field located by label|name|CSS|XPath|strict locator.
|
|
1798
1866
|
* @param {string|Array<*>} option visible text or value of option.
|
|
1799
1867
|
*
|
|
1800
1868
|
*/
|
|
@@ -1835,7 +1903,7 @@ class Playwright extends Helper {
|
|
|
1835
1903
|
* let numOfElements = await I.grabNumberOfVisibleElements('p');
|
|
1836
1904
|
* ```
|
|
1837
1905
|
*
|
|
1838
|
-
* @param {
|
|
1906
|
+
* @param {string | object} locator located by CSS|XPath|strict locator.
|
|
1839
1907
|
* @returns {Promise<number>} number of visible elements
|
|
1840
1908
|
*
|
|
1841
1909
|
*/
|
|
@@ -1908,7 +1976,7 @@ class Playwright extends Helper {
|
|
|
1908
1976
|
* I.see('Register', {css: 'form.register'}); // use strict locator
|
|
1909
1977
|
* ```
|
|
1910
1978
|
* @param {string} text expected on page.
|
|
1911
|
-
* @param {?
|
|
1979
|
+
* @param {?string | object} [context=null] (optional, `null` by default) element located by CSS|Xpath|strict locator in which to search for text.
|
|
1912
1980
|
*
|
|
1913
1981
|
*
|
|
1914
1982
|
*/
|
|
@@ -1924,7 +1992,7 @@ class Playwright extends Helper {
|
|
|
1924
1992
|
* ```
|
|
1925
1993
|
*
|
|
1926
1994
|
* @param {string} text element value to check.
|
|
1927
|
-
* @param {
|
|
1995
|
+
* @param {(string | object)?} [context=null] element located by CSS|XPath|strict locator.
|
|
1928
1996
|
*/
|
|
1929
1997
|
async seeTextEquals(text, context = null) {
|
|
1930
1998
|
return proceedSee.call(this, 'assert', text, context, true);
|
|
@@ -1940,7 +2008,7 @@ class Playwright extends Helper {
|
|
|
1940
2008
|
* ```
|
|
1941
2009
|
*
|
|
1942
2010
|
* @param {string} text which is not present.
|
|
1943
|
-
* @param {
|
|
2011
|
+
* @param {string | object} [context] (optional) element located by CSS|XPath|strict locator in which to perfrom search.
|
|
1944
2012
|
*
|
|
1945
2013
|
*
|
|
1946
2014
|
*
|
|
@@ -2030,7 +2098,7 @@ class Playwright extends Helper {
|
|
|
2030
2098
|
* I.seeNumberOfElements('#submitBtn', 1);
|
|
2031
2099
|
* ```
|
|
2032
2100
|
*
|
|
2033
|
-
* @param {
|
|
2101
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2034
2102
|
* @param {number} num number of elements.
|
|
2035
2103
|
*
|
|
2036
2104
|
*
|
|
@@ -2049,7 +2117,7 @@ class Playwright extends Helper {
|
|
|
2049
2117
|
* I.seeNumberOfVisibleElements('.buttons', 3);
|
|
2050
2118
|
* ```
|
|
2051
2119
|
*
|
|
2052
|
-
* @param {
|
|
2120
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2053
2121
|
* @param {number} num number of elements.
|
|
2054
2122
|
*
|
|
2055
2123
|
*
|
|
@@ -2151,7 +2219,7 @@ class Playwright extends Helper {
|
|
|
2151
2219
|
*/
|
|
2152
2220
|
async clearCookie() {
|
|
2153
2221
|
// Playwright currently doesn't support to delete a certain cookie
|
|
2154
|
-
// https://github.com/microsoft/playwright/blob/
|
|
2222
|
+
// https://github.com/microsoft/playwright/blob/main/docs/api.md#class-browsercontext
|
|
2155
2223
|
if (!this.browserContext) return;
|
|
2156
2224
|
return this.browserContext.clearCookies();
|
|
2157
2225
|
}
|
|
@@ -2213,7 +2281,7 @@ class Playwright extends Helper {
|
|
|
2213
2281
|
* ```
|
|
2214
2282
|
* If multiple elements found returns first element.
|
|
2215
2283
|
*
|
|
2216
|
-
* @param {
|
|
2284
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2217
2285
|
* @returns {Promise<string>} attribute value
|
|
2218
2286
|
*
|
|
2219
2287
|
*
|
|
@@ -2234,7 +2302,7 @@ class Playwright extends Helper {
|
|
|
2234
2302
|
* let pins = await I.grabTextFromAll('#pin li');
|
|
2235
2303
|
* ```
|
|
2236
2304
|
*
|
|
2237
|
-
* @param {
|
|
2305
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2238
2306
|
* @returns {Promise<string[]>} attribute value
|
|
2239
2307
|
*
|
|
2240
2308
|
*
|
|
@@ -2257,7 +2325,7 @@ class Playwright extends Helper {
|
|
|
2257
2325
|
* ```js
|
|
2258
2326
|
* let email = await I.grabValueFrom('input[name=email]');
|
|
2259
2327
|
* ```
|
|
2260
|
-
* @param {
|
|
2328
|
+
* @param {string | object} locator field located by label|name|CSS|XPath|strict locator.
|
|
2261
2329
|
* @returns {Promise<string>} attribute value
|
|
2262
2330
|
*
|
|
2263
2331
|
*/
|
|
@@ -2275,7 +2343,7 @@ class Playwright extends Helper {
|
|
|
2275
2343
|
* ```js
|
|
2276
2344
|
* let inputs = await I.grabValueFromAll('//form/input');
|
|
2277
2345
|
* ```
|
|
2278
|
-
* @param {
|
|
2346
|
+
* @param {string | object} locator field located by label|name|CSS|XPath|strict locator.
|
|
2279
2347
|
* @returns {Promise<string[]>} attribute value
|
|
2280
2348
|
*
|
|
2281
2349
|
*/
|
|
@@ -2294,7 +2362,7 @@ class Playwright extends Helper {
|
|
|
2294
2362
|
* let postHTML = await I.grabHTMLFrom('#post');
|
|
2295
2363
|
* ```
|
|
2296
2364
|
*
|
|
2297
|
-
* @param {
|
|
2365
|
+
* @param {string | object} element located by CSS|XPath|strict locator.
|
|
2298
2366
|
* @returns {Promise<string>} HTML code for an element
|
|
2299
2367
|
*
|
|
2300
2368
|
*/
|
|
@@ -2313,7 +2381,7 @@ class Playwright extends Helper {
|
|
|
2313
2381
|
* let postHTMLs = await I.grabHTMLFromAll('.post');
|
|
2314
2382
|
* ```
|
|
2315
2383
|
*
|
|
2316
|
-
* @param {
|
|
2384
|
+
* @param {string | object} element located by CSS|XPath|strict locator.
|
|
2317
2385
|
* @returns {Promise<string[]>} HTML code for an element
|
|
2318
2386
|
*
|
|
2319
2387
|
*/
|
|
@@ -2332,7 +2400,7 @@ class Playwright extends Helper {
|
|
|
2332
2400
|
* const value = await I.grabCssPropertyFrom('h3', 'font-weight');
|
|
2333
2401
|
* ```
|
|
2334
2402
|
*
|
|
2335
|
-
* @param {
|
|
2403
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2336
2404
|
* @param {string} cssProperty CSS property name.
|
|
2337
2405
|
* @returns {Promise<string>} CSS value
|
|
2338
2406
|
*
|
|
@@ -2353,7 +2421,7 @@ class Playwright extends Helper {
|
|
|
2353
2421
|
* const values = await I.grabCssPropertyFromAll('h3', 'font-weight');
|
|
2354
2422
|
* ```
|
|
2355
2423
|
*
|
|
2356
|
-
* @param {
|
|
2424
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2357
2425
|
* @param {string} cssProperty CSS property name.
|
|
2358
2426
|
* @returns {Promise<string[]>} CSS value
|
|
2359
2427
|
*
|
|
@@ -2374,7 +2442,7 @@ class Playwright extends Helper {
|
|
|
2374
2442
|
* I.seeCssPropertiesOnElements('h3', { 'font-weight': "bold"});
|
|
2375
2443
|
* ```
|
|
2376
2444
|
*
|
|
2377
|
-
* @param {
|
|
2445
|
+
* @param {string | object} locator located by CSS|XPath|strict locator.
|
|
2378
2446
|
* @param {object} cssProperties object with CSS properties and their values to check.
|
|
2379
2447
|
*
|
|
2380
2448
|
*/
|
|
@@ -2419,7 +2487,7 @@ class Playwright extends Helper {
|
|
|
2419
2487
|
* I.seeAttributesOnElements('//form', { method: "post"});
|
|
2420
2488
|
* ```
|
|
2421
2489
|
*
|
|
2422
|
-
* @param {
|
|
2490
|
+
* @param {string | object} locator located by CSS|XPath|strict locator.
|
|
2423
2491
|
* @param {object} attributes attributes and their values to check.
|
|
2424
2492
|
*
|
|
2425
2493
|
*/
|
|
@@ -2457,7 +2525,7 @@ class Playwright extends Helper {
|
|
|
2457
2525
|
* I.dragSlider('#slider', -70);
|
|
2458
2526
|
* ```
|
|
2459
2527
|
*
|
|
2460
|
-
* @param {
|
|
2528
|
+
* @param {string | object} locator located by label|name|CSS|XPath|strict locator.
|
|
2461
2529
|
* @param {number} offsetX position to drag.
|
|
2462
2530
|
*
|
|
2463
2531
|
*/
|
|
@@ -2487,7 +2555,7 @@ class Playwright extends Helper {
|
|
|
2487
2555
|
* ```js
|
|
2488
2556
|
* let hint = await I.grabAttributeFrom('#tooltip', 'title');
|
|
2489
2557
|
* ```
|
|
2490
|
-
* @param {
|
|
2558
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2491
2559
|
* @param {string} attr attribute name.
|
|
2492
2560
|
* @returns {Promise<string>} attribute value
|
|
2493
2561
|
*
|
|
@@ -2507,7 +2575,7 @@ class Playwright extends Helper {
|
|
|
2507
2575
|
* ```js
|
|
2508
2576
|
* let hints = await I.grabAttributeFromAll('.tooltip', 'title');
|
|
2509
2577
|
* ```
|
|
2510
|
-
* @param {
|
|
2578
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2511
2579
|
* @param {string} attr attribute name.
|
|
2512
2580
|
* @returns {Promise<string[]>} attribute value
|
|
2513
2581
|
*
|
|
@@ -2534,7 +2602,7 @@ class Playwright extends Helper {
|
|
|
2534
2602
|
* I.saveElementScreenshot(`#submit`,'debug.png');
|
|
2535
2603
|
* ```
|
|
2536
2604
|
*
|
|
2537
|
-
* @param {
|
|
2605
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2538
2606
|
* @param {string} fileName file name to save.
|
|
2539
2607
|
*
|
|
2540
2608
|
*
|
|
@@ -2584,6 +2652,53 @@ class Playwright extends Helper {
|
|
|
2584
2652
|
return this.page.screenshot({ path: outputFile, fullPage: fullPageOption, type: 'png' });
|
|
2585
2653
|
}
|
|
2586
2654
|
|
|
2655
|
+
/**
|
|
2656
|
+
* Performs [api request](https://playwright.dev/docs/api/class-apirequestcontext#api-request-context-get) using
|
|
2657
|
+
* the cookies from the current browser session.
|
|
2658
|
+
*
|
|
2659
|
+
* ```js
|
|
2660
|
+
* const users = await I.makeApiRequest('GET', '/api/users', { params: { page: 1 }});
|
|
2661
|
+
* users[0]
|
|
2662
|
+
* I.makeApiRequest('PATCH', )
|
|
2663
|
+
* ```
|
|
2664
|
+
*
|
|
2665
|
+
* > This is Playwright's built-in alternative to using REST helper's sendGet, sendPost, etc methods.
|
|
2666
|
+
*
|
|
2667
|
+
* @param {string} method HTTP method
|
|
2668
|
+
* @param {string} url endpoint
|
|
2669
|
+
* @param {object} options request options depending on method used
|
|
2670
|
+
* @returns {Promise<object>} response
|
|
2671
|
+
*/
|
|
2672
|
+
async makeApiRequest(method, url, options) {
|
|
2673
|
+
method = method.toLowerCase();
|
|
2674
|
+
const allowedMethods = ['get', 'post', 'patch', 'head', 'fetch', 'delete'];
|
|
2675
|
+
if (!allowedMethods.includes(method)) {
|
|
2676
|
+
throw new Error(`Method ${method} is not allowed, use the one from a list ${allowedMethods} or switch to using REST helper`);
|
|
2677
|
+
}
|
|
2678
|
+
|
|
2679
|
+
if (url.startsWith('/')) { // local url
|
|
2680
|
+
url = this.options.url + url;
|
|
2681
|
+
this.debugSection('URL', url);
|
|
2682
|
+
}
|
|
2683
|
+
|
|
2684
|
+
const response = await this.page.request[method](url, options);
|
|
2685
|
+
this.debugSection('Status', response.status());
|
|
2686
|
+
this.debugSection('Response', await response.text());
|
|
2687
|
+
|
|
2688
|
+
// hook to allow JSON response handle this
|
|
2689
|
+
if (this.config.onResponse) {
|
|
2690
|
+
const axiosResponse = {
|
|
2691
|
+
data: await response.json(),
|
|
2692
|
+
status: response.status(),
|
|
2693
|
+
statusText: response.statusText(),
|
|
2694
|
+
headers: response.headers(),
|
|
2695
|
+
};
|
|
2696
|
+
this.config.onResponse(axiosResponse);
|
|
2697
|
+
}
|
|
2698
|
+
|
|
2699
|
+
return response;
|
|
2700
|
+
}
|
|
2701
|
+
|
|
2587
2702
|
async _failed(test) {
|
|
2588
2703
|
await this._withinEnd();
|
|
2589
2704
|
|
|
@@ -2596,7 +2711,7 @@ class Playwright extends Helper {
|
|
|
2596
2711
|
}
|
|
2597
2712
|
|
|
2598
2713
|
if (this.options.trace) {
|
|
2599
|
-
const path = `${global.output_dir}/trace/${clearString(test.title)
|
|
2714
|
+
const path = `${`${global.output_dir}/trace/${clearString(test.title)}`.slice(0, 251)}.zip`;
|
|
2600
2715
|
await this.browserContext.tracing.stop({ path });
|
|
2601
2716
|
test.artifacts.trace = path;
|
|
2602
2717
|
}
|
|
@@ -2641,7 +2756,7 @@ class Playwright extends Helper {
|
|
|
2641
2756
|
* Waits for element to become enabled (by default waits for 1sec).
|
|
2642
2757
|
* Element can be located by CSS or XPath.
|
|
2643
2758
|
*
|
|
2644
|
-
* @param {
|
|
2759
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2645
2760
|
* @param {number} [sec=1] (optional) time in seconds to wait, 1 by default.
|
|
2646
2761
|
*/
|
|
2647
2762
|
async waitForEnabled(locator, sec) {
|
|
@@ -2674,7 +2789,7 @@ class Playwright extends Helper {
|
|
|
2674
2789
|
* I.waitForValue('//input', "GoodValue");
|
|
2675
2790
|
* ```
|
|
2676
2791
|
*
|
|
2677
|
-
* @param {
|
|
2792
|
+
* @param {string | object} field input field.
|
|
2678
2793
|
* @param {string }value expected value.
|
|
2679
2794
|
* @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
2680
2795
|
*
|
|
@@ -2710,7 +2825,7 @@ class Playwright extends Helper {
|
|
|
2710
2825
|
* I.waitNumberOfVisibleElements('a', 3);
|
|
2711
2826
|
* ```
|
|
2712
2827
|
*
|
|
2713
|
-
* @param {
|
|
2828
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2714
2829
|
* @param {number} num number of elements.
|
|
2715
2830
|
* @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
2716
2831
|
*
|
|
@@ -2751,7 +2866,7 @@ class Playwright extends Helper {
|
|
|
2751
2866
|
* I.waitForClickable('.btn.continue', 5); // wait for 5 secs
|
|
2752
2867
|
* ```
|
|
2753
2868
|
*
|
|
2754
|
-
* @param {
|
|
2869
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2755
2870
|
* @param {number} [sec] (optional, `1` by default) time in seconds to wait
|
|
2756
2871
|
*/
|
|
2757
2872
|
async waitForClickable(locator, waitTimeout) {
|
|
@@ -2768,7 +2883,7 @@ class Playwright extends Helper {
|
|
|
2768
2883
|
* I.waitForElement('.btn.continue', 5); // wait for 5 secs
|
|
2769
2884
|
* ```
|
|
2770
2885
|
*
|
|
2771
|
-
* @param {
|
|
2886
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2772
2887
|
* @param {number} [sec] (optional, `1` by default) time in seconds to wait
|
|
2773
2888
|
*
|
|
2774
2889
|
*/
|
|
@@ -2791,7 +2906,7 @@ class Playwright extends Helper {
|
|
|
2791
2906
|
* I.waitForVisible('#popup');
|
|
2792
2907
|
* ```
|
|
2793
2908
|
*
|
|
2794
|
-
* @param {
|
|
2909
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2795
2910
|
* @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
2796
2911
|
*
|
|
2797
2912
|
*
|
|
@@ -2815,7 +2930,7 @@ class Playwright extends Helper {
|
|
|
2815
2930
|
* I.waitForInvisible('#popup');
|
|
2816
2931
|
* ```
|
|
2817
2932
|
*
|
|
2818
|
-
* @param {
|
|
2933
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2819
2934
|
* @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
2820
2935
|
*/
|
|
2821
2936
|
async waitForInvisible(locator, sec) {
|
|
@@ -2836,7 +2951,7 @@ class Playwright extends Helper {
|
|
|
2836
2951
|
* I.waitToHide('#popup');
|
|
2837
2952
|
* ```
|
|
2838
2953
|
*
|
|
2839
|
-
* @param {
|
|
2954
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2840
2955
|
* @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
2841
2956
|
*/
|
|
2842
2957
|
async waitToHide(locator, sec) {
|
|
@@ -2925,7 +3040,7 @@ class Playwright extends Helper {
|
|
|
2925
3040
|
*
|
|
2926
3041
|
* @param {string }text to wait for.
|
|
2927
3042
|
* @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
2928
|
-
* @param {
|
|
3043
|
+
* @param {string | object} [context] (optional) element located by CSS|XPath|strict locator.
|
|
2929
3044
|
*/
|
|
2930
3045
|
async waitForText(text, sec = null, context = null) {
|
|
2931
3046
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -2995,7 +3110,7 @@ class Playwright extends Helper {
|
|
|
2995
3110
|
* I.switchTo(); // switch back to main page
|
|
2996
3111
|
* ```
|
|
2997
3112
|
*
|
|
2998
|
-
* @param {?
|
|
3113
|
+
* @param {?string | object} [locator=null] (optional, `null` by default) element located by CSS|XPath|strict locator.
|
|
2999
3114
|
*/
|
|
3000
3115
|
async switchTo(locator) {
|
|
3001
3116
|
if (Number.isInteger(locator)) {
|
|
@@ -3100,7 +3215,7 @@ class Playwright extends Helper {
|
|
|
3100
3215
|
* I.waitForDetached('#popup');
|
|
3101
3216
|
* ```
|
|
3102
3217
|
*
|
|
3103
|
-
* @param {
|
|
3218
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
3104
3219
|
* @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
3105
3220
|
*/
|
|
3106
3221
|
async waitForDetached(locator, sec) {
|
|
@@ -3170,7 +3285,7 @@ class Playwright extends Helper {
|
|
|
3170
3285
|
* const width = await I.grabElementBoundingRect('h3', 'width');
|
|
3171
3286
|
* // width == 527
|
|
3172
3287
|
* ```
|
|
3173
|
-
* @param {
|
|
3288
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
3174
3289
|
* @param {string=} elementSize x, y, width or height of the given element.
|
|
3175
3290
|
* @returns {Promise<DOMRect>|Promise<number>} Element bounding rectangle
|
|
3176
3291
|
*
|
|
@@ -3357,8 +3472,7 @@ async function findCheckable(locator, context) {
|
|
|
3357
3472
|
async function proceedIsChecked(assertType, option) {
|
|
3358
3473
|
let els = await findCheckable.call(this, option);
|
|
3359
3474
|
assertElementExists(els, option, 'Checkable');
|
|
3360
|
-
els = await Promise.all(els.map(el => el.
|
|
3361
|
-
els = await Promise.all(els.map(el => el.jsonValue()));
|
|
3475
|
+
els = await Promise.all(els.map(el => el.isChecked()));
|
|
3362
3476
|
const selected = els.reduce((prev, cur) => prev || cur);
|
|
3363
3477
|
return truth(`checkable ${option}`, 'to be checked')[assertType](selected);
|
|
3364
3478
|
}
|
|
@@ -3386,36 +3500,6 @@ async function findFields(locator) {
|
|
|
3386
3500
|
return this._locate({ css: locator });
|
|
3387
3501
|
}
|
|
3388
3502
|
|
|
3389
|
-
async function proceedDragAndDrop(sourceLocator, destinationLocator) {
|
|
3390
|
-
// modern drag and drop in Playwright
|
|
3391
|
-
if (this.page.dragAndDrop) {
|
|
3392
|
-
const source = new Locator(sourceLocator);
|
|
3393
|
-
const dest = new Locator(destinationLocator);
|
|
3394
|
-
if (source.isBasic() && dest.isBasic()) {
|
|
3395
|
-
return this.page.dragAndDrop(source.simplify(), dest.simplify());
|
|
3396
|
-
}
|
|
3397
|
-
}
|
|
3398
|
-
|
|
3399
|
-
const src = await this._locate(sourceLocator);
|
|
3400
|
-
assertElementExists(src, sourceLocator, 'Source Element');
|
|
3401
|
-
|
|
3402
|
-
const dst = await this._locate(destinationLocator);
|
|
3403
|
-
assertElementExists(dst, destinationLocator, 'Destination Element');
|
|
3404
|
-
|
|
3405
|
-
// Note: Using clickablePoint private api becaues the .BoundingBox does not take into account iframe offsets!
|
|
3406
|
-
const dragSource = await clickablePoint(src[0]);
|
|
3407
|
-
const dragDestination = await clickablePoint(dst[0]);
|
|
3408
|
-
|
|
3409
|
-
// Drag start point
|
|
3410
|
-
await this.page.mouse.move(dragSource.x, dragSource.y, { steps: 5 });
|
|
3411
|
-
await this.page.mouse.down();
|
|
3412
|
-
|
|
3413
|
-
// Drag destination
|
|
3414
|
-
await this.page.mouse.move(dragDestination.x, dragDestination.y, { steps: 5 });
|
|
3415
|
-
await this.page.mouse.up();
|
|
3416
|
-
await this._waitForAction();
|
|
3417
|
-
}
|
|
3418
|
-
|
|
3419
3503
|
async function proceedSeeInField(assertType, field, value) {
|
|
3420
3504
|
const els = await findFields.call(this, field);
|
|
3421
3505
|
assertElementExists(els, field, 'Field');
|
|
@@ -3442,14 +3526,15 @@ async function proceedSeeInField(assertType, field, value) {
|
|
|
3442
3526
|
};
|
|
3443
3527
|
|
|
3444
3528
|
if (tag === 'SELECT') {
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3529
|
+
if (await el.getProperty('multiple')) {
|
|
3530
|
+
const selectedOptions = await el.$$('option:checked');
|
|
3531
|
+
if (!selectedOptions.length) return null;
|
|
3532
|
+
|
|
3533
|
+
const options = await filterFieldsByValue(selectedOptions, value, true);
|
|
3534
|
+
return proceedMultiple(options);
|
|
3449
3535
|
}
|
|
3450
3536
|
|
|
3451
|
-
|
|
3452
|
-
return proceedMultiple(options);
|
|
3537
|
+
return el.inputValue();
|
|
3453
3538
|
}
|
|
3454
3539
|
|
|
3455
3540
|
if (tag === 'INPUT') {
|
|
@@ -3465,7 +3550,8 @@ async function proceedSeeInField(assertType, field, value) {
|
|
|
3465
3550
|
}
|
|
3466
3551
|
return proceedMultiple(els[0]);
|
|
3467
3552
|
}
|
|
3468
|
-
|
|
3553
|
+
|
|
3554
|
+
const fieldVal = await el.inputValue();
|
|
3469
3555
|
return stringIncludes(`fields by ${field}`)[assertType](value, fieldVal);
|
|
3470
3556
|
}
|
|
3471
3557
|
|
|
@@ -3496,10 +3582,10 @@ async function filterFieldsBySelectionState(elements, state) {
|
|
|
3496
3582
|
}
|
|
3497
3583
|
|
|
3498
3584
|
async function elementSelected(element) {
|
|
3499
|
-
const type = await element.getProperty('type').then(el => el.jsonValue());
|
|
3585
|
+
const type = await element.getProperty('type').then(el => !!el && el.jsonValue());
|
|
3500
3586
|
|
|
3501
3587
|
if (type === 'checkbox' || type === 'radio') {
|
|
3502
|
-
return element.
|
|
3588
|
+
return element.isChecked();
|
|
3503
3589
|
}
|
|
3504
3590
|
return element.getProperty('selected').then(el => el.jsonValue());
|
|
3505
3591
|
}
|
|
@@ -3547,12 +3633,18 @@ async function targetCreatedHandler(page) {
|
|
|
3547
3633
|
});
|
|
3548
3634
|
});
|
|
3549
3635
|
page.on('console', (msg) => {
|
|
3550
|
-
|
|
3636
|
+
if (!consoleLogStore.includes(msg) && this.options.ignoreLog && !this.options.ignoreLog.includes(msg.type())) {
|
|
3637
|
+
this.debugSection(`Browser:${ucfirst(msg.type())}`, (msg.text && msg.text() || msg._text || '') + msg.args().join(' '));
|
|
3638
|
+
}
|
|
3551
3639
|
consoleLogStore.add(msg);
|
|
3552
3640
|
});
|
|
3553
3641
|
|
|
3554
3642
|
if (this.options.windowSize && this.options.windowSize.indexOf('x') > 0 && this._getType() === 'Browser') {
|
|
3555
|
-
|
|
3643
|
+
try {
|
|
3644
|
+
await page.setViewportSize(parseWindowSize(this.options.windowSize));
|
|
3645
|
+
} catch (err) {
|
|
3646
|
+
// target can be already closed, ignoring...
|
|
3647
|
+
}
|
|
3556
3648
|
}
|
|
3557
3649
|
}
|
|
3558
3650
|
|
|
@@ -3642,3 +3734,37 @@ async function clickablePoint(el) {
|
|
|
3642
3734
|
} = rect;
|
|
3643
3735
|
return { x: x + width / 2, y: y + height / 2 };
|
|
3644
3736
|
}
|
|
3737
|
+
|
|
3738
|
+
async function refreshContextSession() {
|
|
3739
|
+
// close other sessions
|
|
3740
|
+
try {
|
|
3741
|
+
const contexts = await this.browser.contexts();
|
|
3742
|
+
contexts.shift();
|
|
3743
|
+
|
|
3744
|
+
await Promise.all(contexts.map(c => c.close()));
|
|
3745
|
+
} catch (e) {
|
|
3746
|
+
console.log(e);
|
|
3747
|
+
}
|
|
3748
|
+
|
|
3749
|
+
if (this.page) {
|
|
3750
|
+
const existingPages = await this.browserContext.pages();
|
|
3751
|
+
await this._setPage(existingPages[0]);
|
|
3752
|
+
}
|
|
3753
|
+
|
|
3754
|
+
if (this.options.keepBrowserState) return;
|
|
3755
|
+
|
|
3756
|
+
if (!this.options.keepCookies) {
|
|
3757
|
+
this.debugSection('Session', 'cleaning cookies and localStorage');
|
|
3758
|
+
await this.clearCookie();
|
|
3759
|
+
}
|
|
3760
|
+
const currentUrl = await this.grabCurrentUrl();
|
|
3761
|
+
|
|
3762
|
+
if (currentUrl.startsWith('http')) {
|
|
3763
|
+
await this.executeScript('localStorage.clear();').catch((err) => {
|
|
3764
|
+
if (!(err.message.indexOf("Storage is disabled inside 'data:' URLs.") > -1)) throw err;
|
|
3765
|
+
});
|
|
3766
|
+
await this.executeScript('sessionStorage.clear();').catch((err) => {
|
|
3767
|
+
if (!(err.message.indexOf("Storage is disabled inside 'data:' URLs.") > -1)) throw err;
|
|
3768
|
+
});
|
|
3769
|
+
}
|
|
3770
|
+
}
|