codeceptjs 3.2.2 → 3.3.0-beta.3
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 +57 -0
- package/docs/advanced.md +2 -2
- package/docs/api.md +227 -188
- 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 +271 -151
- package/docs/build/Puppeteer.js +76 -67
- package/docs/build/REST.js +36 -0
- package/docs/build/TestCafe.js +44 -44
- package/docs/build/WebDriver.js +69 -69
- package/docs/changelog.md +7 -0
- 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/playwright.md +73 -18
- package/docs/plugins.md +136 -36
- 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/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 +209 -89
- package/lib/helper/Puppeteer.js +12 -3
- package/lib/helper/REST.js +36 -0
- 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/plugin/allure.js +12 -0
- package/lib/plugin/autoLogin.js +1 -1
- package/lib/plugin/eachElement.js +127 -0
- package/lib/plugin/tryTo.js +6 -0
- package/lib/utils.js +20 -0
- package/package.json +25 -23
- package/translations/pt-BR.js +8 -0
- package/typings/index.d.ts +4 -0
- package/typings/types.d.ts +318 -109
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
|
}
|
|
@@ -366,7 +389,7 @@ class Playwright extends Helper {
|
|
|
366
389
|
},
|
|
367
390
|
});
|
|
368
391
|
|
|
369
|
-
if (
|
|
392
|
+
if (restartsBrowser() && !this.options.manualStart) await this._startBrowser();
|
|
370
393
|
if (!this.isRunning && !this.options.manualStart) await this._startBrowser();
|
|
371
394
|
|
|
372
395
|
this.isAuthenticated = false;
|
|
@@ -388,7 +411,9 @@ class Playwright extends Helper {
|
|
|
388
411
|
if (this.storageState) contextOptions.storageState = this.storageState;
|
|
389
412
|
if (this.options.userAgent) contextOptions.userAgent = this.options.userAgent;
|
|
390
413
|
if (this.options.locale) contextOptions.locale = this.options.locale;
|
|
391
|
-
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
|
+
}
|
|
392
417
|
}
|
|
393
418
|
|
|
394
419
|
let mainPage;
|
|
@@ -416,7 +441,11 @@ class Playwright extends Helper {
|
|
|
416
441
|
return;
|
|
417
442
|
}
|
|
418
443
|
|
|
419
|
-
if (
|
|
444
|
+
if (restartsSession()) {
|
|
445
|
+
return refreshContextSession.bind(this)();
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (restartsBrowser()) {
|
|
420
449
|
this.isRunning = false;
|
|
421
450
|
return this._stopBrowser();
|
|
422
451
|
}
|
|
@@ -438,11 +467,10 @@ class Playwright extends Helper {
|
|
|
438
467
|
return this.browser;
|
|
439
468
|
}
|
|
440
469
|
|
|
441
|
-
_afterSuite() {
|
|
442
|
-
}
|
|
470
|
+
_afterSuite() {}
|
|
443
471
|
|
|
444
|
-
_finishTest() {
|
|
445
|
-
if (
|
|
472
|
+
async _finishTest() {
|
|
473
|
+
if ((restartsSession() || restartsContext()) && this.isRunning) return this._stopBrowser();
|
|
446
474
|
}
|
|
447
475
|
|
|
448
476
|
_session() {
|
|
@@ -501,16 +529,16 @@ class Playwright extends Helper {
|
|
|
501
529
|
* First argument is a description of an action.
|
|
502
530
|
* Second argument is async function that gets this helper as parameter.
|
|
503
531
|
*
|
|
504
|
-
* { [`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.
|
|
505
533
|
*
|
|
506
534
|
* ```js
|
|
507
|
-
* I.usePlaywrightTo('emulate offline mode', async ({
|
|
508
|
-
* await
|
|
535
|
+
* I.usePlaywrightTo('emulate offline mode', async ({ browserContext }) => {
|
|
536
|
+
* await browserContext.setOffline(true);
|
|
509
537
|
* });
|
|
510
538
|
* ```
|
|
511
539
|
*
|
|
512
540
|
* @param {string} description used to show in logs.
|
|
513
|
-
* @param {function} fn async
|
|
541
|
+
* @param {function} fn async function that executed with Playwright helper as argument
|
|
514
542
|
*/
|
|
515
543
|
usePlaywrightTo(description, fn) {
|
|
516
544
|
return this._useTo(...arguments);
|
|
@@ -585,7 +613,9 @@ class Playwright extends Helper {
|
|
|
585
613
|
this._addPopupListener(page);
|
|
586
614
|
this.page = page;
|
|
587
615
|
if (!page) return;
|
|
616
|
+
this.browserContext.setDefaultTimeout(0);
|
|
588
617
|
page.setDefaultNavigationTimeout(this.options.getPageTimeout);
|
|
618
|
+
page.setDefaultTimeout(this.options.timeout);
|
|
589
619
|
|
|
590
620
|
page.on('crash', async () => {
|
|
591
621
|
console.log('ERROR: Page has crashed, closing page!');
|
|
@@ -686,7 +716,6 @@ class Playwright extends Helper {
|
|
|
686
716
|
this._setPage(null);
|
|
687
717
|
this.context = null;
|
|
688
718
|
popupStore.clear();
|
|
689
|
-
|
|
690
719
|
await this.browser.close();
|
|
691
720
|
}
|
|
692
721
|
|
|
@@ -834,7 +863,7 @@ class Playwright extends Helper {
|
|
|
834
863
|
* I.moveCursorTo('#submit', 5,5);
|
|
835
864
|
* ```
|
|
836
865
|
*
|
|
837
|
-
* @param {
|
|
866
|
+
* @param {string | object} locator located by CSS|XPath|strict locator.
|
|
838
867
|
* @param {number} [offsetX=0] (optional, `0` by default) X-axis offset.
|
|
839
868
|
* @param {number} [offsetY=0] (optional, `0` by default) Y-axis offset.
|
|
840
869
|
*
|
|
@@ -857,12 +886,24 @@ class Playwright extends Helper {
|
|
|
857
886
|
* I.dragAndDrop('#dragHandle', '#container');
|
|
858
887
|
* ```
|
|
859
888
|
*
|
|
860
|
-
* @param {
|
|
861
|
-
* @param {
|
|
889
|
+
* @param {string | object} srcElement located by CSS|XPath|strict locator.
|
|
890
|
+
* @param {string | object} destElement located by CSS|XPath|strict locator.
|
|
862
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
|
|
863
901
|
*/
|
|
864
|
-
async dragAndDrop(srcElement, destElement) {
|
|
865
|
-
|
|
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);
|
|
866
907
|
}
|
|
867
908
|
|
|
868
909
|
/**
|
|
@@ -919,7 +960,7 @@ class Playwright extends Helper {
|
|
|
919
960
|
* I.scrollTo('#submit', 5, 5);
|
|
920
961
|
* ```
|
|
921
962
|
*
|
|
922
|
-
* @param {
|
|
963
|
+
* @param {string | object} locator located by CSS|XPath|strict locator.
|
|
923
964
|
* @param {number} [offsetX=0] (optional, `0` by default) X-axis offset.
|
|
924
965
|
* @param {number} [offsetY=0] (optional, `0` by default) Y-axis offset.
|
|
925
966
|
*/
|
|
@@ -1169,7 +1210,7 @@ class Playwright extends Helper {
|
|
|
1169
1210
|
* I.openNewTab();
|
|
1170
1211
|
* ```
|
|
1171
1212
|
*
|
|
1172
|
-
* 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
|
|
1173
1214
|
*
|
|
1174
1215
|
* ```js
|
|
1175
1216
|
* // enable mobile
|
|
@@ -1207,7 +1248,7 @@ class Playwright extends Helper {
|
|
|
1207
1248
|
* ```js
|
|
1208
1249
|
* I.seeElement('#modal');
|
|
1209
1250
|
* ```
|
|
1210
|
-
* @param {
|
|
1251
|
+
* @param {string | object} locator located by CSS|XPath|strict locator.
|
|
1211
1252
|
*
|
|
1212
1253
|
*/
|
|
1213
1254
|
async seeElement(locator) {
|
|
@@ -1223,7 +1264,7 @@ class Playwright extends Helper {
|
|
|
1223
1264
|
* I.dontSeeElement('.modal'); // modal is not shown
|
|
1224
1265
|
* ```
|
|
1225
1266
|
*
|
|
1226
|
-
* @param {
|
|
1267
|
+
* @param {string | object} locator located by CSS|XPath|Strict locator.
|
|
1227
1268
|
*
|
|
1228
1269
|
*/
|
|
1229
1270
|
async dontSeeElement(locator) {
|
|
@@ -1239,7 +1280,7 @@ class Playwright extends Helper {
|
|
|
1239
1280
|
* ```js
|
|
1240
1281
|
* I.seeElementInDOM('#modal');
|
|
1241
1282
|
* ```
|
|
1242
|
-
* @param {
|
|
1283
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
1243
1284
|
*
|
|
1244
1285
|
*/
|
|
1245
1286
|
async seeElementInDOM(locator) {
|
|
@@ -1254,7 +1295,7 @@ class Playwright extends Helper {
|
|
|
1254
1295
|
* I.dontSeeElementInDOM('.nav'); // checks that element is not on page visible or not
|
|
1255
1296
|
* ```
|
|
1256
1297
|
*
|
|
1257
|
-
* @param {
|
|
1298
|
+
* @param {string | object} locator located by CSS|XPath|Strict locator.
|
|
1258
1299
|
*/
|
|
1259
1300
|
async dontSeeElementInDOM(locator) {
|
|
1260
1301
|
const els = await this._locate(locator);
|
|
@@ -1314,14 +1355,25 @@ class Playwright extends Helper {
|
|
|
1314
1355
|
* I.click({css: 'nav a.login'});
|
|
1315
1356
|
* ```
|
|
1316
1357
|
*
|
|
1317
|
-
* @param {
|
|
1318
|
-
* @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.
|
|
1319
1360
|
*
|
|
1320
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
|
+
* ```
|
|
1321
1373
|
*
|
|
1322
1374
|
*/
|
|
1323
|
-
async click(locator, context = null) {
|
|
1324
|
-
return proceedClick.call(this, locator, context);
|
|
1375
|
+
async click(locator, context = null, opts = {}) {
|
|
1376
|
+
return proceedClick.call(this, locator, context, opts);
|
|
1325
1377
|
}
|
|
1326
1378
|
|
|
1327
1379
|
/**
|
|
@@ -1359,8 +1411,8 @@ class Playwright extends Helper {
|
|
|
1359
1411
|
* I.forceClick({css: 'nav a.login'});
|
|
1360
1412
|
* ```
|
|
1361
1413
|
*
|
|
1362
|
-
* @param {
|
|
1363
|
-
* @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.
|
|
1364
1416
|
*
|
|
1365
1417
|
*/
|
|
1366
1418
|
async forceClick(locator, context = null) {
|
|
@@ -1378,8 +1430,8 @@ class Playwright extends Helper {
|
|
|
1378
1430
|
* I.doubleClick('.btn.edit');
|
|
1379
1431
|
* ```
|
|
1380
1432
|
*
|
|
1381
|
-
* @param {
|
|
1382
|
-
* @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.
|
|
1383
1435
|
*
|
|
1384
1436
|
*
|
|
1385
1437
|
*
|
|
@@ -1400,8 +1452,8 @@ class Playwright extends Helper {
|
|
|
1400
1452
|
* I.rightClick('Click me', '.context');
|
|
1401
1453
|
* ```
|
|
1402
1454
|
*
|
|
1403
|
-
* @param {
|
|
1404
|
-
* @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.
|
|
1405
1457
|
*
|
|
1406
1458
|
*
|
|
1407
1459
|
*
|
|
@@ -1421,18 +1473,23 @@ class Playwright extends Helper {
|
|
|
1421
1473
|
* I.checkOption('I Agree to Terms and Conditions');
|
|
1422
1474
|
* I.checkOption('agree', '//form');
|
|
1423
1475
|
* ```
|
|
1424
|
-
* @param {
|
|
1425
|
-
* @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
|
|
1426
1488
|
*/
|
|
1427
|
-
async checkOption(field, context = null) {
|
|
1489
|
+
async checkOption(field, context = null, options = { force: true }) {
|
|
1428
1490
|
const elm = await this._locateCheckable(field, context);
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
// Only check if NOT currently checked
|
|
1432
|
-
if (!curentlyChecked) {
|
|
1433
|
-
await elm.click();
|
|
1434
|
-
return this._waitForAction();
|
|
1435
|
-
}
|
|
1491
|
+
await elm.check(options);
|
|
1492
|
+
return this._waitForAction();
|
|
1436
1493
|
}
|
|
1437
1494
|
|
|
1438
1495
|
/**
|
|
@@ -1446,18 +1503,23 @@ class Playwright extends Helper {
|
|
|
1446
1503
|
* I.uncheckOption('I Agree to Terms and Conditions');
|
|
1447
1504
|
* I.uncheckOption('agree', '//form');
|
|
1448
1505
|
* ```
|
|
1449
|
-
* @param {
|
|
1450
|
-
* @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
|
|
1451
1518
|
*/
|
|
1452
|
-
async uncheckOption(field, context = null) {
|
|
1519
|
+
async uncheckOption(field, context = null, options = { force: true }) {
|
|
1453
1520
|
const elm = await this._locateCheckable(field, context);
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
// Only uncheck if currently checked
|
|
1457
|
-
if (curentlyChecked) {
|
|
1458
|
-
await elm.click();
|
|
1459
|
-
return this._waitForAction();
|
|
1460
|
-
}
|
|
1521
|
+
await elm.uncheck(options);
|
|
1522
|
+
return this._waitForAction();
|
|
1461
1523
|
}
|
|
1462
1524
|
|
|
1463
1525
|
/**
|
|
@@ -1469,7 +1531,7 @@ class Playwright extends Helper {
|
|
|
1469
1531
|
* I.seeCheckboxIsChecked({css: '#signup_form input[type=checkbox]'});
|
|
1470
1532
|
* ```
|
|
1471
1533
|
*
|
|
1472
|
-
* @param {
|
|
1534
|
+
* @param {string | object} field located by label|name|CSS|XPath|strict locator.
|
|
1473
1535
|
*
|
|
1474
1536
|
*/
|
|
1475
1537
|
async seeCheckboxIsChecked(field) {
|
|
@@ -1485,7 +1547,7 @@ class Playwright extends Helper {
|
|
|
1485
1547
|
* I.dontSeeCheckboxIsChecked('agree'); // located by name
|
|
1486
1548
|
* ```
|
|
1487
1549
|
*
|
|
1488
|
-
* @param {
|
|
1550
|
+
* @param {string | object} field located by label|name|CSS|XPath|strict locator.
|
|
1489
1551
|
*
|
|
1490
1552
|
*/
|
|
1491
1553
|
async dontSeeCheckboxIsChecked(field) {
|
|
@@ -1666,8 +1728,8 @@ class Playwright extends Helper {
|
|
|
1666
1728
|
* // or by strict locator
|
|
1667
1729
|
* I.fillField({css: 'form#login input[name=username]'}, 'John');
|
|
1668
1730
|
* ```
|
|
1669
|
-
* @param {
|
|
1670
|
-
* @param {
|
|
1731
|
+
* @param {string | object} field located by label|name|CSS|XPath|strict locator.
|
|
1732
|
+
* @param {string | object} value text value to fill.
|
|
1671
1733
|
*
|
|
1672
1734
|
*
|
|
1673
1735
|
*/
|
|
@@ -1694,7 +1756,7 @@ class Playwright extends Helper {
|
|
|
1694
1756
|
* I.clearField('user[email]');
|
|
1695
1757
|
* I.clearField('#email');
|
|
1696
1758
|
* ```
|
|
1697
|
-
* @param {
|
|
1759
|
+
* @param {string | object} editable field located by label|name|CSS|XPath|strict locator.
|
|
1698
1760
|
*
|
|
1699
1761
|
*/
|
|
1700
1762
|
async clearField(field) {
|
|
@@ -1708,7 +1770,7 @@ class Playwright extends Helper {
|
|
|
1708
1770
|
* ```js
|
|
1709
1771
|
* I.appendField('#myTextField', 'appended');
|
|
1710
1772
|
* ```
|
|
1711
|
-
* @param {
|
|
1773
|
+
* @param {string | object} field located by label|name|CSS|XPath|strict locator
|
|
1712
1774
|
* @param {string} value text value to append.
|
|
1713
1775
|
*
|
|
1714
1776
|
*
|
|
@@ -1731,7 +1793,7 @@ class Playwright extends Helper {
|
|
|
1731
1793
|
* I.seeInField('form input[type=hidden]','hidden_value');
|
|
1732
1794
|
* I.seeInField('#searchform input','Search');
|
|
1733
1795
|
* ```
|
|
1734
|
-
* @param {
|
|
1796
|
+
* @param {string | object} field located by label|name|CSS|XPath|strict locator.
|
|
1735
1797
|
* @param {string} value value to check.
|
|
1736
1798
|
*
|
|
1737
1799
|
*/
|
|
@@ -1748,7 +1810,7 @@ class Playwright extends Helper {
|
|
|
1748
1810
|
* I.dontSeeInField({ css: 'form input.email' }, 'user@user.com'); // field by CSS
|
|
1749
1811
|
* ```
|
|
1750
1812
|
*
|
|
1751
|
-
* @param {
|
|
1813
|
+
* @param {string | object} field located by label|name|CSS|XPath|strict locator.
|
|
1752
1814
|
* @param {string} value value to check.
|
|
1753
1815
|
*/
|
|
1754
1816
|
async dontSeeInField(field, value) {
|
|
@@ -1765,7 +1827,7 @@ class Playwright extends Helper {
|
|
|
1765
1827
|
* I.attachFile('form input[name=avatar]', 'data/avatar.jpg');
|
|
1766
1828
|
* ```
|
|
1767
1829
|
*
|
|
1768
|
-
* @param {
|
|
1830
|
+
* @param {string | object} locator field located by label|name|CSS|XPath|strict locator.
|
|
1769
1831
|
* @param {string} pathToFile local file path relative to codecept.json config file.
|
|
1770
1832
|
*
|
|
1771
1833
|
*/
|
|
@@ -1800,7 +1862,7 @@ class Playwright extends Helper {
|
|
|
1800
1862
|
* ```js
|
|
1801
1863
|
* I.selectOption('Which OS do you use?', ['Android', 'iOS']);
|
|
1802
1864
|
* ```
|
|
1803
|
-
* @param {
|
|
1865
|
+
* @param {string | object} select field located by label|name|CSS|XPath|strict locator.
|
|
1804
1866
|
* @param {string|Array<*>} option visible text or value of option.
|
|
1805
1867
|
*
|
|
1806
1868
|
*/
|
|
@@ -1841,7 +1903,7 @@ class Playwright extends Helper {
|
|
|
1841
1903
|
* let numOfElements = await I.grabNumberOfVisibleElements('p');
|
|
1842
1904
|
* ```
|
|
1843
1905
|
*
|
|
1844
|
-
* @param {
|
|
1906
|
+
* @param {string | object} locator located by CSS|XPath|strict locator.
|
|
1845
1907
|
* @returns {Promise<number>} number of visible elements
|
|
1846
1908
|
*
|
|
1847
1909
|
*/
|
|
@@ -1914,7 +1976,7 @@ class Playwright extends Helper {
|
|
|
1914
1976
|
* I.see('Register', {css: 'form.register'}); // use strict locator
|
|
1915
1977
|
* ```
|
|
1916
1978
|
* @param {string} text expected on page.
|
|
1917
|
-
* @param {?
|
|
1979
|
+
* @param {?string | object} [context=null] (optional, `null` by default) element located by CSS|Xpath|strict locator in which to search for text.
|
|
1918
1980
|
*
|
|
1919
1981
|
*
|
|
1920
1982
|
*/
|
|
@@ -1930,7 +1992,7 @@ class Playwright extends Helper {
|
|
|
1930
1992
|
* ```
|
|
1931
1993
|
*
|
|
1932
1994
|
* @param {string} text element value to check.
|
|
1933
|
-
* @param {
|
|
1995
|
+
* @param {(string | object)?} [context=null] element located by CSS|XPath|strict locator.
|
|
1934
1996
|
*/
|
|
1935
1997
|
async seeTextEquals(text, context = null) {
|
|
1936
1998
|
return proceedSee.call(this, 'assert', text, context, true);
|
|
@@ -1946,7 +2008,7 @@ class Playwright extends Helper {
|
|
|
1946
2008
|
* ```
|
|
1947
2009
|
*
|
|
1948
2010
|
* @param {string} text which is not present.
|
|
1949
|
-
* @param {
|
|
2011
|
+
* @param {string | object} [context] (optional) element located by CSS|XPath|strict locator in which to perfrom search.
|
|
1950
2012
|
*
|
|
1951
2013
|
*
|
|
1952
2014
|
*
|
|
@@ -2036,7 +2098,7 @@ class Playwright extends Helper {
|
|
|
2036
2098
|
* I.seeNumberOfElements('#submitBtn', 1);
|
|
2037
2099
|
* ```
|
|
2038
2100
|
*
|
|
2039
|
-
* @param {
|
|
2101
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2040
2102
|
* @param {number} num number of elements.
|
|
2041
2103
|
*
|
|
2042
2104
|
*
|
|
@@ -2055,7 +2117,7 @@ class Playwright extends Helper {
|
|
|
2055
2117
|
* I.seeNumberOfVisibleElements('.buttons', 3);
|
|
2056
2118
|
* ```
|
|
2057
2119
|
*
|
|
2058
|
-
* @param {
|
|
2120
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2059
2121
|
* @param {number} num number of elements.
|
|
2060
2122
|
*
|
|
2061
2123
|
*
|
|
@@ -2157,7 +2219,7 @@ class Playwright extends Helper {
|
|
|
2157
2219
|
*/
|
|
2158
2220
|
async clearCookie() {
|
|
2159
2221
|
// Playwright currently doesn't support to delete a certain cookie
|
|
2160
|
-
// https://github.com/microsoft/playwright/blob/
|
|
2222
|
+
// https://github.com/microsoft/playwright/blob/main/docs/api.md#class-browsercontext
|
|
2161
2223
|
if (!this.browserContext) return;
|
|
2162
2224
|
return this.browserContext.clearCookies();
|
|
2163
2225
|
}
|
|
@@ -2219,7 +2281,7 @@ class Playwright extends Helper {
|
|
|
2219
2281
|
* ```
|
|
2220
2282
|
* If multiple elements found returns first element.
|
|
2221
2283
|
*
|
|
2222
|
-
* @param {
|
|
2284
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2223
2285
|
* @returns {Promise<string>} attribute value
|
|
2224
2286
|
*
|
|
2225
2287
|
*
|
|
@@ -2240,7 +2302,7 @@ class Playwright extends Helper {
|
|
|
2240
2302
|
* let pins = await I.grabTextFromAll('#pin li');
|
|
2241
2303
|
* ```
|
|
2242
2304
|
*
|
|
2243
|
-
* @param {
|
|
2305
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2244
2306
|
* @returns {Promise<string[]>} attribute value
|
|
2245
2307
|
*
|
|
2246
2308
|
*
|
|
@@ -2263,7 +2325,7 @@ class Playwright extends Helper {
|
|
|
2263
2325
|
* ```js
|
|
2264
2326
|
* let email = await I.grabValueFrom('input[name=email]');
|
|
2265
2327
|
* ```
|
|
2266
|
-
* @param {
|
|
2328
|
+
* @param {string | object} locator field located by label|name|CSS|XPath|strict locator.
|
|
2267
2329
|
* @returns {Promise<string>} attribute value
|
|
2268
2330
|
*
|
|
2269
2331
|
*/
|
|
@@ -2281,7 +2343,7 @@ class Playwright extends Helper {
|
|
|
2281
2343
|
* ```js
|
|
2282
2344
|
* let inputs = await I.grabValueFromAll('//form/input');
|
|
2283
2345
|
* ```
|
|
2284
|
-
* @param {
|
|
2346
|
+
* @param {string | object} locator field located by label|name|CSS|XPath|strict locator.
|
|
2285
2347
|
* @returns {Promise<string[]>} attribute value
|
|
2286
2348
|
*
|
|
2287
2349
|
*/
|
|
@@ -2300,7 +2362,7 @@ class Playwright extends Helper {
|
|
|
2300
2362
|
* let postHTML = await I.grabHTMLFrom('#post');
|
|
2301
2363
|
* ```
|
|
2302
2364
|
*
|
|
2303
|
-
* @param {
|
|
2365
|
+
* @param {string | object} element located by CSS|XPath|strict locator.
|
|
2304
2366
|
* @returns {Promise<string>} HTML code for an element
|
|
2305
2367
|
*
|
|
2306
2368
|
*/
|
|
@@ -2319,7 +2381,7 @@ class Playwright extends Helper {
|
|
|
2319
2381
|
* let postHTMLs = await I.grabHTMLFromAll('.post');
|
|
2320
2382
|
* ```
|
|
2321
2383
|
*
|
|
2322
|
-
* @param {
|
|
2384
|
+
* @param {string | object} element located by CSS|XPath|strict locator.
|
|
2323
2385
|
* @returns {Promise<string[]>} HTML code for an element
|
|
2324
2386
|
*
|
|
2325
2387
|
*/
|
|
@@ -2338,7 +2400,7 @@ class Playwright extends Helper {
|
|
|
2338
2400
|
* const value = await I.grabCssPropertyFrom('h3', 'font-weight');
|
|
2339
2401
|
* ```
|
|
2340
2402
|
*
|
|
2341
|
-
* @param {
|
|
2403
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2342
2404
|
* @param {string} cssProperty CSS property name.
|
|
2343
2405
|
* @returns {Promise<string>} CSS value
|
|
2344
2406
|
*
|
|
@@ -2359,7 +2421,7 @@ class Playwright extends Helper {
|
|
|
2359
2421
|
* const values = await I.grabCssPropertyFromAll('h3', 'font-weight');
|
|
2360
2422
|
* ```
|
|
2361
2423
|
*
|
|
2362
|
-
* @param {
|
|
2424
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2363
2425
|
* @param {string} cssProperty CSS property name.
|
|
2364
2426
|
* @returns {Promise<string[]>} CSS value
|
|
2365
2427
|
*
|
|
@@ -2380,7 +2442,7 @@ class Playwright extends Helper {
|
|
|
2380
2442
|
* I.seeCssPropertiesOnElements('h3', { 'font-weight': "bold"});
|
|
2381
2443
|
* ```
|
|
2382
2444
|
*
|
|
2383
|
-
* @param {
|
|
2445
|
+
* @param {string | object} locator located by CSS|XPath|strict locator.
|
|
2384
2446
|
* @param {object} cssProperties object with CSS properties and their values to check.
|
|
2385
2447
|
*
|
|
2386
2448
|
*/
|
|
@@ -2425,7 +2487,7 @@ class Playwright extends Helper {
|
|
|
2425
2487
|
* I.seeAttributesOnElements('//form', { method: "post"});
|
|
2426
2488
|
* ```
|
|
2427
2489
|
*
|
|
2428
|
-
* @param {
|
|
2490
|
+
* @param {string | object} locator located by CSS|XPath|strict locator.
|
|
2429
2491
|
* @param {object} attributes attributes and their values to check.
|
|
2430
2492
|
*
|
|
2431
2493
|
*/
|
|
@@ -2463,7 +2525,7 @@ class Playwright extends Helper {
|
|
|
2463
2525
|
* I.dragSlider('#slider', -70);
|
|
2464
2526
|
* ```
|
|
2465
2527
|
*
|
|
2466
|
-
* @param {
|
|
2528
|
+
* @param {string | object} locator located by label|name|CSS|XPath|strict locator.
|
|
2467
2529
|
* @param {number} offsetX position to drag.
|
|
2468
2530
|
*
|
|
2469
2531
|
*/
|
|
@@ -2493,7 +2555,7 @@ class Playwright extends Helper {
|
|
|
2493
2555
|
* ```js
|
|
2494
2556
|
* let hint = await I.grabAttributeFrom('#tooltip', 'title');
|
|
2495
2557
|
* ```
|
|
2496
|
-
* @param {
|
|
2558
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2497
2559
|
* @param {string} attr attribute name.
|
|
2498
2560
|
* @returns {Promise<string>} attribute value
|
|
2499
2561
|
*
|
|
@@ -2513,7 +2575,7 @@ class Playwright extends Helper {
|
|
|
2513
2575
|
* ```js
|
|
2514
2576
|
* let hints = await I.grabAttributeFromAll('.tooltip', 'title');
|
|
2515
2577
|
* ```
|
|
2516
|
-
* @param {
|
|
2578
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2517
2579
|
* @param {string} attr attribute name.
|
|
2518
2580
|
* @returns {Promise<string[]>} attribute value
|
|
2519
2581
|
*
|
|
@@ -2540,7 +2602,7 @@ class Playwright extends Helper {
|
|
|
2540
2602
|
* I.saveElementScreenshot(`#submit`,'debug.png');
|
|
2541
2603
|
* ```
|
|
2542
2604
|
*
|
|
2543
|
-
* @param {
|
|
2605
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2544
2606
|
* @param {string} fileName file name to save.
|
|
2545
2607
|
*
|
|
2546
2608
|
*
|
|
@@ -2590,6 +2652,53 @@ class Playwright extends Helper {
|
|
|
2590
2652
|
return this.page.screenshot({ path: outputFile, fullPage: fullPageOption, type: 'png' });
|
|
2591
2653
|
}
|
|
2592
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
|
+
|
|
2593
2702
|
async _failed(test) {
|
|
2594
2703
|
await this._withinEnd();
|
|
2595
2704
|
|
|
@@ -2602,7 +2711,7 @@ class Playwright extends Helper {
|
|
|
2602
2711
|
}
|
|
2603
2712
|
|
|
2604
2713
|
if (this.options.trace) {
|
|
2605
|
-
const path = `${global.output_dir}/trace/${clearString(test.title)
|
|
2714
|
+
const path = `${`${global.output_dir}/trace/${clearString(test.title)}`.slice(0, 251)}.zip`;
|
|
2606
2715
|
await this.browserContext.tracing.stop({ path });
|
|
2607
2716
|
test.artifacts.trace = path;
|
|
2608
2717
|
}
|
|
@@ -2647,7 +2756,7 @@ class Playwright extends Helper {
|
|
|
2647
2756
|
* Waits for element to become enabled (by default waits for 1sec).
|
|
2648
2757
|
* Element can be located by CSS or XPath.
|
|
2649
2758
|
*
|
|
2650
|
-
* @param {
|
|
2759
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2651
2760
|
* @param {number} [sec=1] (optional) time in seconds to wait, 1 by default.
|
|
2652
2761
|
*/
|
|
2653
2762
|
async waitForEnabled(locator, sec) {
|
|
@@ -2680,7 +2789,7 @@ class Playwright extends Helper {
|
|
|
2680
2789
|
* I.waitForValue('//input', "GoodValue");
|
|
2681
2790
|
* ```
|
|
2682
2791
|
*
|
|
2683
|
-
* @param {
|
|
2792
|
+
* @param {string | object} field input field.
|
|
2684
2793
|
* @param {string }value expected value.
|
|
2685
2794
|
* @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
2686
2795
|
*
|
|
@@ -2716,7 +2825,7 @@ class Playwright extends Helper {
|
|
|
2716
2825
|
* I.waitNumberOfVisibleElements('a', 3);
|
|
2717
2826
|
* ```
|
|
2718
2827
|
*
|
|
2719
|
-
* @param {
|
|
2828
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2720
2829
|
* @param {number} num number of elements.
|
|
2721
2830
|
* @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
2722
2831
|
*
|
|
@@ -2757,7 +2866,7 @@ class Playwright extends Helper {
|
|
|
2757
2866
|
* I.waitForClickable('.btn.continue', 5); // wait for 5 secs
|
|
2758
2867
|
* ```
|
|
2759
2868
|
*
|
|
2760
|
-
* @param {
|
|
2869
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2761
2870
|
* @param {number} [sec] (optional, `1` by default) time in seconds to wait
|
|
2762
2871
|
*/
|
|
2763
2872
|
async waitForClickable(locator, waitTimeout) {
|
|
@@ -2774,7 +2883,7 @@ class Playwright extends Helper {
|
|
|
2774
2883
|
* I.waitForElement('.btn.continue', 5); // wait for 5 secs
|
|
2775
2884
|
* ```
|
|
2776
2885
|
*
|
|
2777
|
-
* @param {
|
|
2886
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2778
2887
|
* @param {number} [sec] (optional, `1` by default) time in seconds to wait
|
|
2779
2888
|
*
|
|
2780
2889
|
*/
|
|
@@ -2797,7 +2906,7 @@ class Playwright extends Helper {
|
|
|
2797
2906
|
* I.waitForVisible('#popup');
|
|
2798
2907
|
* ```
|
|
2799
2908
|
*
|
|
2800
|
-
* @param {
|
|
2909
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2801
2910
|
* @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
2802
2911
|
*
|
|
2803
2912
|
*
|
|
@@ -2821,7 +2930,7 @@ class Playwright extends Helper {
|
|
|
2821
2930
|
* I.waitForInvisible('#popup');
|
|
2822
2931
|
* ```
|
|
2823
2932
|
*
|
|
2824
|
-
* @param {
|
|
2933
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2825
2934
|
* @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
2826
2935
|
*/
|
|
2827
2936
|
async waitForInvisible(locator, sec) {
|
|
@@ -2842,7 +2951,7 @@ class Playwright extends Helper {
|
|
|
2842
2951
|
* I.waitToHide('#popup');
|
|
2843
2952
|
* ```
|
|
2844
2953
|
*
|
|
2845
|
-
* @param {
|
|
2954
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
2846
2955
|
* @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
2847
2956
|
*/
|
|
2848
2957
|
async waitToHide(locator, sec) {
|
|
@@ -2931,7 +3040,7 @@ class Playwright extends Helper {
|
|
|
2931
3040
|
*
|
|
2932
3041
|
* @param {string }text to wait for.
|
|
2933
3042
|
* @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
2934
|
-
* @param {
|
|
3043
|
+
* @param {string | object} [context] (optional) element located by CSS|XPath|strict locator.
|
|
2935
3044
|
*/
|
|
2936
3045
|
async waitForText(text, sec = null, context = null) {
|
|
2937
3046
|
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
|
|
@@ -3001,7 +3110,7 @@ class Playwright extends Helper {
|
|
|
3001
3110
|
* I.switchTo(); // switch back to main page
|
|
3002
3111
|
* ```
|
|
3003
3112
|
*
|
|
3004
|
-
* @param {?
|
|
3113
|
+
* @param {?string | object} [locator=null] (optional, `null` by default) element located by CSS|XPath|strict locator.
|
|
3005
3114
|
*/
|
|
3006
3115
|
async switchTo(locator) {
|
|
3007
3116
|
if (Number.isInteger(locator)) {
|
|
@@ -3106,7 +3215,7 @@ class Playwright extends Helper {
|
|
|
3106
3215
|
* I.waitForDetached('#popup');
|
|
3107
3216
|
* ```
|
|
3108
3217
|
*
|
|
3109
|
-
* @param {
|
|
3218
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
3110
3219
|
* @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
|
|
3111
3220
|
*/
|
|
3112
3221
|
async waitForDetached(locator, sec) {
|
|
@@ -3176,7 +3285,7 @@ class Playwright extends Helper {
|
|
|
3176
3285
|
* const width = await I.grabElementBoundingRect('h3', 'width');
|
|
3177
3286
|
* // width == 527
|
|
3178
3287
|
* ```
|
|
3179
|
-
* @param {
|
|
3288
|
+
* @param {string | object} locator element located by CSS|XPath|strict locator.
|
|
3180
3289
|
* @param {string=} elementSize x, y, width or height of the given element.
|
|
3181
3290
|
* @returns {Promise<DOMRect>|Promise<number>} Element bounding rectangle
|
|
3182
3291
|
*
|
|
@@ -3363,8 +3472,7 @@ async function findCheckable(locator, context) {
|
|
|
3363
3472
|
async function proceedIsChecked(assertType, option) {
|
|
3364
3473
|
let els = await findCheckable.call(this, option);
|
|
3365
3474
|
assertElementExists(els, option, 'Checkable');
|
|
3366
|
-
els = await Promise.all(els.map(el => el.
|
|
3367
|
-
els = await Promise.all(els.map(el => el.jsonValue()));
|
|
3475
|
+
els = await Promise.all(els.map(el => el.isChecked()));
|
|
3368
3476
|
const selected = els.reduce((prev, cur) => prev || cur);
|
|
3369
3477
|
return truth(`checkable ${option}`, 'to be checked')[assertType](selected);
|
|
3370
3478
|
}
|
|
@@ -3392,36 +3500,6 @@ async function findFields(locator) {
|
|
|
3392
3500
|
return this._locate({ css: locator });
|
|
3393
3501
|
}
|
|
3394
3502
|
|
|
3395
|
-
async function proceedDragAndDrop(sourceLocator, destinationLocator) {
|
|
3396
|
-
// modern drag and drop in Playwright
|
|
3397
|
-
if (this.page.dragAndDrop) {
|
|
3398
|
-
const source = new Locator(sourceLocator);
|
|
3399
|
-
const dest = new Locator(destinationLocator);
|
|
3400
|
-
if (source.isBasic() && dest.isBasic()) {
|
|
3401
|
-
return this.page.dragAndDrop(source.simplify(), dest.simplify());
|
|
3402
|
-
}
|
|
3403
|
-
}
|
|
3404
|
-
|
|
3405
|
-
const src = await this._locate(sourceLocator);
|
|
3406
|
-
assertElementExists(src, sourceLocator, 'Source Element');
|
|
3407
|
-
|
|
3408
|
-
const dst = await this._locate(destinationLocator);
|
|
3409
|
-
assertElementExists(dst, destinationLocator, 'Destination Element');
|
|
3410
|
-
|
|
3411
|
-
// Note: Using clickablePoint private api becaues the .BoundingBox does not take into account iframe offsets!
|
|
3412
|
-
const dragSource = await clickablePoint(src[0]);
|
|
3413
|
-
const dragDestination = await clickablePoint(dst[0]);
|
|
3414
|
-
|
|
3415
|
-
// Drag start point
|
|
3416
|
-
await this.page.mouse.move(dragSource.x, dragSource.y, { steps: 5 });
|
|
3417
|
-
await this.page.mouse.down();
|
|
3418
|
-
|
|
3419
|
-
// Drag destination
|
|
3420
|
-
await this.page.mouse.move(dragDestination.x, dragDestination.y, { steps: 5 });
|
|
3421
|
-
await this.page.mouse.up();
|
|
3422
|
-
await this._waitForAction();
|
|
3423
|
-
}
|
|
3424
|
-
|
|
3425
3503
|
async function proceedSeeInField(assertType, field, value) {
|
|
3426
3504
|
const els = await findFields.call(this, field);
|
|
3427
3505
|
assertElementExists(els, field, 'Field');
|
|
@@ -3448,14 +3526,15 @@ async function proceedSeeInField(assertType, field, value) {
|
|
|
3448
3526
|
};
|
|
3449
3527
|
|
|
3450
3528
|
if (tag === 'SELECT') {
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
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);
|
|
3455
3535
|
}
|
|
3456
3536
|
|
|
3457
|
-
|
|
3458
|
-
return proceedMultiple(options);
|
|
3537
|
+
return el.inputValue();
|
|
3459
3538
|
}
|
|
3460
3539
|
|
|
3461
3540
|
if (tag === 'INPUT') {
|
|
@@ -3471,7 +3550,8 @@ async function proceedSeeInField(assertType, field, value) {
|
|
|
3471
3550
|
}
|
|
3472
3551
|
return proceedMultiple(els[0]);
|
|
3473
3552
|
}
|
|
3474
|
-
|
|
3553
|
+
|
|
3554
|
+
const fieldVal = await el.inputValue();
|
|
3475
3555
|
return stringIncludes(`fields by ${field}`)[assertType](value, fieldVal);
|
|
3476
3556
|
}
|
|
3477
3557
|
|
|
@@ -3502,10 +3582,10 @@ async function filterFieldsBySelectionState(elements, state) {
|
|
|
3502
3582
|
}
|
|
3503
3583
|
|
|
3504
3584
|
async function elementSelected(element) {
|
|
3505
|
-
const type = await element.getProperty('type').then(el => el.jsonValue());
|
|
3585
|
+
const type = await element.getProperty('type').then(el => !!el && el.jsonValue());
|
|
3506
3586
|
|
|
3507
3587
|
if (type === 'checkbox' || type === 'radio') {
|
|
3508
|
-
return element.
|
|
3588
|
+
return element.isChecked();
|
|
3509
3589
|
}
|
|
3510
3590
|
return element.getProperty('selected').then(el => el.jsonValue());
|
|
3511
3591
|
}
|
|
@@ -3553,12 +3633,18 @@ async function targetCreatedHandler(page) {
|
|
|
3553
3633
|
});
|
|
3554
3634
|
});
|
|
3555
3635
|
page.on('console', (msg) => {
|
|
3556
|
-
|
|
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
|
+
}
|
|
3557
3639
|
consoleLogStore.add(msg);
|
|
3558
3640
|
});
|
|
3559
3641
|
|
|
3560
3642
|
if (this.options.windowSize && this.options.windowSize.indexOf('x') > 0 && this._getType() === 'Browser') {
|
|
3561
|
-
|
|
3643
|
+
try {
|
|
3644
|
+
await page.setViewportSize(parseWindowSize(this.options.windowSize));
|
|
3645
|
+
} catch (err) {
|
|
3646
|
+
// target can be already closed, ignoring...
|
|
3647
|
+
}
|
|
3562
3648
|
}
|
|
3563
3649
|
}
|
|
3564
3650
|
|
|
@@ -3648,3 +3734,37 @@ async function clickablePoint(el) {
|
|
|
3648
3734
|
} = rect;
|
|
3649
3735
|
return { x: x + width / 2, y: y + height / 2 };
|
|
3650
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
|
+
}
|