codeceptjs 4.0.0-beta.2 → 4.0.0-beta.4

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.
Files changed (152) hide show
  1. package/README.md +2 -2
  2. package/bin/codecept.js +84 -81
  3. package/lib/actor.js +13 -13
  4. package/lib/ai.js +10 -13
  5. package/lib/assert/empty.js +20 -21
  6. package/lib/assert/equal.js +37 -39
  7. package/lib/assert/error.js +14 -14
  8. package/lib/assert/include.js +46 -47
  9. package/lib/assert/throws.js +13 -11
  10. package/lib/assert/truth.js +19 -22
  11. package/lib/assert.js +4 -2
  12. package/lib/cli.js +56 -49
  13. package/lib/codecept.js +145 -155
  14. package/lib/colorUtils.js +3 -3
  15. package/lib/command/configMigrate.js +58 -52
  16. package/lib/command/definitions.js +88 -89
  17. package/lib/command/dryRun.js +79 -81
  18. package/lib/command/generate.js +197 -188
  19. package/lib/command/gherkin/init.js +27 -16
  20. package/lib/command/gherkin/snippets.js +21 -21
  21. package/lib/command/gherkin/steps.js +8 -8
  22. package/lib/command/info.js +40 -38
  23. package/lib/command/init.js +290 -288
  24. package/lib/command/interactive.js +32 -32
  25. package/lib/command/list.js +26 -26
  26. package/lib/command/run-multiple/chunk.js +5 -5
  27. package/lib/command/run-multiple/collection.js +3 -3
  28. package/lib/command/run-multiple/run.js +6 -2
  29. package/lib/command/run-multiple.js +113 -93
  30. package/lib/command/run-rerun.js +20 -25
  31. package/lib/command/run-workers.js +64 -66
  32. package/lib/command/run.js +26 -29
  33. package/lib/command/utils.js +80 -65
  34. package/lib/command/workers/runTests.js +11 -12
  35. package/lib/config.js +10 -9
  36. package/lib/container.js +40 -48
  37. package/lib/data/context.js +60 -59
  38. package/lib/data/dataScenarioConfig.js +47 -47
  39. package/lib/data/dataTableArgument.js +29 -29
  40. package/lib/data/table.js +26 -20
  41. package/lib/event.js +163 -167
  42. package/lib/heal.js +14 -18
  43. package/lib/helper/AI.js +130 -41
  44. package/lib/helper/ApiDataFactory.js +74 -70
  45. package/lib/helper/Appium.js +416 -388
  46. package/lib/helper/ExpectHelper.js +40 -48
  47. package/lib/helper/FileSystem.js +80 -79
  48. package/lib/helper/GraphQL.js +44 -43
  49. package/lib/helper/GraphQLDataFactory.js +51 -51
  50. package/lib/helper/JSONResponse.js +65 -62
  51. package/lib/helper/Mochawesome.js +28 -28
  52. package/lib/helper/Nightmare.js +664 -571
  53. package/lib/helper/Playwright.js +1367 -1222
  54. package/lib/helper/Protractor.js +663 -635
  55. package/lib/helper/Puppeteer.js +1232 -1132
  56. package/lib/helper/REST.js +183 -68
  57. package/lib/helper/SoftExpectHelper.js +2 -2
  58. package/lib/helper/TestCafe.js +490 -486
  59. package/lib/helper/WebDriver.js +1246 -1297
  60. package/lib/helper/clientscripts/PollyWebDriverExt.js +1 -1
  61. package/lib/helper/errors/ConnectionRefused.js +1 -1
  62. package/lib/helper/errors/ElementAssertion.js +2 -2
  63. package/lib/helper/errors/ElementNotFound.js +2 -2
  64. package/lib/helper/errors/RemoteBrowserConnectionRefused.js +1 -1
  65. package/lib/helper/extras/Console.js +1 -1
  66. package/lib/helper/extras/PlaywrightPropEngine.js +4 -4
  67. package/lib/helper/extras/PlaywrightReactVueLocator.js +1 -1
  68. package/lib/helper/extras/PlaywrightRestartOpts.js +21 -18
  69. package/lib/helper/extras/Popup.js +1 -1
  70. package/lib/helper/extras/React.js +3 -3
  71. package/lib/helper/network/actions.js +14 -7
  72. package/lib/helper/network/utils.js +4 -3
  73. package/lib/helper/scripts/blurElement.js +1 -1
  74. package/lib/helper/scripts/focusElement.js +1 -1
  75. package/lib/helper/scripts/highlightElement.js +1 -1
  76. package/lib/helper/scripts/isElementClickable.js +1 -1
  77. package/lib/helper/testcafe/testControllerHolder.js +1 -1
  78. package/lib/helper/testcafe/testcafe-utils.js +7 -8
  79. package/lib/helper.js +1 -3
  80. package/lib/history.js +6 -5
  81. package/lib/hooks.js +6 -6
  82. package/lib/html.js +7 -7
  83. package/lib/index.js +25 -41
  84. package/lib/interfaces/bdd.js +47 -64
  85. package/lib/interfaces/featureConfig.js +19 -19
  86. package/lib/interfaces/gherkin.js +124 -118
  87. package/lib/interfaces/scenarioConfig.js +29 -29
  88. package/lib/listener/artifacts.js +9 -9
  89. package/lib/listener/config.js +24 -24
  90. package/lib/listener/exit.js +12 -12
  91. package/lib/listener/helpers.js +42 -42
  92. package/lib/listener/mocha.js +11 -11
  93. package/lib/listener/retry.js +32 -30
  94. package/lib/listener/steps.js +50 -53
  95. package/lib/listener/timeout.js +54 -54
  96. package/lib/locator.js +7 -11
  97. package/lib/mochaFactory.js +18 -15
  98. package/lib/output.js +19 -15
  99. package/lib/parser.js +15 -12
  100. package/lib/pause.js +45 -38
  101. package/lib/plugin/allure.js +15 -15
  102. package/lib/plugin/autoDelay.js +29 -37
  103. package/lib/plugin/autoLogin.js +70 -65
  104. package/lib/plugin/commentStep.js +18 -18
  105. package/lib/plugin/coverage.js +112 -67
  106. package/lib/plugin/customLocator.js +21 -20
  107. package/lib/plugin/debugErrors.js +24 -24
  108. package/lib/plugin/eachElement.js +38 -38
  109. package/lib/plugin/fakerTransform.js +6 -6
  110. package/lib/plugin/heal.js +67 -108
  111. package/lib/plugin/pauseOnFail.js +11 -11
  112. package/lib/plugin/retryFailedStep.js +32 -39
  113. package/lib/plugin/retryTo.js +46 -40
  114. package/lib/plugin/screenshotOnFail.js +109 -87
  115. package/lib/plugin/selenoid.js +131 -118
  116. package/lib/plugin/standardActingHelpers.js +2 -8
  117. package/lib/plugin/stepByStepReport.js +110 -91
  118. package/lib/plugin/stepTimeout.js +24 -23
  119. package/lib/plugin/subtitles.js +34 -35
  120. package/lib/plugin/tryTo.js +40 -30
  121. package/lib/plugin/wdio.js +78 -75
  122. package/lib/recorder.js +14 -17
  123. package/lib/rerun.js +11 -10
  124. package/lib/scenario.js +25 -23
  125. package/lib/secret.js +4 -3
  126. package/lib/session.js +10 -10
  127. package/lib/step.js +12 -9
  128. package/lib/store.js +2 -3
  129. package/lib/transform.js +1 -1
  130. package/lib/translation.js +7 -8
  131. package/lib/ui.js +12 -14
  132. package/lib/utils.js +70 -72
  133. package/lib/within.js +10 -10
  134. package/lib/workerStorage.js +27 -25
  135. package/lib/workers.js +29 -33
  136. package/package.json +67 -68
  137. package/translations/de-DE.js +2 -1
  138. package/translations/fr-FR.js +2 -2
  139. package/translations/index.js +9 -13
  140. package/translations/it-IT.js +1 -1
  141. package/translations/ja-JP.js +1 -1
  142. package/translations/pl-PL.js +1 -1
  143. package/translations/pt-BR.js +1 -1
  144. package/translations/ru-RU.js +1 -1
  145. package/translations/zh-CN.js +1 -1
  146. package/translations/zh-TW.js +1 -1
  147. package/typings/index.d.ts +423 -65
  148. package/typings/promiseBasedTypes.d.ts +41 -172
  149. package/typings/types.d.ts +43 -178
  150. package/lib/dirname.js +0 -5
  151. package/lib/helper/Expect.js +0 -425
  152. package/lib/helper/MockServer.js +0 -223
@@ -1,17 +1,18 @@
1
- import path from 'path';
2
- import fs from 'fs';
3
- import Helper from '@codeceptjs/helper';
4
- import { v4 as uuidv4 } from 'uuid';
5
- import assert from 'assert';
6
- import promiseRetry from 'promise-retry';
7
- import Locator from '../locator.js';
8
- import recorder from '../recorder.js';
9
- import { includes as stringIncludes } from '../assert/include.js';
10
- import { urlEquals, equals } from '../assert/equal.js';
11
- import { empty } from '../assert/empty.js';
12
- import { truth } from '../assert/truth.js';
13
-
14
- import {
1
+ const path = require('path')
2
+ const fs = require('fs')
3
+
4
+ const Helper = require('@codeceptjs/helper')
5
+ const { v4: uuidv4 } = require('uuid')
6
+ const assert = require('assert')
7
+ const promiseRetry = require('promise-retry')
8
+ const Locator = require('../locator')
9
+ const recorder = require('../recorder')
10
+ const stringIncludes = require('../assert/include').includes
11
+ const { urlEquals } = require('../assert/equal')
12
+ const { equals } = require('../assert/equal')
13
+ const { empty } = require('../assert/empty')
14
+ const { truth } = require('../assert/truth')
15
+ const {
15
16
  xpathLocator,
16
17
  ucfirst,
17
18
  fileExists,
@@ -23,40 +24,44 @@ import {
23
24
  clearString,
24
25
  requireWithFallback,
25
26
  normalizeSpacesInString,
26
- } from '../utils.js';
27
-
28
- import { isColorProperty, convertColorToRGBA } from '../colorUtils.js';
29
- import ElementNotFound from './errors/ElementNotFound.js';
30
- import RemoteBrowserConnectionRefused from './errors/RemoteBrowserConnectionRefused.js';
31
- import Popup from './extras/Popup.js';
32
- import Console from './extras/Console.js';
33
- import { findByPlaywrightLocator, findReact, findVue } from './extras/PlaywrightReactVueLocator.js';
34
-
35
- import {
36
- setRestartStrategy, restartsSession, restartsContext, restartsBrowser,
37
- } from './extras/PlaywrightRestartOpts.js';
38
- import { createValueEngine, createDisabledEngine } from './extras/PlaywrightPropEngine.js';
39
-
40
- import {
27
+ } = require('../utils')
28
+ const { isColorProperty, convertColorToRGBA } = require('../colorUtils')
29
+ const ElementNotFound = require('./errors/ElementNotFound')
30
+ const RemoteBrowserConnectionRefused = require('./errors/RemoteBrowserConnectionRefused')
31
+ const Popup = require('./extras/Popup')
32
+ const Console = require('./extras/Console')
33
+ const { findReact, findVue, findByPlaywrightLocator } = require('./extras/PlaywrightReactVueLocator')
34
+
35
+ let playwright
36
+ let perfTiming
37
+ let defaultSelectorEnginesInitialized = false
38
+
39
+ const popupStore = new Popup()
40
+ const consoleLogStore = new Console()
41
+ const availableBrowsers = ['chromium', 'webkit', 'firefox', 'electron']
42
+
43
+ const {
44
+ setRestartStrategy,
45
+ restartsSession,
46
+ restartsContext,
47
+ restartsBrowser,
48
+ } = require('./extras/PlaywrightRestartOpts')
49
+ const { createValueEngine, createDisabledEngine } = require('./extras/PlaywrightPropEngine')
50
+ const {
41
51
  seeElementError,
42
52
  dontSeeElementError,
43
53
  dontSeeElementInDOMError,
44
54
  seeElementInDOMError,
45
- } from './errors/ElementAssertion.js';
46
-
47
- import {
48
- dontSeeTraffic, seeTraffic, grabRecordedNetworkTraffics, stopRecordingTraffic, flushNetworkTraffics,
49
- } from './network/actions.js';
50
-
51
- let playwright;
52
- let perfTiming;
53
- let defaultSelectorEnginesInitialized = false;
54
-
55
- const popupStore = new Popup();
56
- const consoleLogStore = new Console();
57
- const availableBrowsers = ['chromium', 'webkit', 'firefox', 'electron'];
55
+ } = require('./errors/ElementAssertion')
56
+ const {
57
+ dontSeeTraffic,
58
+ seeTraffic,
59
+ grabRecordedNetworkTraffics,
60
+ stopRecordingTraffic,
61
+ flushNetworkTraffics,
62
+ } = require('./network/actions')
58
63
 
59
- const pathSeparator = path.sep;
64
+ const pathSeparator = path.sep
60
65
 
61
66
  /**
62
67
  * ## Configuration
@@ -105,7 +110,7 @@ const pathSeparator = path.sep;
105
110
  * @prop {object} [recordHar] - record HAR and will be saved to `output/har`. See more of [HAR options](https://playwright.dev/docs/api/class-browser#browser-new-context-option-record-har).
106
111
  * @prop {string} [testIdAttribute=data-testid] - locate elements based on the testIdAttribute. See more of [locate by test id](https://playwright.dev/docs/locators#locate-by-test-id).
107
112
  */
108
- const config = {};
113
+ const config = {}
109
114
 
110
115
  /**
111
116
  * Uses [Playwright](https://github.com/microsoft/playwright) library to run tests inside:
@@ -327,34 +332,34 @@ const config = {};
327
332
  */
328
333
  class Playwright extends Helper {
329
334
  constructor(config) {
330
- super(config);
335
+ super(config)
331
336
 
332
- playwright = requireWithFallback('playwright', 'playwright-core');
337
+ playwright = requireWithFallback('playwright', 'playwright-core')
333
338
 
334
339
  // set defaults
335
- this.isRemoteBrowser = false;
336
- this.isRunning = false;
337
- this.isAuthenticated = false;
338
- this.sessionPages = {};
339
- this.activeSessionName = '';
340
- this.isElectron = false;
341
- this.isCDPConnection = false;
342
- this.electronSessions = [];
343
- this.storageState = null;
340
+ this.isRemoteBrowser = false
341
+ this.isRunning = false
342
+ this.isAuthenticated = false
343
+ this.sessionPages = {}
344
+ this.activeSessionName = ''
345
+ this.isElectron = false
346
+ this.isCDPConnection = false
347
+ this.electronSessions = []
348
+ this.storageState = null
344
349
 
345
350
  // for network stuff
346
- this.requests = [];
347
- this.recording = false;
348
- this.recordedAtLeastOnce = false;
351
+ this.requests = []
352
+ this.recording = false
353
+ this.recordedAtLeastOnce = false
349
354
 
350
355
  // for websocket messages
351
- this.webSocketMessages = [];
352
- this.recordingWebSocketMessages = false;
353
- this.recordedWebSocketMessagesAtLeastOnce = false;
354
- this.cdpSession = null;
356
+ this.webSocketMessages = []
357
+ this.recordingWebSocketMessages = false
358
+ this.recordedWebSocketMessagesAtLeastOnce = false
359
+ this.cdpSession = null
355
360
 
356
361
  // override defaults with config
357
- this._setConfig(config);
362
+ this._setConfig(config)
358
363
  }
359
364
 
360
365
  _validateConfig(config) {
@@ -381,54 +386,65 @@ class Playwright extends Helper {
381
386
  use: { actionTimeout: 0 },
382
387
  ignoreHTTPSErrors: false, // Adding it here o that context can be set up to ignore the SSL errors,
383
388
  highlightElement: false,
384
- };
389
+ }
385
390
 
386
- process.env.testIdAttribute = 'data-testid';
387
- config = Object.assign(defaults, config);
391
+ process.env.testIdAttribute = 'data-testid'
392
+ config = Object.assign(defaults, config)
388
393
 
389
394
  if (availableBrowsers.indexOf(config.browser) < 0) {
390
- throw new Error(`Invalid config. Can't use browser "${config.browser}". Accepted values: ${availableBrowsers.join(', ')}`);
395
+ throw new Error(
396
+ `Invalid config. Can't use browser "${config.browser}". Accepted values: ${availableBrowsers.join(', ')}`,
397
+ )
391
398
  }
392
399
 
393
- return config;
400
+ return config
394
401
  }
395
402
 
396
403
  _getOptionsForBrowser(config) {
397
404
  if (config[config.browser]) {
398
405
  if (config[config.browser].browserWSEndpoint && config[config.browser].browserWSEndpoint.wsEndpoint) {
399
- config[config.browser].browserWSEndpoint = config[config.browser].browserWSEndpoint.wsEndpoint;
406
+ config[config.browser].browserWSEndpoint = config[config.browser].browserWSEndpoint.wsEndpoint
400
407
  }
401
408
  return {
402
409
  ...config[config.browser],
403
410
  wsEndpoint: config[config.browser].browserWSEndpoint,
404
- };
411
+ }
405
412
  }
406
- return {};
413
+ return {}
407
414
  }
408
415
 
409
416
  _setConfig(config) {
410
- this.options = this._validateConfig(config);
411
- setRestartStrategy(this.options);
417
+ this.options = this._validateConfig(config)
418
+ setRestartStrategy(this.options)
412
419
  this.playwrightOptions = {
413
420
  headless: !this.options.show,
414
421
  ...this._getOptionsForBrowser(config),
415
- };
422
+ }
416
423
 
417
424
  if (this.options.channel && this.options.browser === 'chromium') {
418
- this.playwrightOptions.channel = this.options.channel;
425
+ this.playwrightOptions.channel = this.options.channel
419
426
  }
420
427
 
421
428
  if (this.options.video) {
422
- this.options.recordVideo = { size: parseWindowSize(this.options.windowSize) };
429
+ // set the video resolution with window size
430
+ let size = parseWindowSize(this.options.windowSize)
431
+
432
+ // if the video resolution is passed, set the record resoultion with that resolution
433
+ if (this.options.recordVideo && this.options.recordVideo.size) {
434
+ size = parseWindowSize(this.options.recordVideo.size)
435
+ }
436
+ this.options.recordVideo = { size }
423
437
  }
424
438
  if (this.options.recordVideo && !this.options.recordVideo.dir) {
425
- this.options.recordVideo.dir = `${global.output_dir}/videos/`;
439
+ this.options.recordVideo.dir = `${global.output_dir}/videos/`
426
440
  }
427
- this.isRemoteBrowser = !!this.playwrightOptions.browserWSEndpoint;
428
- this.isElectron = this.options.browser === 'electron';
429
- this.userDataDir = this.playwrightOptions.userDataDir ? `${this.playwrightOptions.userDataDir}_${Date.now().toString()}` : undefined;
430
- this.isCDPConnection = this.playwrightOptions.cdpConnection;
431
- popupStore.defaultAction = this.options.defaultPopupAction;
441
+ this.isRemoteBrowser = !!this.playwrightOptions.browserWSEndpoint
442
+ this.isElectron = this.options.browser === 'electron'
443
+ this.userDataDir = this.playwrightOptions.userDataDir
444
+ ? `${this.playwrightOptions.userDataDir}_${Date.now().toString()}`
445
+ : undefined
446
+ this.isCDPConnection = this.playwrightOptions.cdpConnection
447
+ popupStore.defaultAction = this.options.defaultPopupAction
432
448
  }
433
449
 
434
450
  static _config() {
@@ -451,216 +467,222 @@ class Playwright extends Helper {
451
467
  type: 'confirm',
452
468
  when: (answers) => answers.Playwright_browser !== 'electron',
453
469
  },
454
- ];
470
+ ]
455
471
  }
456
472
 
457
473
  static _checkRequirements() {
458
474
  try {
459
- requireWithFallback('playwright', 'playwright-core');
475
+ requireWithFallback('playwright', 'playwright-core')
460
476
  } catch (e) {
461
- return ['playwright@^1.18'];
477
+ return ['playwright@^1.18']
462
478
  }
463
479
  }
464
480
 
465
481
  async _init() {
466
482
  // register an internal selector engine for reading value property of elements in a selector
467
- if (defaultSelectorEnginesInitialized) return;
468
- defaultSelectorEnginesInitialized = true;
483
+ if (defaultSelectorEnginesInitialized) return
484
+ defaultSelectorEnginesInitialized = true
469
485
  try {
470
- await playwright.selectors.register('__value', createValueEngine);
471
- await playwright.selectors.register('__disabled', createDisabledEngine);
472
- if (process.env.testIdAttribute) await playwright.selectors.setTestIdAttribute(process.env.testIdAttribute);
486
+ await playwright.selectors.register('__value', createValueEngine)
487
+ await playwright.selectors.register('__disabled', createDisabledEngine)
488
+ if (process.env.testIdAttribute) await playwright.selectors.setTestIdAttribute(process.env.testIdAttribute)
473
489
  } catch (e) {
474
- console.warn(e);
490
+ console.warn(e)
475
491
  }
476
492
  }
477
493
 
478
494
  _beforeSuite() {
479
495
  if ((restartsSession() || restartsContext()) && !this.options.manualStart && !this.isRunning) {
480
- this.debugSection('Session', 'Starting singleton browser session');
481
- return this._startBrowser();
496
+ this.debugSection('Session', 'Starting singleton browser session')
497
+ return this._startBrowser()
482
498
  }
483
499
  }
484
500
 
485
501
  async _before(test) {
486
- this.currentRunningTest = test;
502
+ this.currentRunningTest = test
487
503
  recorder.retry({
488
504
  retries: process.env.FAILED_STEP_RETRIES || 3,
489
- when: err => {
490
- if (!err || typeof (err.message) !== 'string') {
491
- return false;
505
+ when: (err) => {
506
+ if (!err || typeof err.message !== 'string') {
507
+ return false
492
508
  }
493
509
  // ignore context errors
494
- return err.message.includes('context');
510
+ return err.message.includes('context')
495
511
  },
496
- });
512
+ })
497
513
 
498
- if (restartsBrowser() && !this.options.manualStart) await this._startBrowser();
499
- if (!this.isRunning && !this.options.manualStart) await this._startBrowser();
514
+ if (restartsBrowser() && !this.options.manualStart) await this._startBrowser()
515
+ if (!this.isRunning && !this.options.manualStart) await this._startBrowser()
500
516
 
501
- this.isAuthenticated = false;
517
+ this.isAuthenticated = false
502
518
  if (this.isElectron) {
503
- this.browserContext = this.browser.context();
519
+ this.browserContext = this.browser.context()
504
520
  } else if (this.playwrightOptions.userDataDir) {
505
- this.browserContext = this.browser;
521
+ this.browserContext = this.browser
506
522
  } else {
507
523
  const contextOptions = {
508
524
  ignoreHTTPSErrors: this.options.ignoreHTTPSErrors,
509
525
  acceptDownloads: true,
510
526
  ...this.options.emulate,
511
- };
527
+ }
512
528
  if (this.options.basicAuth) {
513
- contextOptions.httpCredentials = this.options.basicAuth;
514
- this.isAuthenticated = true;
529
+ contextOptions.httpCredentials = this.options.basicAuth
530
+ this.isAuthenticated = true
515
531
  }
516
- if (this.options.bypassCSP) contextOptions.bypassCSP = this.options.bypassCSP;
517
- if (this.options.recordVideo) contextOptions.recordVideo = this.options.recordVideo;
532
+ if (this.options.bypassCSP) contextOptions.bypassCSP = this.options.bypassCSP
533
+ if (this.options.recordVideo) contextOptions.recordVideo = this.options.recordVideo
518
534
  if (this.options.recordHar) {
519
- const harExt = this.options.recordHar.content && this.options.recordHar.content === 'attach' ? 'zip' : 'har';
520
- const fileName = `${`${global.output_dir}${path.sep}har${path.sep}${uuidv4()}_${clearString(this.currentRunningTest.title)}`.slice(0, 245)}.${harExt}`;
521
- const dir = path.dirname(fileName);
522
- if (!fileExists(dir)) fs.mkdirSync(dir);
523
- this.options.recordHar.path = fileName;
524
- this.currentRunningTest.artifacts.har = fileName;
525
- contextOptions.recordHar = this.options.recordHar;
535
+ const harExt = this.options.recordHar.content && this.options.recordHar.content === 'attach' ? 'zip' : 'har'
536
+ const fileName = `${`${global.output_dir}${path.sep}har${path.sep}${uuidv4()}_${clearString(this.currentRunningTest.title)}`.slice(0, 245)}.${harExt}`
537
+ const dir = path.dirname(fileName)
538
+ if (!fileExists(dir)) fs.mkdirSync(dir)
539
+ this.options.recordHar.path = fileName
540
+ this.currentRunningTest.artifacts.har = fileName
541
+ contextOptions.recordHar = this.options.recordHar
526
542
  }
527
- if (this.storageState) contextOptions.storageState = this.storageState;
528
- if (this.options.userAgent) contextOptions.userAgent = this.options.userAgent;
529
- if (this.options.locale) contextOptions.locale = this.options.locale;
530
- if (this.options.colorScheme) contextOptions.colorScheme = this.options.colorScheme;
531
- this.contextOptions = contextOptions;
543
+ if (this.storageState) contextOptions.storageState = this.storageState
544
+ if (this.options.userAgent) contextOptions.userAgent = this.options.userAgent
545
+ if (this.options.locale) contextOptions.locale = this.options.locale
546
+ if (this.options.colorScheme) contextOptions.colorScheme = this.options.colorScheme
547
+ this.contextOptions = contextOptions
532
548
  if (!this.browserContext || !restartsSession()) {
533
- this.browserContext = await this.browser.newContext(this.contextOptions); // Adding the HTTPSError ignore in the context so that we can ignore those errors
549
+ this.browserContext = await this.browser.newContext(this.contextOptions) // Adding the HTTPSError ignore in the context so that we can ignore those errors
534
550
  }
535
551
  }
536
552
 
537
- let mainPage;
553
+ let mainPage
538
554
  if (this.isElectron) {
539
- mainPage = await this.browser.firstWindow();
555
+ mainPage = await this.browser.firstWindow()
540
556
  } else {
541
557
  try {
542
- const existingPages = await this.browserContext.pages();
543
- mainPage = existingPages[0] || (await this.browserContext.newPage());
558
+ const existingPages = await this.browserContext.pages()
559
+ mainPage = existingPages[0] || (await this.browserContext.newPage())
544
560
  } catch (e) {
545
561
  if (this.playwrightOptions.userDataDir) {
546
- this.browser = await playwright[this.options.browser].launchPersistentContext(this.userDataDir, this.playwrightOptions);
547
- this.browserContext = this.browser;
548
- const existingPages = await this.browserContext.pages();
549
- mainPage = existingPages[0];
562
+ this.browser = await playwright[this.options.browser].launchPersistentContext(
563
+ this.userDataDir,
564
+ this.playwrightOptions,
565
+ )
566
+ this.browserContext = this.browser
567
+ const existingPages = await this.browserContext.pages()
568
+ mainPage = existingPages[0]
550
569
  }
551
570
  }
552
571
  }
553
- await targetCreatedHandler.call(this, mainPage);
572
+ await targetCreatedHandler.call(this, mainPage)
554
573
 
555
- await this._setPage(mainPage);
574
+ await this._setPage(mainPage)
556
575
 
557
- if (this.options.trace) await this.browserContext.tracing.start({ screenshots: true, snapshots: true });
576
+ if (this.options.trace) await this.browserContext.tracing.start({ screenshots: true, snapshots: true })
558
577
 
559
- return this.browser;
578
+ return this.browser
560
579
  }
561
580
 
562
581
  async _after() {
563
- if (!this.isRunning) return;
582
+ if (!this.isRunning) return
564
583
 
565
584
  if (this.isElectron) {
566
- this.browser.close();
567
- this.electronSessions.forEach(session => session.close());
568
- return;
585
+ this.browser.close()
586
+ this.electronSessions.forEach((session) => session.close())
587
+ return
569
588
  }
570
589
 
571
590
  if (restartsSession()) {
572
- return refreshContextSession.bind(this)();
591
+ return refreshContextSession.bind(this)()
573
592
  }
574
593
 
575
594
  if (restartsBrowser()) {
576
- this.isRunning = false;
577
- return this._stopBrowser();
595
+ this.isRunning = false
596
+ return this._stopBrowser()
578
597
  }
579
598
 
580
599
  // close other sessions
581
600
  try {
582
601
  if ((await this.browser)._type === 'Browser') {
583
- const contexts = await this.browser.contexts();
584
- const currentContext = contexts[0];
602
+ const contexts = await this.browser.contexts()
603
+ const currentContext = contexts[0]
585
604
  if (currentContext && (this.options.keepCookies || this.options.keepBrowserState)) {
586
- this.storageState = await currentContext.storageState();
605
+ this.storageState = await currentContext.storageState()
587
606
  }
588
607
 
589
- await Promise.all(contexts.map(c => c.close()));
608
+ await Promise.all(contexts.map((c) => c.close()))
590
609
  }
591
610
  } catch (e) {
592
- console.log(e);
611
+ console.log(e)
593
612
  }
594
613
 
595
614
  // await this.closeOtherTabs();
596
- return this.browser;
615
+ return this.browser
597
616
  }
598
617
 
599
618
  _afterSuite() {}
600
619
 
601
620
  async _finishTest() {
602
- if ((restartsSession() || restartsContext()) && this.isRunning) return this._stopBrowser();
621
+ if ((restartsSession() || restartsContext()) && this.isRunning) return this._stopBrowser()
603
622
  }
604
623
 
605
624
  _session() {
606
- const defaultContext = this.browserContext;
625
+ const defaultContext = this.browserContext
607
626
  return {
608
627
  start: async (sessionName = '', config) => {
609
- this.debugSection('New Context', config ? JSON.stringify(config) : 'opened');
610
- this.activeSessionName = sessionName;
628
+ this.debugSection('New Context', config ? JSON.stringify(config) : 'opened')
629
+ this.activeSessionName = sessionName
611
630
 
612
- let browserContext;
613
- let page;
631
+ let browserContext
632
+ let page
614
633
  if (this.isElectron) {
615
- const browser = await playwright._electron.launch(this.playwrightOptions);
616
- this.electronSessions.push(browser);
617
- browserContext = browser.context();
618
- page = await browser.firstWindow();
634
+ const browser = await playwright._electron.launch(this.playwrightOptions)
635
+ this.electronSessions.push(browser)
636
+ browserContext = browser.context()
637
+ page = await browser.firstWindow()
619
638
  } else {
620
639
  try {
621
- browserContext = await this.browser.newContext(Object.assign(this.contextOptions, config));
622
- page = await browserContext.newPage();
640
+ browserContext = await this.browser.newContext(Object.assign(this.contextOptions, config))
641
+ page = await browserContext.newPage()
623
642
  } catch (e) {
624
643
  if (this.playwrightOptions.userDataDir) {
625
- browserContext = await playwright[this.options.browser].launchPersistentContext(`${this.userDataDir}_${this.activeSessionName}`, this.playwrightOptions);
626
- this.browser = browserContext;
627
- page = await browserContext.pages()[0];
644
+ browserContext = await playwright[this.options.browser].launchPersistentContext(
645
+ `${this.userDataDir}_${this.activeSessionName}`,
646
+ this.playwrightOptions,
647
+ )
648
+ this.browser = browserContext
649
+ page = await browserContext.pages()[0]
628
650
  }
629
651
  }
630
652
  }
631
653
 
632
- if (this.options.trace) await browserContext.tracing.start({ screenshots: true, snapshots: true });
633
- await targetCreatedHandler.call(this, page);
634
- await this._setPage(page);
654
+ if (this.options.trace) await browserContext.tracing.start({ screenshots: true, snapshots: true })
655
+ await targetCreatedHandler.call(this, page)
656
+ await this._setPage(page)
635
657
  // Create a new page inside context.
636
- return browserContext;
658
+ return browserContext
637
659
  },
638
660
  stop: async () => {
639
661
  // is closed by _after
640
662
  },
641
663
  loadVars: async (context) => {
642
664
  if (context) {
643
- this.browserContext = context;
644
- const existingPages = await context.pages();
645
- this.sessionPages[this.activeSessionName] = existingPages[0];
646
- return this._setPage(this.sessionPages[this.activeSessionName]);
665
+ this.browserContext = context
666
+ const existingPages = await context.pages()
667
+ this.sessionPages[this.activeSessionName] = existingPages[0]
668
+ return this._setPage(this.sessionPages[this.activeSessionName])
647
669
  }
648
670
  },
649
671
  restoreVars: async (session) => {
650
- this.withinLocator = null;
651
- this.browserContext = defaultContext;
672
+ this.withinLocator = null
673
+ this.browserContext = defaultContext
652
674
 
653
675
  if (!session) {
654
- this.activeSessionName = '';
676
+ this.activeSessionName = ''
655
677
  } else {
656
- this.activeSessionName = session;
678
+ this.activeSessionName = session
657
679
  }
658
- const existingPages = await this.browserContext.pages();
659
- await this._setPage(existingPages[0]);
680
+ const existingPages = await this.browserContext.pages()
681
+ await this._setPage(existingPages[0])
660
682
 
661
- return this._waitForAction();
683
+ return this._waitForAction()
662
684
  },
663
- };
685
+ }
664
686
  }
665
687
 
666
688
  /**
@@ -681,7 +703,7 @@ class Playwright extends Helper {
681
703
  * @param {function} fn async function that executed with Playwright helper as arguments
682
704
  */
683
705
  usePlaywrightTo(description, fn) {
684
- return this._useTo(...arguments);
706
+ return this._useTo(...arguments)
685
707
  }
686
708
 
687
709
  /**
@@ -695,7 +717,7 @@ class Playwright extends Helper {
695
717
  * ```
696
718
  */
697
719
  amAcceptingPopups() {
698
- popupStore.actionType = 'accept';
720
+ popupStore.actionType = 'accept'
699
721
  }
700
722
 
701
723
  /**
@@ -704,7 +726,7 @@ class Playwright extends Helper {
704
726
  * libraries](http://jster.net/category/windows-modals-popups).
705
727
  */
706
728
  acceptPopup() {
707
- popupStore.assertPopupActionType('accept');
729
+ popupStore.assertPopupActionType('accept')
708
730
  }
709
731
 
710
732
  /**
@@ -718,23 +740,23 @@ class Playwright extends Helper {
718
740
  * ```
719
741
  */
720
742
  amCancellingPopups() {
721
- popupStore.actionType = 'cancel';
743
+ popupStore.actionType = 'cancel'
722
744
  }
723
745
 
724
746
  /**
725
747
  * Dismisses the active JavaScript popup, as created by window.alert|window.confirm|window.prompt.
726
748
  */
727
749
  cancelPopup() {
728
- popupStore.assertPopupActionType('cancel');
750
+ popupStore.assertPopupActionType('cancel')
729
751
  }
730
752
 
731
753
  /**
732
754
  * {{> seeInPopup }}
733
755
  */
734
756
  async seeInPopup(text) {
735
- popupStore.assertPopupVisible();
736
- const popupText = await popupStore.popup.message();
737
- stringIncludes('text in popup').assert(text, popupText);
757
+ popupStore.assertPopupVisible()
758
+ const popupText = await popupStore.popup.message()
759
+ stringIncludes('text in popup').assert(text, popupText)
738
760
  }
739
761
 
740
762
  /**
@@ -742,21 +764,21 @@ class Playwright extends Helper {
742
764
  * @param {object} page page to set
743
765
  */
744
766
  async _setPage(page) {
745
- page = await page;
746
- this._addPopupListener(page);
747
- this.page = page;
748
- if (!page) return;
749
- this.browserContext.setDefaultTimeout(0);
750
- page.setDefaultNavigationTimeout(this.options.getPageTimeout);
751
- page.setDefaultTimeout(this.options.timeout);
767
+ page = await page
768
+ this._addPopupListener(page)
769
+ this.page = page
770
+ if (!page) return
771
+ this.browserContext.setDefaultTimeout(0)
772
+ page.setDefaultNavigationTimeout(this.options.getPageTimeout)
773
+ page.setDefaultTimeout(this.options.timeout)
752
774
 
753
775
  page.on('crash', async () => {
754
- console.log('ERROR: Page has crashed, closing page!');
755
- await page.close();
756
- });
757
- this.context = await this.page;
758
- this.contextLocator = null;
759
- await page.bringToFront();
776
+ console.log('ERROR: Page has crashed, closing page!')
777
+ await page.close()
778
+ })
779
+ this.context = await this.page
780
+ this.contextLocator = null
781
+ await page.bringToFront()
760
782
  }
761
783
 
762
784
  /**
@@ -768,33 +790,33 @@ class Playwright extends Helper {
768
790
  */
769
791
  _addPopupListener(page) {
770
792
  if (!page) {
771
- return;
793
+ return
772
794
  }
773
- page.removeAllListeners('dialog');
795
+ page.removeAllListeners('dialog')
774
796
  page.on('dialog', async (dialog) => {
775
- popupStore.popup = dialog;
776
- const action = popupStore.actionType || this.options.defaultPopupAction;
777
- await this._waitForAction();
797
+ popupStore.popup = dialog
798
+ const action = popupStore.actionType || this.options.defaultPopupAction
799
+ await this._waitForAction()
778
800
 
779
801
  switch (action) {
780
802
  case 'accept':
781
- return dialog.accept();
803
+ return dialog.accept()
782
804
 
783
805
  case 'cancel':
784
- return dialog.dismiss();
806
+ return dialog.dismiss()
785
807
 
786
808
  default: {
787
- throw new Error('Unknown popup action type. Only "accept" or "cancel" are accepted');
809
+ throw new Error('Unknown popup action type. Only "accept" or "cancel" are accepted')
788
810
  }
789
811
  }
790
- });
812
+ })
791
813
  }
792
814
 
793
815
  /**
794
816
  * Gets page URL including hash.
795
817
  */
796
818
  async _getPageUrl() {
797
- return this.executeScript(() => window.location.href);
819
+ return this.executeScript(() => window.location.href)
798
820
  }
799
821
 
800
822
  /**
@@ -807,45 +829,48 @@ class Playwright extends Helper {
807
829
  */
808
830
  async grabPopupText() {
809
831
  if (popupStore.popup) {
810
- return popupStore.popup.message();
832
+ return popupStore.popup.message()
811
833
  }
812
- return null;
834
+ return null
813
835
  }
814
836
 
815
837
  async _startBrowser() {
816
838
  if (this.isElectron) {
817
- this.browser = await playwright._electron.launch(this.playwrightOptions);
839
+ this.browser = await playwright._electron.launch(this.playwrightOptions)
818
840
  } else if (this.isRemoteBrowser && this.isCDPConnection) {
819
841
  try {
820
- this.browser = await playwright[this.options.browser].connectOverCDP(this.playwrightOptions);
842
+ this.browser = await playwright[this.options.browser].connectOverCDP(this.playwrightOptions)
821
843
  } catch (err) {
822
844
  if (err.toString().indexOf('ECONNREFUSED')) {
823
- throw new RemoteBrowserConnectionRefused(err);
845
+ throw new RemoteBrowserConnectionRefused(err)
824
846
  }
825
- throw err;
847
+ throw err
826
848
  }
827
849
  } else if (this.isRemoteBrowser) {
828
850
  try {
829
- this.browser = await playwright[this.options.browser].connect(this.playwrightOptions);
851
+ this.browser = await playwright[this.options.browser].connect(this.playwrightOptions)
830
852
  } catch (err) {
831
853
  if (err.toString().indexOf('ECONNREFUSED')) {
832
- throw new RemoteBrowserConnectionRefused(err);
854
+ throw new RemoteBrowserConnectionRefused(err)
833
855
  }
834
- throw err;
856
+ throw err
835
857
  }
836
858
  } else if (this.playwrightOptions.userDataDir) {
837
- this.browser = await playwright[this.options.browser].launchPersistentContext(this.userDataDir, this.playwrightOptions);
859
+ this.browser = await playwright[this.options.browser].launchPersistentContext(
860
+ this.userDataDir,
861
+ this.playwrightOptions,
862
+ )
838
863
  } else {
839
- this.browser = await playwright[this.options.browser].launch(this.playwrightOptions);
864
+ this.browser = await playwright[this.options.browser].launch(this.playwrightOptions)
840
865
  }
841
866
 
842
867
  // works only for Chromium
843
868
  this.browser.on('targetchanged', (target) => {
844
- this.debugSection('Url', target.url());
845
- });
869
+ this.debugSection('Url', target.url())
870
+ })
846
871
 
847
- this.isRunning = true;
848
- return this.browser;
872
+ this.isRunning = true
873
+ return this.browser
849
874
  }
850
875
 
851
876
  /**
@@ -854,72 +879,72 @@ class Playwright extends Helper {
854
879
  * @param {object} [contextOptions] See https://playwright.dev/docs/api/class-browser#browser-new-context
855
880
  */
856
881
  async _createContextPage(contextOptions) {
857
- this.browserContext = await this.browser.newContext(contextOptions);
858
- const page = await this.browserContext.newPage();
859
- targetCreatedHandler.call(this, page);
860
- await this._setPage(page);
882
+ this.browserContext = await this.browser.newContext(contextOptions)
883
+ const page = await this.browserContext.newPage()
884
+ targetCreatedHandler.call(this, page)
885
+ await this._setPage(page)
861
886
  }
862
887
 
863
888
  _getType() {
864
- return this.browser._type;
889
+ return this.browser._type
865
890
  }
866
891
 
867
892
  async _stopBrowser() {
868
- this.withinLocator = null;
869
- await this._setPage(null);
870
- this.context = null;
871
- this.frame = null;
872
- popupStore.clear();
873
- if (this.options.recordHar) await this.browserContext.close();
874
- await this.browser.close();
893
+ this.withinLocator = null
894
+ await this._setPage(null)
895
+ this.context = null
896
+ this.frame = null
897
+ popupStore.clear()
898
+ if (this.options.recordHar) await this.browserContext.close()
899
+ await this.browser.close()
875
900
  }
876
901
 
877
902
  async _evaluateHandeInContext(...args) {
878
- const context = await this._getContext();
879
- return context.evaluateHandle(...args);
903
+ const context = await this._getContext()
904
+ return context.evaluateHandle(...args)
880
905
  }
881
906
 
882
907
  async _withinBegin(locator) {
883
908
  if (this.withinLocator) {
884
- throw new Error('Can\'t start within block inside another within block');
909
+ throw new Error("Can't start within block inside another within block")
885
910
  }
886
911
 
887
- const frame = isFrameLocator(locator);
912
+ const frame = isFrameLocator(locator)
888
913
 
889
914
  if (frame) {
890
915
  if (Array.isArray(frame)) {
891
- await this.switchTo(null);
892
- return frame.reduce((p, frameLocator) => p.then(() => this.switchTo(frameLocator)), Promise.resolve());
916
+ await this.switchTo(null)
917
+ return frame.reduce((p, frameLocator) => p.then(() => this.switchTo(frameLocator)), Promise.resolve())
893
918
  }
894
- await this.switchTo(frame);
895
- this.withinLocator = new Locator(frame);
896
- return;
919
+ await this.switchTo(frame)
920
+ this.withinLocator = new Locator(frame)
921
+ return
897
922
  }
898
923
 
899
- const el = await this._locateElement(locator);
900
- assertElementExists(el, locator);
901
- this.context = el;
902
- this.contextLocator = locator;
924
+ const el = await this._locateElement(locator)
925
+ assertElementExists(el, locator)
926
+ this.context = el
927
+ this.contextLocator = locator
903
928
 
904
- this.withinLocator = new Locator(locator);
929
+ this.withinLocator = new Locator(locator)
905
930
  }
906
931
 
907
932
  async _withinEnd() {
908
- this.withinLocator = null;
909
- this.context = await this.page;
910
- this.contextLocator = null;
911
- this.frame = null;
933
+ this.withinLocator = null
934
+ this.context = await this.page
935
+ this.contextLocator = null
936
+ this.frame = null
912
937
  }
913
938
 
914
939
  _extractDataFromPerformanceTiming(timing, ...dataNames) {
915
- const navigationStart = timing.navigationStart;
940
+ const navigationStart = timing.navigationStart
916
941
 
917
- const extractedData = {};
942
+ const extractedData = {}
918
943
  dataNames.forEach((name) => {
919
- extractedData[name] = timing[name] - navigationStart;
920
- });
944
+ extractedData[name] = timing[name] - navigationStart
945
+ })
921
946
 
922
- return extractedData;
947
+ return extractedData
923
948
  }
924
949
 
925
950
  /**
@@ -927,22 +952,22 @@ class Playwright extends Helper {
927
952
  */
928
953
  async amOnPage(url) {
929
954
  if (this.isElectron) {
930
- throw new Error('Cannot open pages inside an Electron container');
955
+ throw new Error('Cannot open pages inside an Electron container')
931
956
  }
932
- if (!(/^\w+\:(\/\/|.+)/.test(url))) {
933
- url = this.options.url + (url.startsWith('/') ? url : `/${url}`);
957
+ if (!/^\w+\:(\/\/|.+)/.test(url)) {
958
+ url = this.options.url + (url.startsWith('/') ? url : `/${url}`)
934
959
  }
935
960
 
936
- if (this.options.basicAuth && (this.isAuthenticated !== true)) {
961
+ if (this.options.basicAuth && this.isAuthenticated !== true) {
937
962
  if (url.includes(this.options.url)) {
938
- await this.browserContext.setHTTPCredentials(this.options.basicAuth);
939
- this.isAuthenticated = true;
963
+ await this.browserContext.setHTTPCredentials(this.options.basicAuth)
964
+ this.isAuthenticated = true
940
965
  }
941
966
  }
942
967
 
943
- await this.page.goto(url, { waitUntil: this.options.waitForNavigation });
968
+ await this.page.goto(url, { waitUntil: this.options.waitForNavigation })
944
969
 
945
- const performanceTiming = JSON.parse(await this.page.evaluate(() => JSON.stringify(window.performance.timing)));
970
+ const performanceTiming = JSON.parse(await this.page.evaluate(() => JSON.stringify(window.performance.timing)))
946
971
 
947
972
  perfTiming = this._extractDataFromPerformanceTiming(
948
973
  performanceTiming,
@@ -950,9 +975,9 @@ class Playwright extends Helper {
950
975
  'domInteractive',
951
976
  'domContentLoadedEventEnd',
952
977
  'loadEventEnd',
953
- );
978
+ )
954
979
 
955
- return this._waitForAction();
980
+ return this._waitForAction()
956
981
  }
957
982
 
958
983
  /**
@@ -973,11 +998,11 @@ class Playwright extends Helper {
973
998
  */
974
999
  async resizeWindow(width, height) {
975
1000
  if (width === 'maximize') {
976
- throw new Error('Playwright can\'t control windows, so it can\'t maximize it');
1001
+ throw new Error("Playwright can't control windows, so it can't maximize it")
977
1002
  }
978
1003
 
979
- await this.page.setViewportSize({ width, height });
980
- return this._waitForAction();
1004
+ await this.page.setViewportSize({ width, height })
1005
+ return this._waitForAction()
981
1006
  }
982
1007
 
983
1008
  /**
@@ -993,9 +1018,9 @@ class Playwright extends Helper {
993
1018
  */
994
1019
  async setPlaywrightRequestHeaders(customHeaders) {
995
1020
  if (!customHeaders) {
996
- throw new Error('Cannot send empty headers.');
1021
+ throw new Error('Cannot send empty headers.')
997
1022
  }
998
- return this.browserContext.setExtraHTTPHeaders(customHeaders);
1023
+ return this.browserContext.setExtraHTTPHeaders(customHeaders)
999
1024
  }
1000
1025
 
1001
1026
  /**
@@ -1003,13 +1028,13 @@ class Playwright extends Helper {
1003
1028
  *
1004
1029
  */
1005
1030
  async moveCursorTo(locator, offsetX = 0, offsetY = 0) {
1006
- const el = await this._locateElement(locator);
1007
- assertElementExists(el, locator);
1031
+ const el = await this._locateElement(locator)
1032
+ assertElementExists(el, locator)
1008
1033
 
1009
1034
  // Use manual mouse.move instead of .hover() so the offset can be added to the coordinates
1010
- const { x, y } = await clickablePoint(el);
1011
- await this.page.mouse.move(x + offsetX, y + offsetY);
1012
- return this._waitForAction();
1035
+ const { x, y } = await clickablePoint(el)
1036
+ await this.page.mouse.move(x + offsetX, y + offsetY)
1037
+ return this._waitForAction()
1013
1038
  }
1014
1039
 
1015
1040
  /**
@@ -1017,11 +1042,11 @@ class Playwright extends Helper {
1017
1042
  *
1018
1043
  */
1019
1044
  async focus(locator, options = {}) {
1020
- const el = await this._locateElement(locator);
1021
- assertElementExists(el, locator, 'Element to focus');
1045
+ const el = await this._locateElement(locator)
1046
+ assertElementExists(el, locator, 'Element to focus')
1022
1047
 
1023
- await el.focus(options);
1024
- return this._waitForAction();
1048
+ await el.focus(options)
1049
+ return this._waitForAction()
1025
1050
  }
1026
1051
 
1027
1052
  /**
@@ -1029,11 +1054,11 @@ class Playwright extends Helper {
1029
1054
  *
1030
1055
  */
1031
1056
  async blur(locator, options = {}) {
1032
- const el = await this._locateElement(locator);
1033
- assertElementExists(el, locator, 'Element to blur');
1057
+ const el = await this._locateElement(locator)
1058
+ assertElementExists(el, locator, 'Element to blur')
1034
1059
 
1035
- await el.blur(options);
1036
- return this._waitForAction();
1060
+ await el.blur(options)
1061
+ return this._waitForAction()
1037
1062
  }
1038
1063
  /**
1039
1064
  * Return the checked status of given element.
@@ -1045,14 +1070,14 @@ class Playwright extends Helper {
1045
1070
  */
1046
1071
 
1047
1072
  async grabCheckedElementStatus(locator, options = {}) {
1048
- const supportedTypes = ['checkbox', 'radio'];
1049
- const el = await this._locateElement(locator);
1050
- const type = await el.getAttribute('type');
1073
+ const supportedTypes = ['checkbox', 'radio']
1074
+ const el = await this._locateElement(locator)
1075
+ const type = await el.getAttribute('type')
1051
1076
 
1052
1077
  if (supportedTypes.includes(type)) {
1053
- return el.isChecked(options);
1078
+ return el.isChecked(options)
1054
1079
  }
1055
- throw new Error(`Element is not a ${supportedTypes.join(' or ')} input`);
1080
+ throw new Error(`Element is not a ${supportedTypes.join(' or ')} input`)
1056
1081
  }
1057
1082
  /**
1058
1083
  * Return the disabled status of given element.
@@ -1064,8 +1089,8 @@ class Playwright extends Helper {
1064
1089
  */
1065
1090
 
1066
1091
  async grabDisabledElementStatus(locator, options = {}) {
1067
- const el = await this._locateElement(locator);
1068
- return el.isDisabled(options);
1092
+ const el = await this._locateElement(locator)
1093
+ return el.isDisabled(options)
1069
1094
  }
1070
1095
 
1071
1096
  /**
@@ -1082,24 +1107,24 @@ class Playwright extends Helper {
1082
1107
  *
1083
1108
  */
1084
1109
  async dragAndDrop(srcElement, destElement, options) {
1085
- const src = new Locator(srcElement);
1086
- const dst = new Locator(destElement);
1110
+ const src = new Locator(srcElement)
1111
+ const dst = new Locator(destElement)
1087
1112
 
1088
1113
  if (options) {
1089
- return this.page.dragAndDrop(buildLocatorString(src), buildLocatorString(dst), options);
1114
+ return this.page.dragAndDrop(buildLocatorString(src), buildLocatorString(dst), options)
1090
1115
  }
1091
1116
 
1092
- const _smallWaitInMs = 600;
1093
- await this.page.locator(buildLocatorString(src)).hover();
1094
- await this.page.mouse.down();
1095
- await this.page.waitForTimeout(_smallWaitInMs);
1117
+ const _smallWaitInMs = 600
1118
+ await this.page.locator(buildLocatorString(src)).hover()
1119
+ await this.page.mouse.down()
1120
+ await this.page.waitForTimeout(_smallWaitInMs)
1096
1121
 
1097
- const destElBox = await this.page.locator(buildLocatorString(dst)).boundingBox();
1122
+ const destElBox = await this.page.locator(buildLocatorString(dst)).boundingBox()
1098
1123
 
1099
- await this.page.mouse.move(destElBox.x + destElBox.width / 2, destElBox.y + destElBox.height / 2);
1100
- await this.page.locator(buildLocatorString(dst)).hover({ position: { x: 10, y: 10 } });
1101
- await this.page.waitForTimeout(_smallWaitInMs);
1102
- await this.page.mouse.up();
1124
+ await this.page.mouse.move(destElBox.x + destElBox.width / 2, destElBox.y + destElBox.height / 2)
1125
+ await this.page.locator(buildLocatorString(dst)).hover({ position: { x: 10, y: 10 } })
1126
+ await this.page.waitForTimeout(_smallWaitInMs)
1127
+ await this.page.mouse.up()
1103
1128
  }
1104
1129
 
1105
1130
  /**
@@ -1117,16 +1142,16 @@ class Playwright extends Helper {
1117
1142
  * @param {object} [contextOptions] [Options for browser context](https://playwright.dev/docs/api/class-browser#browser-new-context) when starting new browser
1118
1143
  */
1119
1144
  async restartBrowser(contextOptions) {
1120
- await this._stopBrowser();
1121
- await this._startBrowser();
1122
- await this._createContextPage(contextOptions);
1145
+ await this._stopBrowser()
1146
+ await this._startBrowser()
1147
+ await this._createContextPage(contextOptions)
1123
1148
  }
1124
1149
 
1125
1150
  /**
1126
1151
  * {{> refreshPage }}
1127
1152
  */
1128
1153
  async refreshPage() {
1129
- return this.page.reload({ timeout: this.options.getPageTimeout, waitUntil: this.options.waitForNavigation });
1154
+ return this.page.reload({ timeout: this.options.getPageTimeout, waitUntil: this.options.waitForNavigation })
1130
1155
  }
1131
1156
 
1132
1157
  /**
@@ -1147,13 +1172,13 @@ class Playwright extends Helper {
1147
1172
  * @returns Promise<void>
1148
1173
  */
1149
1174
  async replayFromHar(harFilePath, opts) {
1150
- const file = path.join(global.codecept_dir, harFilePath);
1175
+ const file = path.join(global.codecept_dir, harFilePath)
1151
1176
 
1152
1177
  if (!fileExists(file)) {
1153
- throw new Error(`File at ${file} cannot be found on local system`);
1178
+ throw new Error(`File at ${file} cannot be found on local system`)
1154
1179
  }
1155
1180
 
1156
- await this.page.routeFromHAR(harFilePath, opts);
1181
+ await this.page.routeFromHAR(harFilePath, opts)
1157
1182
  }
1158
1183
 
1159
1184
  /**
@@ -1161,8 +1186,8 @@ class Playwright extends Helper {
1161
1186
  */
1162
1187
  scrollPageToTop() {
1163
1188
  return this.executeScript(() => {
1164
- window.scrollTo(0, 0);
1165
- });
1189
+ window.scrollTo(0, 0)
1190
+ })
1166
1191
  }
1167
1192
 
1168
1193
  /**
@@ -1170,16 +1195,13 @@ class Playwright extends Helper {
1170
1195
  */
1171
1196
  async scrollPageToBottom() {
1172
1197
  return this.executeScript(() => {
1173
- const body = document.body;
1174
- const html = document.documentElement;
1175
- window.scrollTo(0, Math.max(
1176
- body.scrollHeight,
1177
- body.offsetHeight,
1178
- html.clientHeight,
1179
- html.scrollHeight,
1180
- html.offsetHeight,
1181
- ));
1182
- });
1198
+ const body = document.body
1199
+ const html = document.documentElement
1200
+ window.scrollTo(
1201
+ 0,
1202
+ Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight),
1203
+ )
1204
+ })
1183
1205
  }
1184
1206
 
1185
1207
  /**
@@ -1187,67 +1209,69 @@ class Playwright extends Helper {
1187
1209
  */
1188
1210
  async scrollTo(locator, offsetX = 0, offsetY = 0) {
1189
1211
  if (typeof locator === 'number' && typeof offsetX === 'number') {
1190
- offsetY = offsetX;
1191
- offsetX = locator;
1192
- locator = null;
1212
+ offsetY = offsetX
1213
+ offsetX = locator
1214
+ locator = null
1193
1215
  }
1194
1216
 
1195
1217
  if (locator) {
1196
- const el = await this._locateElement(locator);
1197
- assertElementExists(el, locator, 'Element');
1198
- await el.scrollIntoViewIfNeeded();
1199
- const elementCoordinates = await clickablePoint(el);
1200
- await this.executeScript((offsetX, offsetY) => window.scrollBy(offsetX, offsetY), { offsetX: elementCoordinates.x + offsetX, offsetY: elementCoordinates.y + offsetY });
1218
+ const el = await this._locateElement(locator)
1219
+ assertElementExists(el, locator, 'Element')
1220
+ await el.scrollIntoViewIfNeeded()
1221
+ const elementCoordinates = await clickablePoint(el)
1222
+ await this.executeScript((offsetX, offsetY) => window.scrollBy(offsetX, offsetY), {
1223
+ offsetX: elementCoordinates.x + offsetX,
1224
+ offsetY: elementCoordinates.y + offsetY,
1225
+ })
1201
1226
  } else {
1202
- await this.executeScript(({ offsetX, offsetY }) => window.scrollTo(offsetX, offsetY), { offsetX, offsetY });
1227
+ await this.executeScript(({ offsetX, offsetY }) => window.scrollTo(offsetX, offsetY), { offsetX, offsetY })
1203
1228
  }
1204
- return this._waitForAction();
1229
+ return this._waitForAction()
1205
1230
  }
1206
1231
 
1207
1232
  /**
1208
1233
  * {{> seeInTitle }}
1209
1234
  */
1210
1235
  async seeInTitle(text) {
1211
- const title = await this.page.title();
1212
- stringIncludes('web page title').assert(text, title);
1236
+ const title = await this.page.title()
1237
+ stringIncludes('web page title').assert(text, title)
1213
1238
  }
1214
1239
 
1215
1240
  /**
1216
1241
  * {{> grabPageScrollPosition }}
1217
1242
  */
1218
1243
  async grabPageScrollPosition() {
1219
- /* eslint-disable comma-dangle */
1220
1244
  function getScrollPosition() {
1221
1245
  return {
1222
1246
  x: window.pageXOffset,
1223
- y: window.pageYOffset
1224
- };
1247
+ y: window.pageYOffset,
1248
+ }
1225
1249
  }
1226
- /* eslint-enable comma-dangle */
1227
- return this.executeScript(getScrollPosition);
1250
+
1251
+ return this.executeScript(getScrollPosition)
1228
1252
  }
1229
1253
 
1230
1254
  /**
1231
1255
  * {{> seeTitleEquals }}
1232
1256
  */
1233
1257
  async seeTitleEquals(text) {
1234
- const title = await this.page.title();
1235
- return equals('web page title').assert(title, text);
1258
+ const title = await this.page.title()
1259
+ return equals('web page title').assert(title, text)
1236
1260
  }
1237
1261
 
1238
1262
  /**
1239
1263
  * {{> dontSeeInTitle }}
1240
1264
  */
1241
1265
  async dontSeeInTitle(text) {
1242
- const title = await this.page.title();
1243
- stringIncludes('web page title').negate(text, title);
1266
+ const title = await this.page.title()
1267
+ stringIncludes('web page title').negate(text, title)
1244
1268
  }
1245
1269
 
1246
1270
  /**
1247
1271
  * {{> grabTitle }}
1248
1272
  */
1249
1273
  async grabTitle() {
1250
- return this.page.title();
1274
+ return this.page.title()
1251
1275
  }
1252
1276
 
1253
1277
  /**
@@ -1259,11 +1283,11 @@ class Playwright extends Helper {
1259
1283
  * ```
1260
1284
  */
1261
1285
  async _locate(locator) {
1262
- const context = (await this.context) || (await this._getContext());
1286
+ const context = await this._getContext()
1263
1287
 
1264
- if (this.frame) return findElements(this.frame, locator);
1288
+ if (this.frame) return findElements(this.frame, locator)
1265
1289
 
1266
- return findElements(context, locator);
1290
+ return findElements(context, locator)
1267
1291
  }
1268
1292
 
1269
1293
  /**
@@ -1275,8 +1299,8 @@ class Playwright extends Helper {
1275
1299
  * ```
1276
1300
  */
1277
1301
  async _locateElement(locator) {
1278
- const context = (await this.context) || (await this._getContext());
1279
- return findElement(context, locator);
1302
+ const context = await this._getContext()
1303
+ return findElement(context, locator)
1280
1304
  }
1281
1305
 
1282
1306
  /**
@@ -1288,10 +1312,10 @@ class Playwright extends Helper {
1288
1312
  * ```
1289
1313
  */
1290
1314
  async _locateCheckable(locator, providedContext = null) {
1291
- const context = providedContext || (await this._getContext());
1292
- const els = await findCheckable.call(this, locator, context);
1293
- assertElementExists(els[0], locator, 'Checkbox or radio');
1294
- return els[0];
1315
+ const context = providedContext || (await this._getContext())
1316
+ const els = await findCheckable.call(this, locator, context)
1317
+ assertElementExists(els[0], locator, 'Checkbox or radio')
1318
+ return els[0]
1295
1319
  }
1296
1320
 
1297
1321
  /**
@@ -1302,8 +1326,8 @@ class Playwright extends Helper {
1302
1326
  * ```
1303
1327
  */
1304
1328
  async _locateClickable(locator) {
1305
- const context = await this._getContext();
1306
- return findClickable.call(this, context, locator);
1329
+ const context = await this._getContext()
1330
+ return findClickable.call(this, context, locator)
1307
1331
  }
1308
1332
 
1309
1333
  /**
@@ -1314,7 +1338,7 @@ class Playwright extends Helper {
1314
1338
  * ```
1315
1339
  */
1316
1340
  async _locateFields(locator) {
1317
- return findFields.call(this, locator);
1341
+ return findFields.call(this, locator)
1318
1342
  }
1319
1343
 
1320
1344
  /**
@@ -1322,7 +1346,7 @@ class Playwright extends Helper {
1322
1346
  *
1323
1347
  */
1324
1348
  async grabWebElements(locator) {
1325
- return this._locate(locator);
1349
+ return this._locate(locator)
1326
1350
  }
1327
1351
 
1328
1352
  /**
@@ -1330,7 +1354,7 @@ class Playwright extends Helper {
1330
1354
  *
1331
1355
  */
1332
1356
  async grabWebElement(locator) {
1333
- return this._locateElement(locator);
1357
+ return this._locateElement(locator)
1334
1358
  }
1335
1359
 
1336
1360
  /**
@@ -1345,20 +1369,20 @@ class Playwright extends Helper {
1345
1369
  */
1346
1370
  async switchToNextTab(num = 1) {
1347
1371
  if (this.isElectron) {
1348
- throw new Error('Cannot switch tabs inside an Electron container');
1372
+ throw new Error('Cannot switch tabs inside an Electron container')
1349
1373
  }
1350
- const pages = await this.browserContext.pages();
1374
+ const pages = await this.browserContext.pages()
1351
1375
 
1352
- const index = pages.indexOf(this.page);
1353
- this.withinLocator = null;
1354
- const page = pages[index + num];
1376
+ const index = pages.indexOf(this.page)
1377
+ this.withinLocator = null
1378
+ const page = pages[index + num]
1355
1379
 
1356
1380
  if (!page) {
1357
- throw new Error(`There is no ability to switch to next tab with offset ${num}`);
1381
+ throw new Error(`There is no ability to switch to next tab with offset ${num}`)
1358
1382
  }
1359
- await targetCreatedHandler.call(this, page);
1360
- await this._setPage(page);
1361
- return this._waitForAction();
1383
+ await targetCreatedHandler.call(this, page)
1384
+ await this._setPage(page)
1385
+ return this._waitForAction()
1362
1386
  }
1363
1387
 
1364
1388
  /**
@@ -1372,19 +1396,19 @@ class Playwright extends Helper {
1372
1396
  */
1373
1397
  async switchToPreviousTab(num = 1) {
1374
1398
  if (this.isElectron) {
1375
- throw new Error('Cannot switch tabs inside an Electron container');
1399
+ throw new Error('Cannot switch tabs inside an Electron container')
1376
1400
  }
1377
- const pages = await this.browserContext.pages();
1378
- const index = pages.indexOf(this.page);
1379
- this.withinLocator = null;
1380
- const page = pages[index - num];
1401
+ const pages = await this.browserContext.pages()
1402
+ const index = pages.indexOf(this.page)
1403
+ this.withinLocator = null
1404
+ const page = pages[index - num]
1381
1405
 
1382
1406
  if (!page) {
1383
- throw new Error(`There is no ability to switch to previous tab with offset ${num}`);
1407
+ throw new Error(`There is no ability to switch to previous tab with offset ${num}`)
1384
1408
  }
1385
1409
 
1386
- await this._setPage(page);
1387
- return this._waitForAction();
1410
+ await this._setPage(page)
1411
+ return this._waitForAction()
1388
1412
  }
1389
1413
 
1390
1414
  /**
@@ -1396,12 +1420,12 @@ class Playwright extends Helper {
1396
1420
  */
1397
1421
  async closeCurrentTab() {
1398
1422
  if (this.isElectron) {
1399
- throw new Error('Cannot close current tab inside an Electron container');
1423
+ throw new Error('Cannot close current tab inside an Electron container')
1400
1424
  }
1401
- const oldPage = this.page;
1402
- await this.switchToPreviousTab();
1403
- await oldPage.close();
1404
- return this._waitForAction();
1425
+ const oldPage = this.page
1426
+ await this.switchToPreviousTab()
1427
+ await oldPage.close()
1428
+ return this._waitForAction()
1405
1429
  }
1406
1430
 
1407
1431
  /**
@@ -1412,13 +1436,13 @@ class Playwright extends Helper {
1412
1436
  * ```
1413
1437
  */
1414
1438
  async closeOtherTabs() {
1415
- const pages = await this.browserContext.pages();
1416
- const otherPages = pages.filter(page => page !== this.page);
1439
+ const pages = await this.browserContext.pages()
1440
+ const otherPages = pages.filter((page) => page !== this.page)
1417
1441
  if (otherPages.length) {
1418
- this.debug(`Closing ${otherPages.length} tabs`);
1419
- return Promise.all(otherPages.map(p => p.close()));
1442
+ this.debug(`Closing ${otherPages.length} tabs`)
1443
+ return Promise.all(otherPages.map((p) => p.close()))
1420
1444
  }
1421
- return Promise.resolve();
1445
+ return Promise.resolve()
1422
1446
  }
1423
1447
 
1424
1448
  /**
@@ -1437,20 +1461,20 @@ class Playwright extends Helper {
1437
1461
  */
1438
1462
  async openNewTab(options) {
1439
1463
  if (this.isElectron) {
1440
- throw new Error('Cannot open new tabs inside an Electron container');
1464
+ throw new Error('Cannot open new tabs inside an Electron container')
1441
1465
  }
1442
- const page = await this.browserContext.newPage(options);
1443
- await targetCreatedHandler.call(this, page);
1444
- await this._setPage(page);
1445
- return this._waitForAction();
1466
+ const page = await this.browserContext.newPage(options)
1467
+ await targetCreatedHandler.call(this, page)
1468
+ await this._setPage(page)
1469
+ return this._waitForAction()
1446
1470
  }
1447
1471
 
1448
1472
  /**
1449
1473
  * {{> grabNumberOfOpenTabs }}
1450
1474
  */
1451
1475
  async grabNumberOfOpenTabs() {
1452
- const pages = await this.browserContext.pages();
1453
- return pages.length;
1476
+ const pages = await this.browserContext.pages()
1477
+ return pages.length
1454
1478
  }
1455
1479
 
1456
1480
  /**
@@ -1458,12 +1482,12 @@ class Playwright extends Helper {
1458
1482
  *
1459
1483
  */
1460
1484
  async seeElement(locator) {
1461
- let els = await this._locate(locator);
1462
- els = await Promise.all(els.map(el => el.isVisible()));
1485
+ let els = await this._locate(locator)
1486
+ els = await Promise.all(els.map((el) => el.isVisible()))
1463
1487
  try {
1464
- return empty('visible elements').negate(els.filter(v => v).fill('ELEMENT'));
1488
+ return empty('visible elements').negate(els.filter((v) => v).fill('ELEMENT'))
1465
1489
  } catch (e) {
1466
- dontSeeElementError(locator);
1490
+ dontSeeElementError(locator)
1467
1491
  }
1468
1492
  }
1469
1493
 
@@ -1472,12 +1496,12 @@ class Playwright extends Helper {
1472
1496
  *
1473
1497
  */
1474
1498
  async dontSeeElement(locator) {
1475
- let els = await this._locate(locator);
1476
- els = await Promise.all(els.map(el => el.isVisible()));
1499
+ let els = await this._locate(locator)
1500
+ els = await Promise.all(els.map((el) => el.isVisible()))
1477
1501
  try {
1478
- return empty('visible elements').assert(els.filter(v => v).fill('ELEMENT'));
1502
+ return empty('visible elements').assert(els.filter((v) => v).fill('ELEMENT'))
1479
1503
  } catch (e) {
1480
- seeElementError(locator);
1504
+ seeElementError(locator)
1481
1505
  }
1482
1506
  }
1483
1507
 
@@ -1485,11 +1509,11 @@ class Playwright extends Helper {
1485
1509
  * {{> seeElementInDOM }}
1486
1510
  */
1487
1511
  async seeElementInDOM(locator) {
1488
- const els = await this._locate(locator);
1512
+ const els = await this._locate(locator)
1489
1513
  try {
1490
- return empty('elements on page').negate(els.filter(v => v).fill('ELEMENT'));
1514
+ return empty('elements on page').negate(els.filter((v) => v).fill('ELEMENT'))
1491
1515
  } catch (e) {
1492
- dontSeeElementInDOMError(locator);
1516
+ dontSeeElementInDOMError(locator)
1493
1517
  }
1494
1518
  }
1495
1519
 
@@ -1497,11 +1521,11 @@ class Playwright extends Helper {
1497
1521
  * {{> dontSeeElementInDOM }}
1498
1522
  */
1499
1523
  async dontSeeElementInDOM(locator) {
1500
- const els = await this._locate(locator);
1524
+ const els = await this._locate(locator)
1501
1525
  try {
1502
- return empty('elements on a page').assert(els.filter(v => v).fill('ELEMENT'));
1526
+ return empty('elements on a page').assert(els.filter((v) => v).fill('ELEMENT'))
1503
1527
  } catch (e) {
1504
- seeElementInDOMError(locator);
1528
+ seeElementInDOMError(locator)
1505
1529
  }
1506
1530
  }
1507
1531
 
@@ -1524,18 +1548,18 @@ class Playwright extends Helper {
1524
1548
  */
1525
1549
  async handleDownloads(fileName) {
1526
1550
  this.page.waitForEvent('download').then(async (download) => {
1527
- const filePath = await download.path();
1528
- fileName = fileName || `downloads/${path.basename(filePath)}`;
1551
+ const filePath = await download.path()
1552
+ fileName = fileName || `downloads/${path.basename(filePath)}`
1529
1553
 
1530
- const downloadPath = path.join(global.output_dir, fileName);
1554
+ const downloadPath = path.join(global.output_dir, fileName)
1531
1555
  if (!fs.existsSync(path.dirname(downloadPath))) {
1532
- fs.mkdirSync(path.dirname(downloadPath), '0777');
1556
+ fs.mkdirSync(path.dirname(downloadPath), '0777')
1533
1557
  }
1534
- fs.copyFileSync(filePath, downloadPath);
1535
- this.debug('Download completed');
1536
- this.debugSection('Downloaded From', await download.url());
1537
- this.debugSection('Downloaded To', downloadPath);
1538
- });
1558
+ fs.copyFileSync(filePath, downloadPath)
1559
+ this.debug('Download completed')
1560
+ this.debugSection('Downloaded From', await download.url())
1561
+ this.debugSection('Downloaded To', downloadPath)
1562
+ })
1539
1563
  }
1540
1564
 
1541
1565
  /**
@@ -1555,37 +1579,37 @@ class Playwright extends Helper {
1555
1579
  *
1556
1580
  */
1557
1581
  async click(locator, context = null, options = {}) {
1558
- return proceedClick.call(this, locator, context, options);
1582
+ return proceedClick.call(this, locator, context, options)
1559
1583
  }
1560
1584
 
1561
1585
  /**
1562
1586
  * Clicks link and waits for navigation (deprecated)
1563
1587
  */
1564
1588
  async clickLink(locator, context = null) {
1565
- console.log('clickLink deprecated: Playwright automatically waits for navigation to happen.');
1566
- console.log('Replace I.clickLink with I.click');
1567
- return this.click(locator, context);
1589
+ console.log('clickLink deprecated: Playwright automatically waits for navigation to happen.')
1590
+ console.log('Replace I.clickLink with I.click')
1591
+ return this.click(locator, context)
1568
1592
  }
1569
1593
 
1570
1594
  /**
1571
1595
  * {{> forceClick }}
1572
1596
  */
1573
1597
  async forceClick(locator, context = null) {
1574
- return proceedClick.call(this, locator, context, { force: true });
1598
+ return proceedClick.call(this, locator, context, { force: true })
1575
1599
  }
1576
1600
 
1577
1601
  /**
1578
1602
  * {{> doubleClick }}
1579
1603
  */
1580
1604
  async doubleClick(locator, context = null) {
1581
- return proceedClick.call(this, locator, context, { clickCount: 2 });
1605
+ return proceedClick.call(this, locator, context, { clickCount: 2 })
1582
1606
  }
1583
1607
 
1584
1608
  /**
1585
1609
  * {{> rightClick }}
1586
1610
  */
1587
1611
  async rightClick(locator, context = null) {
1588
- return proceedClick.call(this, locator, context, { button: 'right' });
1612
+ return proceedClick.call(this, locator, context, { button: 'right' })
1589
1613
  }
1590
1614
 
1591
1615
  /**
@@ -1604,9 +1628,9 @@ class Playwright extends Helper {
1604
1628
  *
1605
1629
  */
1606
1630
  async checkOption(field, context = null, options = { force: true }) {
1607
- const elm = await this._locateCheckable(field, context);
1608
- await elm.check(options);
1609
- return this._waitForAction();
1631
+ const elm = await this._locateCheckable(field, context)
1632
+ await elm.check(options)
1633
+ return this._waitForAction()
1610
1634
  }
1611
1635
 
1612
1636
  /**
@@ -1624,41 +1648,41 @@ class Playwright extends Helper {
1624
1648
  * {{> uncheckOption }}
1625
1649
  */
1626
1650
  async uncheckOption(field, context = null, options = { force: true }) {
1627
- const elm = await this._locateCheckable(field, context);
1628
- await elm.uncheck(options);
1629
- return this._waitForAction();
1651
+ const elm = await this._locateCheckable(field, context)
1652
+ await elm.uncheck(options)
1653
+ return this._waitForAction()
1630
1654
  }
1631
1655
 
1632
1656
  /**
1633
1657
  * {{> seeCheckboxIsChecked }}
1634
1658
  */
1635
1659
  async seeCheckboxIsChecked(field) {
1636
- return proceedIsChecked.call(this, 'assert', field);
1660
+ return proceedIsChecked.call(this, 'assert', field)
1637
1661
  }
1638
1662
 
1639
1663
  /**
1640
1664
  * {{> dontSeeCheckboxIsChecked }}
1641
1665
  */
1642
1666
  async dontSeeCheckboxIsChecked(field) {
1643
- return proceedIsChecked.call(this, 'negate', field);
1667
+ return proceedIsChecked.call(this, 'negate', field)
1644
1668
  }
1645
1669
 
1646
1670
  /**
1647
1671
  * {{> pressKeyDown }}
1648
1672
  */
1649
1673
  async pressKeyDown(key) {
1650
- key = getNormalizedKey.call(this, key);
1651
- await this.page.keyboard.down(key);
1652
- return this._waitForAction();
1674
+ key = getNormalizedKey.call(this, key)
1675
+ await this.page.keyboard.down(key)
1676
+ return this._waitForAction()
1653
1677
  }
1654
1678
 
1655
1679
  /**
1656
1680
  * {{> pressKeyUp }}
1657
1681
  */
1658
1682
  async pressKeyUp(key) {
1659
- key = getNormalizedKey.call(this, key);
1660
- await this.page.keyboard.up(key);
1661
- return this._waitForAction();
1683
+ key = getNormalizedKey.call(this, key)
1684
+ await this.page.keyboard.up(key)
1685
+ return this._waitForAction()
1662
1686
  }
1663
1687
 
1664
1688
  /**
@@ -1668,28 +1692,28 @@ class Playwright extends Helper {
1668
1692
  * {{> pressKeyWithKeyNormalization }}
1669
1693
  */
1670
1694
  async pressKey(key) {
1671
- const modifiers = [];
1695
+ const modifiers = []
1672
1696
  if (Array.isArray(key)) {
1673
1697
  for (let k of key) {
1674
- k = getNormalizedKey.call(this, k);
1698
+ k = getNormalizedKey.call(this, k)
1675
1699
  if (isModifierKey(k)) {
1676
- modifiers.push(k);
1700
+ modifiers.push(k)
1677
1701
  } else {
1678
- key = k;
1679
- break;
1702
+ key = k
1703
+ break
1680
1704
  }
1681
1705
  }
1682
1706
  } else {
1683
- key = getNormalizedKey.call(this, key);
1707
+ key = getNormalizedKey.call(this, key)
1684
1708
  }
1685
1709
  for (const modifier of modifiers) {
1686
- await this.page.keyboard.down(modifier);
1710
+ await this.page.keyboard.down(modifier)
1687
1711
  }
1688
- await this.page.keyboard.press(key);
1712
+ await this.page.keyboard.press(key)
1689
1713
  for (const modifier of modifiers) {
1690
- await this.page.keyboard.up(modifier);
1714
+ await this.page.keyboard.up(modifier)
1691
1715
  }
1692
- return this._waitForAction();
1716
+ return this._waitForAction()
1693
1717
  }
1694
1718
 
1695
1719
  /**
@@ -1697,13 +1721,13 @@ class Playwright extends Helper {
1697
1721
  */
1698
1722
  async type(keys, delay = null) {
1699
1723
  if (!Array.isArray(keys)) {
1700
- keys = keys.toString();
1701
- keys = keys.split('');
1724
+ keys = keys.toString()
1725
+ keys = keys.split('')
1702
1726
  }
1703
1727
 
1704
1728
  for (const key of keys) {
1705
- await this.page.keyboard.press(key);
1706
- if (delay) await this.wait(delay / 1000);
1729
+ await this.page.keyboard.press(key)
1730
+ if (delay) await this.wait(delay / 1000)
1707
1731
  }
1708
1732
  }
1709
1733
 
@@ -1712,75 +1736,75 @@ class Playwright extends Helper {
1712
1736
  *
1713
1737
  */
1714
1738
  async fillField(field, value) {
1715
- const els = await findFields.call(this, field);
1716
- assertElementExists(els, field, 'Field');
1717
- const el = els[0];
1739
+ const els = await findFields.call(this, field)
1740
+ assertElementExists(els, field, 'Field')
1741
+ const el = els[0]
1718
1742
 
1719
- await el.clear();
1743
+ await el.clear()
1720
1744
 
1721
- await highlightActiveElement.call(this, el);
1745
+ await highlightActiveElement.call(this, el)
1722
1746
 
1723
- await el.type(value.toString(), { delay: this.options.pressKeyDelay });
1747
+ await el.type(value.toString(), { delay: this.options.pressKeyDelay })
1724
1748
 
1725
- return this._waitForAction();
1749
+ return this._waitForAction()
1726
1750
  }
1727
1751
 
1728
1752
  /**
1729
1753
  * Clears the text input element: `<input>`, `<textarea>` or `[contenteditable]` .
1730
1754
  *
1731
- *
1732
- * Examples:
1733
- *
1734
- * ```js
1735
- * I.clearField('.text-area')
1736
- *
1737
- * // if this doesn't work use force option
1738
- * I.clearField('#submit', { force: true })
1739
- * ```
1740
- * Use `force` to bypass the [actionability](https://playwright.dev/docs/actionability) checks.
1741
- *
1755
+ *
1756
+ * Examples:
1757
+ *
1758
+ * ```js
1759
+ * I.clearField('.text-area')
1760
+ *
1761
+ * // if this doesn't work use force option
1762
+ * I.clearField('#submit', { force: true })
1763
+ * ```
1764
+ * Use `force` to bypass the [actionability](https://playwright.dev/docs/actionability) checks.
1765
+ *
1742
1766
  * @param {CodeceptJS.LocatorOrString} locator field located by label|name|CSS|XPath|strict locator.
1743
1767
  * @param {any} [options] [Additional options](https://playwright.dev/docs/api/class-locator#locator-clear) for available options object as 2nd argument.
1744
1768
  */
1745
1769
  async clearField(locator, options = {}) {
1746
- const els = await findFields.call(this, locator);
1747
- assertElementExists(els, locator, 'Field to clear');
1770
+ const els = await findFields.call(this, locator)
1771
+ assertElementExists(els, locator, 'Field to clear')
1748
1772
 
1749
- const el = els[0];
1773
+ const el = els[0]
1750
1774
 
1751
- await highlightActiveElement.call(this, el);
1775
+ await highlightActiveElement.call(this, el)
1752
1776
 
1753
- await el.clear();
1777
+ await el.clear()
1754
1778
 
1755
- return this._waitForAction();
1779
+ return this._waitForAction()
1756
1780
  }
1757
1781
 
1758
1782
  /**
1759
1783
  * {{> appendField }}
1760
1784
  */
1761
1785
  async appendField(field, value) {
1762
- const els = await findFields.call(this, field);
1763
- assertElementExists(els, field, 'Field');
1764
- await highlightActiveElement.call(this, els[0]);
1765
- await els[0].press('End');
1766
- await els[0].type(value.toString(), { delay: this.options.pressKeyDelay });
1767
- return this._waitForAction();
1786
+ const els = await findFields.call(this, field)
1787
+ assertElementExists(els, field, 'Field')
1788
+ await highlightActiveElement.call(this, els[0])
1789
+ await els[0].press('End')
1790
+ await els[0].type(value.toString(), { delay: this.options.pressKeyDelay })
1791
+ return this._waitForAction()
1768
1792
  }
1769
1793
 
1770
1794
  /**
1771
1795
  * {{> seeInField }}
1772
1796
  */
1773
1797
  async seeInField(field, value) {
1774
- const _value = (typeof value === 'boolean') ? value : value.toString();
1775
- return proceedSeeInField.call(this, 'assert', field, _value);
1798
+ const _value = typeof value === 'boolean' ? value : value.toString()
1799
+ return proceedSeeInField.call(this, 'assert', field, _value)
1776
1800
  }
1777
1801
 
1778
1802
  /**
1779
1803
  * {{> dontSeeInField }}
1780
1804
  */
1781
1805
  async dontSeeInField(field, value) {
1782
- const _value = (typeof value === 'boolean') ? value : value.toString();
1783
- return proceedSeeInField.call(this, 'negate', field, _value);
1806
+ const _value = typeof value === 'boolean' ? value : value.toString()
1807
+ return proceedSeeInField.call(this, 'negate', field, _value)
1784
1808
  }
1785
1809
 
1786
1810
  /**
@@ -1788,38 +1812,38 @@ class Playwright extends Helper {
1788
1812
  *
1789
1813
  */
1790
1814
  async attachFile(locator, pathToFile) {
1791
- const file = path.join(global.codecept_dir, pathToFile);
1815
+ const file = path.join(global.codecept_dir, pathToFile)
1792
1816
 
1793
1817
  if (!fileExists(file)) {
1794
- throw new Error(`File at ${file} can not be found on local system`);
1818
+ throw new Error(`File at ${file} can not be found on local system`)
1795
1819
  }
1796
- const els = await findFields.call(this, locator);
1797
- assertElementExists(els, locator, 'Field');
1798
- await els[0].setInputFiles(file);
1799
- return this._waitForAction();
1820
+ const els = await findFields.call(this, locator)
1821
+ assertElementExists(els, locator, 'Field')
1822
+ await els[0].setInputFiles(file)
1823
+ return this._waitForAction()
1800
1824
  }
1801
1825
 
1802
1826
  /**
1803
1827
  * {{> selectOption }}
1804
1828
  */
1805
1829
  async selectOption(select, option) {
1806
- const els = await findFields.call(this, select);
1807
- assertElementExists(els, select, 'Selectable field');
1808
- const el = els[0];
1830
+ const els = await findFields.call(this, select)
1831
+ assertElementExists(els, select, 'Selectable field')
1832
+ const el = els[0]
1809
1833
 
1810
- await highlightActiveElement.call(this, el);
1811
- let optionToSelect = '';
1834
+ await highlightActiveElement.call(this, el)
1835
+ let optionToSelect = ''
1812
1836
 
1813
1837
  try {
1814
- optionToSelect = (await el.locator('option', { hasText: option }).textContent()).trim();
1838
+ optionToSelect = (await el.locator('option', { hasText: option }).textContent()).trim()
1815
1839
  } catch (e) {
1816
- optionToSelect = option;
1840
+ optionToSelect = option
1817
1841
  }
1818
1842
 
1819
- if (!Array.isArray(option)) option = [optionToSelect];
1843
+ if (!Array.isArray(option)) option = [optionToSelect]
1820
1844
 
1821
- await el.selectOption(option);
1822
- return this._waitForAction();
1845
+ await el.selectOption(option)
1846
+ return this._waitForAction()
1823
1847
  }
1824
1848
 
1825
1849
  /**
@@ -1827,37 +1851,37 @@ class Playwright extends Helper {
1827
1851
  *
1828
1852
  */
1829
1853
  async grabNumberOfVisibleElements(locator) {
1830
- let els = await this._locate(locator);
1831
- els = await Promise.all(els.map(el => el.isVisible()));
1832
- return els.filter(v => v).length;
1854
+ let els = await this._locate(locator)
1855
+ els = await Promise.all(els.map((el) => el.isVisible()))
1856
+ return els.filter((v) => v).length
1833
1857
  }
1834
1858
 
1835
1859
  /**
1836
1860
  * {{> seeInCurrentUrl }}
1837
1861
  */
1838
1862
  async seeInCurrentUrl(url) {
1839
- stringIncludes('url').assert(url, await this._getPageUrl());
1863
+ stringIncludes('url').assert(url, await this._getPageUrl())
1840
1864
  }
1841
1865
 
1842
1866
  /**
1843
1867
  * {{> dontSeeInCurrentUrl }}
1844
1868
  */
1845
1869
  async dontSeeInCurrentUrl(url) {
1846
- stringIncludes('url').negate(url, await this._getPageUrl());
1870
+ stringIncludes('url').negate(url, await this._getPageUrl())
1847
1871
  }
1848
1872
 
1849
1873
  /**
1850
1874
  * {{> seeCurrentUrlEquals }}
1851
1875
  */
1852
1876
  async seeCurrentUrlEquals(url) {
1853
- urlEquals(this.options.url).assert(url, await this._getPageUrl());
1877
+ urlEquals(this.options.url).assert(url, await this._getPageUrl())
1854
1878
  }
1855
1879
 
1856
1880
  /**
1857
1881
  * {{> dontSeeCurrentUrlEquals }}
1858
1882
  */
1859
1883
  async dontSeeCurrentUrlEquals(url) {
1860
- urlEquals(this.options.url).negate(url, await this._getPageUrl());
1884
+ urlEquals(this.options.url).negate(url, await this._getPageUrl())
1861
1885
  }
1862
1886
 
1863
1887
  /**
@@ -1866,14 +1890,14 @@ class Playwright extends Helper {
1866
1890
  *
1867
1891
  */
1868
1892
  async see(text, context = null) {
1869
- return proceedSee.call(this, 'assert', text, context);
1893
+ return proceedSee.call(this, 'assert', text, context)
1870
1894
  }
1871
1895
 
1872
1896
  /**
1873
1897
  * {{> seeTextEquals }}
1874
1898
  */
1875
1899
  async seeTextEquals(text, context = null) {
1876
- return proceedSee.call(this, 'assert', text, context, true);
1900
+ return proceedSee.call(this, 'assert', text, context, true)
1877
1901
  }
1878
1902
 
1879
1903
  /**
@@ -1882,14 +1906,14 @@ class Playwright extends Helper {
1882
1906
  *
1883
1907
  */
1884
1908
  async dontSee(text, context = null) {
1885
- return proceedSee.call(this, 'negate', text, context);
1909
+ return proceedSee.call(this, 'negate', text, context)
1886
1910
  }
1887
1911
 
1888
1912
  /**
1889
1913
  * {{> grabSource }}
1890
1914
  */
1891
1915
  async grabSource() {
1892
- return this.page.content();
1916
+ return this.page.content()
1893
1917
  }
1894
1918
 
1895
1919
  /**
@@ -1904,32 +1928,32 @@ class Playwright extends Helper {
1904
1928
  * @return {Promise<any[]>}
1905
1929
  */
1906
1930
  async grabBrowserLogs() {
1907
- const logs = consoleLogStore.entries;
1908
- consoleLogStore.clear();
1909
- return logs;
1931
+ const logs = consoleLogStore.entries
1932
+ consoleLogStore.clear()
1933
+ return logs
1910
1934
  }
1911
1935
 
1912
1936
  /**
1913
1937
  * {{> grabCurrentUrl }}
1914
1938
  */
1915
1939
  async grabCurrentUrl() {
1916
- return this._getPageUrl();
1940
+ return this._getPageUrl()
1917
1941
  }
1918
1942
 
1919
1943
  /**
1920
1944
  * {{> seeInSource }}
1921
1945
  */
1922
1946
  async seeInSource(text) {
1923
- const source = await this.page.content();
1924
- stringIncludes('HTML source of a page').assert(text, source);
1947
+ const source = await this.page.content()
1948
+ stringIncludes('HTML source of a page').assert(text, source)
1925
1949
  }
1926
1950
 
1927
1951
  /**
1928
1952
  * {{> dontSeeInSource }}
1929
1953
  */
1930
1954
  async dontSeeInSource(text) {
1931
- const source = await this.page.content();
1932
- stringIncludes('HTML source of a page').negate(text, source);
1955
+ const source = await this.page.content()
1956
+ stringIncludes('HTML source of a page').negate(text, source)
1933
1957
  }
1934
1958
 
1935
1959
  /**
@@ -1938,8 +1962,10 @@ class Playwright extends Helper {
1938
1962
  *
1939
1963
  */
1940
1964
  async seeNumberOfElements(locator, num) {
1941
- const elements = await this._locate(locator);
1942
- return equals(`expected number of elements (${(new Locator(locator))}) is ${num}, but found ${elements.length}`).assert(elements.length, num);
1965
+ const elements = await this._locate(locator)
1966
+ return equals(
1967
+ `expected number of elements (${new Locator(locator)}) is ${num}, but found ${elements.length}`,
1968
+ ).assert(elements.length, num)
1943
1969
  }
1944
1970
 
1945
1971
  /**
@@ -1948,8 +1974,11 @@ class Playwright extends Helper {
1948
1974
  *
1949
1975
  */
1950
1976
  async seeNumberOfVisibleElements(locator, num) {
1951
- const res = await this.grabNumberOfVisibleElements(locator);
1952
- return equals(`expected number of visible elements (${(new Locator(locator))}) is ${num}, but found ${res}`).assert(res, num);
1977
+ const res = await this.grabNumberOfVisibleElements(locator)
1978
+ return equals(`expected number of visible elements (${new Locator(locator)}) is ${num}, but found ${res}`).assert(
1979
+ res,
1980
+ num,
1981
+ )
1953
1982
  }
1954
1983
 
1955
1984
  /**
@@ -1957,9 +1986,9 @@ class Playwright extends Helper {
1957
1986
  */
1958
1987
  async setCookie(cookie) {
1959
1988
  if (Array.isArray(cookie)) {
1960
- return this.browserContext.addCookies(cookie);
1989
+ return this.browserContext.addCookies(cookie)
1961
1990
  }
1962
- return this.browserContext.addCookies([cookie]);
1991
+ return this.browserContext.addCookies([cookie])
1963
1992
  }
1964
1993
 
1965
1994
  /**
@@ -1967,16 +1996,16 @@ class Playwright extends Helper {
1967
1996
  *
1968
1997
  */
1969
1998
  async seeCookie(name) {
1970
- const cookies = await this.browserContext.cookies();
1971
- empty(`cookie ${name} to be set`).negate(cookies.filter(c => c.name === name));
1999
+ const cookies = await this.browserContext.cookies()
2000
+ empty(`cookie ${name} to be set`).negate(cookies.filter((c) => c.name === name))
1972
2001
  }
1973
2002
 
1974
2003
  /**
1975
2004
  * {{> dontSeeCookie }}
1976
2005
  */
1977
2006
  async dontSeeCookie(name) {
1978
- const cookies = await this.browserContext.cookies();
1979
- empty(`cookie ${name} to be set`).assert(cookies.filter(c => c.name === name));
2007
+ const cookies = await this.browserContext.cookies()
2008
+ empty(`cookie ${name} not to be set`).assert(cookies.filter((c) => c.name === name))
1980
2009
  }
1981
2010
 
1982
2011
  /**
@@ -1985,10 +2014,10 @@ class Playwright extends Helper {
1985
2014
  * {{> grabCookie }}
1986
2015
  */
1987
2016
  async grabCookie(name) {
1988
- const cookies = await this.browserContext.cookies();
1989
- if (!name) return cookies;
1990
- const cookie = cookies.filter(c => c.name === name);
1991
- if (cookie[0]) return cookie[0];
2017
+ const cookies = await this.browserContext.cookies()
2018
+ if (!name) return cookies
2019
+ const cookie = cookies.filter((c) => c.name === name)
2020
+ if (cookie[0]) return cookie[0]
1992
2021
  }
1993
2022
 
1994
2023
  /**
@@ -1997,8 +2026,8 @@ class Playwright extends Helper {
1997
2026
  async clearCookie() {
1998
2027
  // Playwright currently doesn't support to delete a certain cookie
1999
2028
  // https://github.com/microsoft/playwright/blob/main/docs/src/api/class-browsercontext.md#async-method-browsercontextclearcookies
2000
- if (!this.browserContext) return;
2001
- return this.browserContext.clearCookies();
2029
+ if (!this.browserContext) return
2030
+ return this.browserContext.clearCookies()
2002
2031
  }
2003
2032
 
2004
2033
  /**
@@ -2028,9 +2057,9 @@ class Playwright extends Helper {
2028
2057
  async executeScript(fn, arg) {
2029
2058
  if (this.context && this.context.constructor.name === 'FrameLocator') {
2030
2059
  // switching to iframe context
2031
- return this.context.locator(':root').evaluate(fn, arg);
2060
+ return this.context.locator(':root').evaluate(fn, arg)
2032
2061
  }
2033
- return this.page.evaluate.apply(this.page, [fn, arg]);
2062
+ return this.page.evaluate.apply(this.page, [fn, arg])
2034
2063
  }
2035
2064
 
2036
2065
  /**
@@ -2039,14 +2068,14 @@ class Playwright extends Helper {
2039
2068
  * @param {*} locator
2040
2069
  */
2041
2070
  _contextLocator(locator) {
2042
- locator = buildLocatorString(new Locator(locator, 'css'));
2071
+ locator = buildLocatorString(new Locator(locator, 'css'))
2043
2072
 
2044
2073
  if (this.contextLocator) {
2045
- const contextLocator = buildLocatorString(new Locator(this.contextLocator, 'css'));
2046
- locator = `${contextLocator} >> ${locator}`;
2074
+ const contextLocator = buildLocatorString(new Locator(this.contextLocator, 'css'))
2075
+ locator = `${contextLocator} >> ${locator}`
2047
2076
  }
2048
2077
 
2049
- return locator;
2078
+ return locator
2050
2079
  }
2051
2080
 
2052
2081
  /**
@@ -2054,11 +2083,11 @@ class Playwright extends Helper {
2054
2083
  *
2055
2084
  */
2056
2085
  async grabTextFrom(locator) {
2057
- locator = this._contextLocator(locator);
2058
- const text = await this.page.textContent(locator);
2059
- assertElementExists(text, locator);
2060
- this.debugSection('Text', text);
2061
- return text;
2086
+ locator = this._contextLocator(locator)
2087
+ const text = await this.page.textContent(locator)
2088
+ assertElementExists(text, locator)
2089
+ this.debugSection('Text', text)
2090
+ return text
2062
2091
  }
2063
2092
 
2064
2093
  /**
@@ -2066,51 +2095,51 @@ class Playwright extends Helper {
2066
2095
  *
2067
2096
  */
2068
2097
  async grabTextFromAll(locator) {
2069
- const els = await this._locate(locator);
2070
- const texts = [];
2098
+ const els = await this._locate(locator)
2099
+ const texts = []
2071
2100
  for (const el of els) {
2072
- texts.push(await (await el.innerText()));
2101
+ texts.push(await await el.innerText())
2073
2102
  }
2074
- this.debug(`Matched ${els.length} elements`);
2075
- return texts;
2103
+ this.debug(`Matched ${els.length} elements`)
2104
+ return texts
2076
2105
  }
2077
2106
 
2078
2107
  /**
2079
2108
  * {{> grabValueFrom }}
2080
2109
  */
2081
2110
  async grabValueFrom(locator) {
2082
- const values = await this.grabValueFromAll(locator);
2083
- assertElementExists(values, locator);
2084
- this.debugSection('Value', values[0]);
2085
- return values[0];
2111
+ const values = await this.grabValueFromAll(locator)
2112
+ assertElementExists(values, locator)
2113
+ this.debugSection('Value', values[0])
2114
+ return values[0]
2086
2115
  }
2087
2116
 
2088
2117
  /**
2089
2118
  * {{> grabValueFromAll }}
2090
2119
  */
2091
2120
  async grabValueFromAll(locator) {
2092
- const els = await findFields.call(this, locator);
2093
- this.debug(`Matched ${els.length} elements`);
2094
- return Promise.all(els.map(el => el.inputValue()));
2121
+ const els = await findFields.call(this, locator)
2122
+ this.debug(`Matched ${els.length} elements`)
2123
+ return Promise.all(els.map((el) => el.inputValue()))
2095
2124
  }
2096
2125
 
2097
2126
  /**
2098
2127
  * {{> grabHTMLFrom }}
2099
2128
  */
2100
2129
  async grabHTMLFrom(locator) {
2101
- const html = await this.grabHTMLFromAll(locator);
2102
- assertElementExists(html, locator);
2103
- this.debugSection('HTML', html[0]);
2104
- return html[0];
2130
+ const html = await this.grabHTMLFromAll(locator)
2131
+ assertElementExists(html, locator)
2132
+ this.debugSection('HTML', html[0])
2133
+ return html[0]
2105
2134
  }
2106
2135
 
2107
2136
  /**
2108
2137
  * {{> grabHTMLFromAll }}
2109
2138
  */
2110
2139
  async grabHTMLFromAll(locator) {
2111
- const els = await this._locate(locator);
2112
- this.debug(`Matched ${els.length} elements`);
2113
- return Promise.all(els.map(el => el.innerHTML()));
2140
+ const els = await this._locate(locator)
2141
+ this.debug(`Matched ${els.length} elements`)
2142
+ return Promise.all(els.map((el) => el.innerHTML()))
2114
2143
  }
2115
2144
 
2116
2145
  /**
@@ -2118,10 +2147,10 @@ class Playwright extends Helper {
2118
2147
  *
2119
2148
  */
2120
2149
  async grabCssPropertyFrom(locator, cssProperty) {
2121
- const cssValues = await this.grabCssPropertyFromAll(locator, cssProperty);
2122
- assertElementExists(cssValues, locator);
2123
- this.debugSection('CSS', cssValues[0]);
2124
- return cssValues[0];
2150
+ const cssValues = await this.grabCssPropertyFromAll(locator, cssProperty)
2151
+ assertElementExists(cssValues, locator)
2152
+ this.debugSection('CSS', cssValues[0])
2153
+ return cssValues[0]
2125
2154
  }
2126
2155
 
2127
2156
  /**
@@ -2129,11 +2158,15 @@ class Playwright extends Helper {
2129
2158
  *
2130
2159
  */
2131
2160
  async grabCssPropertyFromAll(locator, cssProperty) {
2132
- const els = await this._locate(locator);
2133
- this.debug(`Matched ${els.length} elements`);
2134
- const cssValues = await Promise.all(els.map(el => el.evaluate((el, cssProperty) => getComputedStyle(el).getPropertyValue(cssProperty), cssProperty)));
2161
+ const els = await this._locate(locator)
2162
+ this.debug(`Matched ${els.length} elements`)
2163
+ const cssValues = await Promise.all(
2164
+ els.map((el) =>
2165
+ el.evaluate((el, cssProperty) => getComputedStyle(el).getPropertyValue(cssProperty), cssProperty),
2166
+ ),
2167
+ )
2135
2168
 
2136
- return cssValues;
2169
+ return cssValues
2137
2170
  }
2138
2171
 
2139
2172
  /**
@@ -2141,35 +2174,37 @@ class Playwright extends Helper {
2141
2174
  *
2142
2175
  */
2143
2176
  async seeCssPropertiesOnElements(locator, cssProperties) {
2144
- const res = await this._locate(locator);
2145
- assertElementExists(res, locator);
2177
+ const res = await this._locate(locator)
2178
+ assertElementExists(res, locator)
2146
2179
 
2147
- const cssPropertiesCamelCase = convertCssPropertiesToCamelCase(cssProperties);
2148
- const elemAmount = res.length;
2149
- let props = [];
2180
+ const cssPropertiesCamelCase = convertCssPropertiesToCamelCase(cssProperties)
2181
+ const elemAmount = res.length
2182
+ let props = []
2150
2183
 
2151
2184
  for (const element of res) {
2152
2185
  for (const prop of Object.keys(cssProperties)) {
2153
- const cssProp = await this.grabCssPropertyFrom(locator, prop);
2186
+ const cssProp = await this.grabCssPropertyFrom(locator, prop)
2154
2187
  if (isColorProperty(prop)) {
2155
- props.push(convertColorToRGBA(cssProp));
2188
+ props.push(convertColorToRGBA(cssProp))
2156
2189
  } else {
2157
- props.push(cssProp);
2190
+ props.push(cssProp)
2158
2191
  }
2159
2192
  }
2160
2193
  }
2161
2194
 
2162
- const values = Object.keys(cssPropertiesCamelCase).map(key => cssPropertiesCamelCase[key]);
2163
- if (!Array.isArray(props)) props = [props];
2164
- let chunked = chunkArray(props, values.length);
2195
+ const values = Object.keys(cssPropertiesCamelCase).map((key) => cssPropertiesCamelCase[key])
2196
+ if (!Array.isArray(props)) props = [props]
2197
+ let chunked = chunkArray(props, values.length)
2165
2198
  chunked = chunked.filter((val) => {
2166
2199
  for (let i = 0; i < val.length; ++i) {
2167
2200
  // eslint-disable-next-line eqeqeq
2168
- if (val[i] != values[i]) return false;
2201
+ if (val[i] != values[i]) return false
2169
2202
  }
2170
- return true;
2171
- });
2172
- return equals(`all elements (${(new Locator(locator))}) to have CSS property ${JSON.stringify(cssProperties)}`).assert(chunked.length, elemAmount);
2203
+ return true
2204
+ })
2205
+ return equals(
2206
+ `all elements (${new Locator(locator)}) to have CSS property ${JSON.stringify(cssProperties)}`,
2207
+ ).assert(chunked.length, elemAmount)
2173
2208
  }
2174
2209
 
2175
2210
  /**
@@ -2177,31 +2212,33 @@ class Playwright extends Helper {
2177
2212
  *
2178
2213
  */
2179
2214
  async seeAttributesOnElements(locator, attributes) {
2180
- const res = await this._locate(locator);
2181
- assertElementExists(res, locator);
2215
+ const res = await this._locate(locator)
2216
+ assertElementExists(res, locator)
2182
2217
 
2183
- const elemAmount = res.length;
2184
- const commands = [];
2218
+ const elemAmount = res.length
2219
+ const commands = []
2185
2220
  res.forEach((el) => {
2186
2221
  Object.keys(attributes).forEach((prop) => {
2187
- commands.push(el
2188
- .evaluate((el, attr) => el[attr] || el.getAttribute(attr), prop));
2189
- });
2190
- });
2191
- let attrs = await Promise.all(commands);
2192
- const values = Object.keys(attributes).map(key => attributes[key]);
2193
- if (!Array.isArray(attrs)) attrs = [attrs];
2194
- let chunked = chunkArray(attrs, values.length);
2222
+ commands.push(el.evaluate((el, attr) => el[attr] || el.getAttribute(attr), prop))
2223
+ })
2224
+ })
2225
+ let attrs = await Promise.all(commands)
2226
+ const values = Object.keys(attributes).map((key) => attributes[key])
2227
+ if (!Array.isArray(attrs)) attrs = [attrs]
2228
+ let chunked = chunkArray(attrs, values.length)
2195
2229
  chunked = chunked.filter((val) => {
2196
2230
  for (let i = 0; i < val.length; ++i) {
2197
2231
  // the attribute could be a boolean
2198
- if (typeof val[i] === 'boolean') return val[i] === values[i];
2232
+ if (typeof val[i] === 'boolean') return val[i] === values[i]
2199
2233
  // if the attribute doesn't exist, returns false as well
2200
- if (!val[i] || !val[i].includes(values[i])) return false;
2234
+ if (!val[i] || !val[i].includes(values[i])) return false
2201
2235
  }
2202
- return true;
2203
- });
2204
- return equals(`all elements (${(new Locator(locator))}) to have attributes ${JSON.stringify(attributes)}`).assert(chunked.length, elemAmount);
2236
+ return true
2237
+ })
2238
+ return equals(`all elements (${new Locator(locator)}) to have attributes ${JSON.stringify(attributes)}`).assert(
2239
+ chunked.length,
2240
+ elemAmount,
2241
+ )
2205
2242
  }
2206
2243
 
2207
2244
  /**
@@ -2209,21 +2246,21 @@ class Playwright extends Helper {
2209
2246
  *
2210
2247
  */
2211
2248
  async dragSlider(locator, offsetX = 0) {
2212
- const src = await this._locateElement(locator);
2213
- assertElementExists(src, locator, 'Slider Element');
2249
+ const src = await this._locateElement(locator)
2250
+ assertElementExists(src, locator, 'Slider Element')
2214
2251
 
2215
2252
  // Note: Using clickablePoint private api because the .BoundingBox does not take into account iframe offsets!
2216
- const sliderSource = await clickablePoint(src);
2253
+ const sliderSource = await clickablePoint(src)
2217
2254
 
2218
2255
  // Drag start point
2219
- await this.page.mouse.move(sliderSource.x, sliderSource.y, { steps: 5 });
2220
- await this.page.mouse.down();
2256
+ await this.page.mouse.move(sliderSource.x, sliderSource.y, { steps: 5 })
2257
+ await this.page.mouse.down()
2221
2258
 
2222
2259
  // Drag destination
2223
- await this.page.mouse.move(sliderSource.x + offsetX, sliderSource.y, { steps: 5 });
2224
- await this.page.mouse.up();
2260
+ await this.page.mouse.move(sliderSource.x + offsetX, sliderSource.y, { steps: 5 })
2261
+ await this.page.mouse.up()
2225
2262
 
2226
- return this._waitForAction();
2263
+ return this._waitForAction()
2227
2264
  }
2228
2265
 
2229
2266
  /**
@@ -2231,10 +2268,10 @@ class Playwright extends Helper {
2231
2268
  *
2232
2269
  */
2233
2270
  async grabAttributeFrom(locator, attr) {
2234
- const attrs = await this.grabAttributeFromAll(locator, attr);
2235
- assertElementExists(attrs, locator);
2236
- this.debugSection('Attribute', attrs[0]);
2237
- return attrs[0];
2271
+ const attrs = await this.grabAttributeFromAll(locator, attr)
2272
+ assertElementExists(attrs, locator)
2273
+ this.debugSection('Attribute', attrs[0])
2274
+ return attrs[0]
2238
2275
  }
2239
2276
 
2240
2277
  /**
@@ -2242,15 +2279,15 @@ class Playwright extends Helper {
2242
2279
  *
2243
2280
  */
2244
2281
  async grabAttributeFromAll(locator, attr) {
2245
- const els = await this._locate(locator);
2246
- this.debug(`Matched ${els.length} elements`);
2247
- const array = [];
2282
+ const els = await this._locate(locator)
2283
+ this.debug(`Matched ${els.length} elements`)
2284
+ const array = []
2248
2285
 
2249
2286
  for (let index = 0; index < els.length; index++) {
2250
- array.push(await els[index].getAttribute(attr));
2287
+ array.push(await els[index].getAttribute(attr))
2251
2288
  }
2252
2289
 
2253
- return array;
2290
+ return array
2254
2291
  }
2255
2292
 
2256
2293
  /**
@@ -2258,43 +2295,43 @@ class Playwright extends Helper {
2258
2295
  *
2259
2296
  */
2260
2297
  async saveElementScreenshot(locator, fileName) {
2261
- const outputFile = screenshotOutputFolder(fileName);
2298
+ const outputFile = screenshotOutputFolder(fileName)
2262
2299
 
2263
- const res = await this._locateElement(locator);
2264
- assertElementExists(res, locator);
2265
- const elem = res;
2266
- this.debug(`Screenshot of ${(new Locator(locator))} element has been saved to ${outputFile}`);
2267
- return elem.screenshot({ path: outputFile, type: 'png' });
2300
+ const res = await this._locateElement(locator)
2301
+ assertElementExists(res, locator)
2302
+ const elem = res
2303
+ this.debug(`Screenshot of ${new Locator(locator)} element has been saved to ${outputFile}`)
2304
+ return elem.screenshot({ path: outputFile, type: 'png' })
2268
2305
  }
2269
2306
 
2270
2307
  /**
2271
2308
  * {{> saveScreenshot }}
2272
2309
  */
2273
2310
  async saveScreenshot(fileName, fullPage) {
2274
- const fullPageOption = fullPage || this.options.fullPageScreenshots;
2275
- let outputFile = screenshotOutputFolder(fileName);
2311
+ const fullPageOption = fullPage || this.options.fullPageScreenshots
2312
+ let outputFile = screenshotOutputFolder(fileName)
2276
2313
 
2277
- this.debug(`Screenshot is saving to ${outputFile}`);
2314
+ this.debug(`Screenshot is saving to ${outputFile}`)
2278
2315
 
2279
2316
  await this.page.screenshot({
2280
2317
  path: outputFile,
2281
2318
  fullPage: fullPageOption,
2282
2319
  type: 'png',
2283
- });
2320
+ })
2284
2321
 
2285
2322
  if (this.activeSessionName) {
2286
2323
  for (const sessionName in this.sessionPages) {
2287
- const activeSessionPage = this.sessionPages[sessionName];
2288
- outputFile = screenshotOutputFolder(`${sessionName}_${fileName}`);
2324
+ const activeSessionPage = this.sessionPages[sessionName]
2325
+ outputFile = screenshotOutputFolder(`${sessionName}_${fileName}`)
2289
2326
 
2290
- this.debug(`${sessionName} - Screenshot is saving to ${outputFile}`);
2327
+ this.debug(`${sessionName} - Screenshot is saving to ${outputFile}`)
2291
2328
 
2292
2329
  if (activeSessionPage) {
2293
2330
  await activeSessionPage.screenshot({
2294
2331
  path: outputFile,
2295
2332
  fullPage: fullPageOption,
2296
2333
  type: 'png',
2297
- });
2334
+ })
2298
2335
  }
2299
2336
  }
2300
2337
  }
@@ -2318,20 +2355,23 @@ class Playwright extends Helper {
2318
2355
  * @returns {Promise<object>} response
2319
2356
  */
2320
2357
  async makeApiRequest(method, url, options) {
2321
- method = method.toLowerCase();
2322
- const allowedMethods = ['get', 'post', 'patch', 'head', 'fetch', 'delete'];
2358
+ method = method.toLowerCase()
2359
+ const allowedMethods = ['get', 'post', 'patch', 'head', 'fetch', 'delete']
2323
2360
  if (!allowedMethods.includes(method)) {
2324
- throw new Error(`Method ${method} is not allowed, use the one from a list ${allowedMethods} or switch to using REST helper`);
2361
+ throw new Error(
2362
+ `Method ${method} is not allowed, use the one from a list ${allowedMethods} or switch to using REST helper`,
2363
+ )
2325
2364
  }
2326
2365
 
2327
- if (url.startsWith('/')) { // local url
2328
- url = this.options.url + url;
2329
- this.debugSection('URL', url);
2366
+ if (url.startsWith('/')) {
2367
+ // local url
2368
+ url = this.options.url + url
2369
+ this.debugSection('URL', url)
2330
2370
  }
2331
2371
 
2332
- const response = await this.page.request[method](url, options);
2333
- this.debugSection('Status', response.status());
2334
- this.debugSection('Response', await response.text());
2372
+ const response = await this.page.request[method](url, options)
2373
+ this.debugSection('Status', response.status())
2374
+ this.debugSection('Response', await response.text())
2335
2375
 
2336
2376
  // hook to allow JSON response handle this
2337
2377
  if (this.config.onResponse) {
@@ -2340,68 +2380,83 @@ class Playwright extends Helper {
2340
2380
  status: response.status(),
2341
2381
  statusText: response.statusText(),
2342
2382
  headers: response.headers(),
2343
- };
2344
- this.config.onResponse(axiosResponse);
2383
+ }
2384
+ this.config.onResponse(axiosResponse)
2345
2385
  }
2346
2386
 
2347
- return response;
2387
+ return response
2348
2388
  }
2349
2389
 
2350
2390
  async _failed(test) {
2351
- await this._withinEnd();
2391
+ await this._withinEnd()
2352
2392
 
2353
2393
  if (!test.artifacts) {
2354
- test.artifacts = {};
2394
+ test.artifacts = {}
2355
2395
  }
2356
2396
 
2357
2397
  if (this.options.recordVideo && this.page && this.page.video()) {
2358
- test.artifacts.video = await saveVideoForPage(this.page, `${test.title}.failed`);
2398
+ test.artifacts.video = saveVideoForPage(this.page, `${test.title}.failed`)
2359
2399
  for (const sessionName in this.sessionPages) {
2360
- test.artifacts[`video_${sessionName}`] = await saveVideoForPage(this.sessionPages[sessionName], `${test.title}_${sessionName}.failed`);
2400
+ test.artifacts[`video_${sessionName}`] = saveVideoForPage(
2401
+ this.sessionPages[sessionName],
2402
+ `${test.title}_${sessionName}.failed`,
2403
+ )
2361
2404
  }
2362
2405
  }
2363
2406
 
2364
2407
  if (this.options.trace) {
2365
- test.artifacts.trace = await saveTraceForContext(this.browserContext, `${test.title}.failed`);
2408
+ test.artifacts.trace = await saveTraceForContext(this.browserContext, `${test.title}.failed`)
2366
2409
  for (const sessionName in this.sessionPages) {
2367
- if (!this.sessionPages[sessionName].context) continue;
2368
- test.artifacts[`trace_${sessionName}`] = await saveTraceForContext(this.sessionPages[sessionName].context, `${test.title}_${sessionName}.failed`);
2410
+ if (!this.sessionPages[sessionName].context) continue
2411
+ test.artifacts[`trace_${sessionName}`] = await saveTraceForContext(
2412
+ this.sessionPages[sessionName].context,
2413
+ `${test.title}_${sessionName}.failed`,
2414
+ )
2369
2415
  }
2370
2416
  }
2371
2417
 
2372
2418
  if (this.options.recordHar) {
2373
- test.artifacts.har = this.currentRunningTest.artifacts.har;
2419
+ test.artifacts.har = this.currentRunningTest.artifacts.har
2374
2420
  }
2375
2421
  }
2376
2422
 
2377
2423
  async _passed(test) {
2378
2424
  if (this.options.recordVideo && this.page && this.page.video()) {
2379
2425
  if (this.options.keepVideoForPassedTests) {
2380
- test.artifacts.video = await saveVideoForPage(this.page, `${test.title}.passed`);
2426
+ test.artifacts.video = saveVideoForPage(this.page, `${test.title}.passed`)
2381
2427
  for (const sessionName of Object.keys(this.sessionPages)) {
2382
- test.artifacts[`video_${sessionName}`] = await saveVideoForPage(this.sessionPages[sessionName], `${test.title}_${sessionName}.passed`);
2428
+ test.artifacts[`video_${sessionName}`] = saveVideoForPage(
2429
+ this.sessionPages[sessionName],
2430
+ `${test.title}_${sessionName}.passed`,
2431
+ )
2383
2432
  }
2384
2433
  } else {
2385
- this.page.video().delete().catch(e => {});
2434
+ this.page
2435
+ .video()
2436
+ .delete()
2437
+ .catch((e) => {})
2386
2438
  }
2387
2439
  }
2388
2440
 
2389
2441
  if (this.options.trace) {
2390
2442
  if (this.options.keepTraceForPassedTests) {
2391
2443
  if (this.options.trace) {
2392
- test.artifacts.trace = await saveTraceForContext(this.browserContext, `${test.title}.passed`);
2444
+ test.artifacts.trace = await saveTraceForContext(this.browserContext, `${test.title}.passed`)
2393
2445
  for (const sessionName in this.sessionPages) {
2394
- if (!this.sessionPages[sessionName].context) continue;
2395
- test.artifacts[`trace_${sessionName}`] = await saveTraceForContext(this.sessionPages[sessionName].context, `${test.title}_${sessionName}.passed`);
2446
+ if (!this.sessionPages[sessionName].context) continue
2447
+ test.artifacts[`trace_${sessionName}`] = await saveTraceForContext(
2448
+ this.sessionPages[sessionName].context,
2449
+ `${test.title}_${sessionName}.passed`,
2450
+ )
2396
2451
  }
2397
2452
  }
2398
2453
  } else {
2399
- await this.browserContext.tracing.stop();
2454
+ await this.browserContext.tracing.stop()
2400
2455
  }
2401
2456
  }
2402
2457
 
2403
2458
  if (this.options.recordHar) {
2404
- test.artifacts.har = this.currentRunningTest.artifacts.har;
2459
+ test.artifacts.har = this.currentRunningTest.artifacts.har
2405
2460
  }
2406
2461
  }
2407
2462
 
@@ -2409,62 +2464,99 @@ class Playwright extends Helper {
2409
2464
  * {{> wait }}
2410
2465
  */
2411
2466
  async wait(sec) {
2412
- return new Promise(((done) => {
2413
- setTimeout(done, sec * 1000);
2414
- }));
2467
+ return new Promise((done) => {
2468
+ setTimeout(done, sec * 1000)
2469
+ })
2415
2470
  }
2416
2471
 
2417
2472
  /**
2418
2473
  * {{> waitForEnabled }}
2419
2474
  */
2420
2475
  async waitForEnabled(locator, sec) {
2421
- const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
2422
- locator = new Locator(locator, 'css');
2423
- const matcher = await this.context;
2424
- let waiter;
2425
- const context = await this._getContext();
2476
+ const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
2477
+ locator = new Locator(locator, 'css')
2478
+
2479
+ let waiter
2480
+ const context = await this._getContext()
2426
2481
  if (!locator.isXPath()) {
2427
2482
  const valueFn = function ([locator]) {
2428
- return Array.from(document.querySelectorAll(locator)).filter(el => !el.disabled).length > 0;
2429
- };
2430
- waiter = context.waitForFunction(valueFn, [locator.value], { timeout: waitTimeout });
2483
+ return Array.from(document.querySelectorAll(locator)).filter((el) => !el.disabled).length > 0
2484
+ }
2485
+ waiter = context.waitForFunction(valueFn, [locator.value], { timeout: waitTimeout })
2431
2486
  } else {
2432
2487
  const enabledFn = function ([locator, $XPath]) {
2433
- eval($XPath); // eslint-disable-line no-eval
2434
- return $XPath(null, locator).filter(el => !el.disabled).length > 0;
2435
- };
2436
- waiter = context.waitForFunction(enabledFn, [locator.value, $XPath.toString()], { timeout: waitTimeout });
2488
+ eval($XPath) // eslint-disable-line no-eval
2489
+ return $XPath(null, locator).filter((el) => !el.disabled).length > 0
2490
+ }
2491
+ waiter = context.waitForFunction(enabledFn, [locator.value, $XPath.toString()], { timeout: waitTimeout })
2492
+ }
2493
+ return waiter.catch((err) => {
2494
+ throw new Error(
2495
+ `element (${locator.toString()}) still not enabled after ${waitTimeout / 1000} sec\n${err.message}`,
2496
+ )
2497
+ })
2498
+ }
2499
+
2500
+ /**
2501
+ * {{> waitForDisabled }}
2502
+ */
2503
+ async waitForDisabled(locator, sec) {
2504
+ const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
2505
+ locator = new Locator(locator, 'css')
2506
+
2507
+ let waiter
2508
+ const context = await this._getContext()
2509
+ if (!locator.isXPath()) {
2510
+ const valueFn = function ([locator]) {
2511
+ return Array.from(document.querySelectorAll(locator)).filter((el) => el.disabled).length > 0
2512
+ }
2513
+ waiter = context.waitForFunction(valueFn, [locator.value], { timeout: waitTimeout })
2514
+ } else {
2515
+ const disabledFn = function ([locator, $XPath]) {
2516
+ eval($XPath) // eslint-disable-line no-eval
2517
+ return $XPath(null, locator).filter((el) => el.disabled).length > 0
2518
+ }
2519
+ waiter = context.waitForFunction(disabledFn, [locator.value, $XPath.toString()], { timeout: waitTimeout })
2437
2520
  }
2438
2521
  return waiter.catch((err) => {
2439
- throw new Error(`element (${locator.toString()}) still not enabled after ${waitTimeout / 1000} sec\n${err.message}`);
2440
- });
2522
+ throw new Error(
2523
+ `element (${locator.toString()}) is still enabled after ${waitTimeout / 1000} sec\n${err.message}`,
2524
+ )
2525
+ })
2441
2526
  }
2442
2527
 
2443
2528
  /**
2444
2529
  * {{> waitForValue }}
2445
2530
  */
2446
2531
  async waitForValue(field, value, sec) {
2447
- const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
2448
- const locator = new Locator(field, 'css');
2449
- const matcher = await this.context;
2450
- let waiter;
2451
- const context = await this._getContext();
2532
+ const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
2533
+ const locator = new Locator(field, 'css')
2534
+ const matcher = await this.context
2535
+ let waiter
2536
+ const context = await this._getContext()
2452
2537
  if (!locator.isXPath()) {
2453
2538
  const valueFn = function ([locator, value]) {
2454
- return Array.from(document.querySelectorAll(locator)).filter(el => (el.value || '').indexOf(value) !== -1).length > 0;
2455
- };
2456
- waiter = context.waitForFunction(valueFn, [locator.value, value], { timeout: waitTimeout });
2539
+ return (
2540
+ Array.from(document.querySelectorAll(locator)).filter((el) => (el.value || '').indexOf(value) !== -1).length >
2541
+ 0
2542
+ )
2543
+ }
2544
+ waiter = context.waitForFunction(valueFn, [locator.value, value], { timeout: waitTimeout })
2457
2545
  } else {
2458
2546
  const valueFn = function ([locator, $XPath, value]) {
2459
- eval($XPath); // eslint-disable-line no-eval
2460
- return $XPath(null, locator).filter(el => (el.value || '').indexOf(value) !== -1).length > 0;
2461
- };
2462
- waiter = context.waitForFunction(valueFn, [locator.value, $XPath.toString(), value], { timeout: waitTimeout });
2547
+ eval($XPath) // eslint-disable-line no-eval
2548
+ return $XPath(null, locator).filter((el) => (el.value || '').indexOf(value) !== -1).length > 0
2549
+ }
2550
+ waiter = context.waitForFunction(valueFn, [locator.value, $XPath.toString(), value], {
2551
+ timeout: waitTimeout,
2552
+ })
2463
2553
  }
2464
2554
  return waiter.catch((err) => {
2465
- const loc = locator.toString();
2466
- throw new Error(`element (${loc}) is not in DOM or there is no element(${loc}) with value "${value}" after ${waitTimeout / 1000} sec\n${err.message}`);
2467
- });
2555
+ const loc = locator.toString()
2556
+ throw new Error(
2557
+ `element (${loc}) is not in DOM or there is no element(${loc}) with value "${value}" after ${waitTimeout / 1000} sec\n${err.message}`,
2558
+ )
2559
+ })
2468
2560
  }
2469
2561
 
2470
2562
  /**
@@ -2472,38 +2564,44 @@ class Playwright extends Helper {
2472
2564
  *
2473
2565
  */
2474
2566
  async waitNumberOfVisibleElements(locator, num, sec) {
2475
- const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
2476
- locator = new Locator(locator, 'css');
2567
+ const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
2568
+ locator = new Locator(locator, 'css')
2477
2569
 
2478
- let waiter;
2479
- const context = await this._getContext();
2570
+ let waiter
2571
+ const context = await this._getContext()
2480
2572
  if (locator.isCSS()) {
2481
2573
  const visibleFn = function ([locator, num]) {
2482
- const els = document.querySelectorAll(locator);
2574
+ const els = document.querySelectorAll(locator)
2483
2575
  if (!els || els.length === 0) {
2484
- return false;
2576
+ return false
2485
2577
  }
2486
- return Array.prototype.filter.call(els, el => el.offsetParent !== null).length === num;
2487
- };
2488
- waiter = context.waitForFunction(visibleFn, [locator.value, num], { timeout: waitTimeout });
2578
+ return Array.prototype.filter.call(els, (el) => el.offsetParent !== null).length === num
2579
+ }
2580
+ waiter = context.waitForFunction(visibleFn, [locator.value, num], { timeout: waitTimeout })
2489
2581
  } else {
2490
2582
  const visibleFn = function ([locator, $XPath, num]) {
2491
- eval($XPath); // eslint-disable-line no-eval
2492
- return $XPath(null, locator).filter(el => el.offsetParent !== null).length === num;
2493
- };
2494
- waiter = context.waitForFunction(visibleFn, [locator.value, $XPath.toString(), num], { timeout: waitTimeout });
2583
+ eval($XPath) // eslint-disable-line no-eval
2584
+ return $XPath(null, locator).filter((el) => el.offsetParent !== null).length === num
2585
+ }
2586
+ waiter = context.waitForFunction(visibleFn, [locator.value, $XPath.toString(), num], {
2587
+ timeout: waitTimeout,
2588
+ })
2495
2589
  }
2496
2590
  return waiter.catch((err) => {
2497
- throw new Error(`The number of elements (${locator.toString()}) is not ${num} after ${waitTimeout / 1000} sec\n${err.message}`);
2498
- });
2591
+ throw new Error(
2592
+ `The number of elements (${locator.toString()}) is not ${num} after ${waitTimeout / 1000} sec\n${err.message}`,
2593
+ )
2594
+ })
2499
2595
  }
2500
2596
 
2501
2597
  /**
2502
2598
  * {{> waitForClickable }}
2503
2599
  */
2504
2600
  async waitForClickable(locator, waitTimeout) {
2505
- console.log('I.waitForClickable is DEPRECATED: This is no longer needed, Playwright automatically waits for element to be clickable');
2506
- console.log('Remove usage of this function');
2601
+ console.log(
2602
+ 'I.waitForClickable is DEPRECATED: This is no longer needed, Playwright automatically waits for element to be clickable',
2603
+ )
2604
+ console.log('Remove usage of this function')
2507
2605
  }
2508
2606
 
2509
2607
  /**
@@ -2511,14 +2609,16 @@ class Playwright extends Helper {
2511
2609
  *
2512
2610
  */
2513
2611
  async waitForElement(locator, sec) {
2514
- const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
2515
- locator = new Locator(locator, 'css');
2612
+ const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
2613
+ locator = new Locator(locator, 'css')
2516
2614
 
2517
- const context = await this._getContext();
2615
+ const context = await this._getContext()
2518
2616
  try {
2519
- await context.locator(buildLocatorString(locator)).first().waitFor({ timeout: waitTimeout, state: 'attached' });
2617
+ await context.locator(buildLocatorString(locator)).first().waitFor({ timeout: waitTimeout, state: 'attached' })
2520
2618
  } catch (e) {
2521
- throw new Error(`element (${locator.toString()}) still not present on page after ${waitTimeout / 1000} sec\n${e.message}`);
2619
+ throw new Error(
2620
+ `element (${locator.toString()}) still not present on page after ${waitTimeout / 1000} sec\n${e.message}`,
2621
+ )
2522
2622
  }
2523
2623
  }
2524
2624
 
@@ -2528,28 +2628,28 @@ class Playwright extends Helper {
2528
2628
  * {{> waitForVisible }}
2529
2629
  */
2530
2630
  async waitForVisible(locator, sec) {
2531
- const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
2532
- locator = new Locator(locator, 'css');
2533
- const context = await this._getContext();
2534
- let count = 0;
2631
+ const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
2632
+ locator = new Locator(locator, 'css')
2633
+ const context = await this._getContext()
2634
+ let count = 0
2535
2635
 
2536
2636
  // we have this as https://github.com/microsoft/playwright/issues/26829 is not yet implemented
2537
- let waiter;
2637
+ let waiter
2538
2638
  if (this.frame) {
2539
2639
  do {
2540
- waiter = await this.frame.locator(buildLocatorString(locator)).first().isVisible();
2541
- await this.wait(1);
2542
- count += 1000;
2543
- if (waiter) break;
2544
- } while (count <= waitTimeout);
2640
+ waiter = await this.frame.locator(buildLocatorString(locator)).first().isVisible()
2641
+ await this.wait(1)
2642
+ count += 1000
2643
+ if (waiter) break
2644
+ } while (count <= waitTimeout)
2545
2645
 
2546
- if (!waiter) throw new Error(`element (${locator.toString()}) still not visible after ${waitTimeout / 1000} sec.`);
2646
+ if (!waiter) throw new Error(`element (${locator.toString()}) still not visible after ${waitTimeout / 1000} sec.`)
2547
2647
  }
2548
2648
 
2549
2649
  try {
2550
- await context.locator(buildLocatorString(locator)).first().waitFor({ timeout: waitTimeout, state: 'visible' });
2650
+ await context.locator(buildLocatorString(locator)).first().waitFor({ timeout: waitTimeout, state: 'visible' })
2551
2651
  } catch (e) {
2552
- throw new Error(`element (${locator.toString()}) still not visible after ${waitTimeout / 1000} sec\n${e.message}`);
2652
+ throw new Error(`element (${locator.toString()}) still not visible after ${waitTimeout / 1000} sec\n${e.message}`)
2553
2653
  }
2554
2654
  }
2555
2655
 
@@ -2557,29 +2657,29 @@ class Playwright extends Helper {
2557
2657
  * {{> waitForInvisible }}
2558
2658
  */
2559
2659
  async waitForInvisible(locator, sec) {
2560
- const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
2561
- locator = new Locator(locator, 'css');
2562
- const context = await this._getContext();
2563
- let waiter;
2564
- let count = 0;
2660
+ const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
2661
+ locator = new Locator(locator, 'css')
2662
+ const context = await this._getContext()
2663
+ let waiter
2664
+ let count = 0
2565
2665
 
2566
2666
  // we have this as https://github.com/microsoft/playwright/issues/26829 is not yet implemented
2567
2667
  if (this.frame) {
2568
2668
  do {
2569
- waiter = await this.frame.locator(buildLocatorString(locator)).first().isHidden();
2570
- await this.wait(1);
2571
- count += 1000;
2572
- if (waiter) break;
2573
- } while (count <= waitTimeout);
2669
+ waiter = await this.frame.locator(buildLocatorString(locator)).first().isHidden()
2670
+ await this.wait(1)
2671
+ count += 1000
2672
+ if (waiter) break
2673
+ } while (count <= waitTimeout)
2574
2674
 
2575
- if (!waiter) throw new Error(`element (${locator.toString()}) still visible after ${waitTimeout / 1000} sec.`);
2576
- return;
2675
+ if (!waiter) throw new Error(`element (${locator.toString()}) still visible after ${waitTimeout / 1000} sec.`)
2676
+ return
2577
2677
  }
2578
2678
 
2579
2679
  try {
2580
- await context.locator(buildLocatorString(locator)).first().waitFor({ timeout: waitTimeout, state: 'hidden' });
2680
+ await context.locator(buildLocatorString(locator)).first().waitFor({ timeout: waitTimeout, state: 'hidden' })
2581
2681
  } catch (e) {
2582
- throw new Error(`element (${locator.toString()}) still visible after ${waitTimeout / 1000} sec\n${e.message}`);
2682
+ throw new Error(`element (${locator.toString()}) still visible after ${waitTimeout / 1000} sec\n${e.message}`)
2583
2683
  }
2584
2684
  }
2585
2685
 
@@ -2587,143 +2687,171 @@ class Playwright extends Helper {
2587
2687
  * {{> waitToHide }}
2588
2688
  */
2589
2689
  async waitToHide(locator, sec) {
2590
- const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
2591
- locator = new Locator(locator, 'css');
2592
- const context = await this._getContext();
2593
- let waiter;
2594
- let count = 0;
2690
+ const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
2691
+ locator = new Locator(locator, 'css')
2692
+ const context = await this._getContext()
2693
+ let waiter
2694
+ let count = 0
2595
2695
 
2596
2696
  // we have this as https://github.com/microsoft/playwright/issues/26829 is not yet implemented
2597
2697
  if (this.frame) {
2598
2698
  do {
2599
- waiter = await this.frame.locator(buildLocatorString(locator)).first().isHidden();
2600
- await this.wait(1);
2601
- count += 1000;
2602
- if (waiter) break;
2603
- } while (count <= waitTimeout);
2699
+ waiter = await this.frame.locator(buildLocatorString(locator)).first().isHidden()
2700
+ await this.wait(1)
2701
+ count += 1000
2702
+ if (waiter) break
2703
+ } while (count <= waitTimeout)
2604
2704
 
2605
- if (!waiter) throw new Error(`element (${locator.toString()}) still not hidden after ${waitTimeout / 1000} sec.`);
2606
- return;
2705
+ if (!waiter) throw new Error(`element (${locator.toString()}) still not hidden after ${waitTimeout / 1000} sec.`)
2706
+ return
2607
2707
  }
2608
2708
 
2609
- return context.locator(buildLocatorString(locator)).first().waitFor({ timeout: waitTimeout, state: 'hidden' }).catch((err) => {
2610
- throw new Error(`element (${locator.toString()}) still not hidden after ${waitTimeout / 1000} sec\n${err.message}`);
2611
- });
2709
+ return context
2710
+ .locator(buildLocatorString(locator))
2711
+ .first()
2712
+ .waitFor({ timeout: waitTimeout, state: 'hidden' })
2713
+ .catch((err) => {
2714
+ throw new Error(
2715
+ `element (${locator.toString()}) still not hidden after ${waitTimeout / 1000} sec\n${err.message}`,
2716
+ )
2717
+ })
2612
2718
  }
2613
2719
 
2614
2720
  /**
2615
2721
  * {{> waitForNumberOfTabs }}
2616
2722
  */
2617
2723
  async waitForNumberOfTabs(expectedTabs, sec) {
2618
- const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
2619
- let currentTabs;
2620
- let count = 0;
2724
+ const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
2725
+ let currentTabs
2726
+ let count = 0
2621
2727
 
2622
2728
  do {
2623
- currentTabs = await this.grabNumberOfOpenTabs();
2624
- await this.wait(1);
2625
- count += 1000;
2626
- if (currentTabs >= expectedTabs) return;
2627
- } while (count <= waitTimeout);
2729
+ currentTabs = await this.grabNumberOfOpenTabs()
2730
+ await this.wait(1)
2731
+ count += 1000
2732
+ if (currentTabs >= expectedTabs) return
2733
+ } while (count <= waitTimeout)
2628
2734
 
2629
- throw new Error(`Expected ${expectedTabs} tabs are not met after ${waitTimeout / 1000} sec.`);
2735
+ throw new Error(`Expected ${expectedTabs} tabs are not met after ${waitTimeout / 1000} sec.`)
2630
2736
  }
2631
2737
 
2632
2738
  async _getContext() {
2633
- if (this.context && this.context.constructor.name === 'FrameLocator') {
2634
- return this.context;
2739
+ if ((this.context && this.context.constructor.name === 'FrameLocator') || this.context) {
2740
+ return this.context
2635
2741
  }
2636
- return this.page;
2742
+ return this.page
2637
2743
  }
2638
2744
 
2639
2745
  /**
2640
2746
  * {{> waitInUrl }}
2641
2747
  */
2642
2748
  async waitInUrl(urlPart, sec = null) {
2643
- const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
2644
-
2645
- return this.page.waitForFunction((urlPart) => {
2646
- const currUrl = decodeURIComponent(decodeURIComponent(decodeURIComponent(window.location.href)));
2647
- return currUrl.indexOf(urlPart) > -1;
2648
- }, urlPart, { timeout: waitTimeout }).catch(async (e) => {
2649
- const currUrl = await this._getPageUrl(); // Required because the waitForFunction can't return data.
2650
- if (/Timeout/i.test(e.message)) {
2651
- throw new Error(`expected url to include ${urlPart}, but found ${currUrl}`);
2652
- } else {
2653
- throw e;
2654
- }
2655
- });
2749
+ const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
2750
+
2751
+ return this.page
2752
+ .waitForFunction(
2753
+ (urlPart) => {
2754
+ const currUrl = decodeURIComponent(decodeURIComponent(decodeURIComponent(window.location.href)))
2755
+ return currUrl.indexOf(urlPart) > -1
2756
+ },
2757
+ urlPart,
2758
+ { timeout: waitTimeout },
2759
+ )
2760
+ .catch(async (e) => {
2761
+ const currUrl = await this._getPageUrl() // Required because the waitForFunction can't return data.
2762
+ if (/Timeout/i.test(e.message)) {
2763
+ throw new Error(`expected url to include ${urlPart}, but found ${currUrl}`)
2764
+ } else {
2765
+ throw e
2766
+ }
2767
+ })
2656
2768
  }
2657
2769
 
2658
2770
  /**
2659
2771
  * {{> waitUrlEquals }}
2660
2772
  */
2661
2773
  async waitUrlEquals(urlPart, sec = null) {
2662
- const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
2774
+ const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
2663
2775
 
2664
- const baseUrl = this.options.url;
2776
+ const baseUrl = this.options.url
2665
2777
  if (urlPart.indexOf('http') < 0) {
2666
- urlPart = baseUrl + urlPart;
2667
- }
2668
-
2669
- return this.page.waitForFunction((urlPart) => {
2670
- const currUrl = decodeURIComponent(decodeURIComponent(decodeURIComponent(window.location.href)));
2671
- return currUrl.indexOf(urlPart) > -1;
2672
- }, urlPart, { timeout: waitTimeout }).catch(async (e) => {
2673
- const currUrl = await this._getPageUrl(); // Required because the waitForFunction can't return data.
2674
- if (/Timeout/i.test(e.message)) {
2675
- throw new Error(`expected url to be ${urlPart}, but found ${currUrl}`);
2676
- } else {
2677
- throw e;
2678
- }
2679
- });
2778
+ urlPart = baseUrl + urlPart
2779
+ }
2780
+
2781
+ return this.page
2782
+ .waitForFunction(
2783
+ (urlPart) => {
2784
+ const currUrl = decodeURIComponent(decodeURIComponent(decodeURIComponent(window.location.href)))
2785
+ return currUrl.indexOf(urlPart) > -1
2786
+ },
2787
+ urlPart,
2788
+ { timeout: waitTimeout },
2789
+ )
2790
+ .catch(async (e) => {
2791
+ const currUrl = await this._getPageUrl() // Required because the waitForFunction can't return data.
2792
+ if (/Timeout/i.test(e.message)) {
2793
+ throw new Error(`expected url to be ${urlPart}, but found ${currUrl}`)
2794
+ } else {
2795
+ throw e
2796
+ }
2797
+ })
2680
2798
  }
2681
2799
 
2682
2800
  /**
2683
2801
  * {{> waitForText }}
2684
2802
  */
2685
2803
  async waitForText(text, sec = null, context = null) {
2686
- const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
2687
- const errorMessage = `Text "${text}" was not found on page after ${waitTimeout / 1000} sec.`;
2688
- let waiter;
2804
+ const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
2805
+ const errorMessage = `Text "${text}" was not found on page after ${waitTimeout / 1000} sec.`
2806
+ let waiter
2689
2807
 
2690
- const contextObject = await this._getContext();
2808
+ const contextObject = await this._getContext()
2691
2809
 
2692
2810
  if (context) {
2693
- const locator = new Locator(context, 'css');
2811
+ const locator = new Locator(context, 'css')
2694
2812
  if (!locator.isXPath()) {
2695
2813
  try {
2696
- await contextObject.locator(`${locator.isCustom() ? `${locator.type}=${locator.value}` : locator.simplify()} >> text=${text}`).first().waitFor({ timeout: waitTimeout, state: 'visible' });
2814
+ await contextObject
2815
+ .locator(`${locator.isCustom() ? `${locator.type}=${locator.value}` : locator.simplify()} >> text=${text}`)
2816
+ .first()
2817
+ .waitFor({ timeout: waitTimeout, state: 'visible' })
2697
2818
  } catch (e) {
2698
- throw new Error(`${errorMessage}\n${e.message}`);
2819
+ throw new Error(`${errorMessage}\n${e.message}`)
2699
2820
  }
2700
2821
  }
2701
2822
 
2702
2823
  if (locator.isXPath()) {
2703
2824
  try {
2704
- await contextObject.waitForFunction(([locator, text, $XPath]) => {
2705
- eval($XPath); // eslint-disable-line no-eval
2706
- const el = $XPath(null, locator);
2707
- if (!el.length) return false;
2708
- return el[0].innerText.indexOf(text) > -1;
2709
- }, [locator.value, text, $XPath.toString()], { timeout: waitTimeout });
2825
+ await contextObject.waitForFunction(
2826
+ ([locator, text, $XPath]) => {
2827
+ eval($XPath) // eslint-disable-line no-eval
2828
+ const el = $XPath(null, locator)
2829
+ if (!el.length) return false
2830
+ return el[0].innerText.indexOf(text) > -1
2831
+ },
2832
+ [locator.value, text, $XPath.toString()],
2833
+ { timeout: waitTimeout },
2834
+ )
2710
2835
  } catch (e) {
2711
- throw new Error(`${errorMessage}\n${e.message}`);
2836
+ throw new Error(`${errorMessage}\n${e.message}`)
2712
2837
  }
2713
2838
  }
2714
2839
  } else {
2715
2840
  // we have this as https://github.com/microsoft/playwright/issues/26829 is not yet implemented
2716
- // eslint-disable-next-line no-lonely-if
2717
- const _contextObject = this.frame ? this.frame : contextObject;
2718
- let count = 0;
2841
+
2842
+ const _contextObject = this.frame ? this.frame : contextObject
2843
+ let count = 0
2719
2844
  do {
2720
- waiter = await _contextObject.locator(`:has-text("${text}")`).first().isVisible();
2721
- if (waiter) break;
2722
- await this.wait(1);
2723
- count += 1000;
2724
- } while (count <= waitTimeout);
2845
+ waiter = await _contextObject
2846
+ .locator(`:has-text(${JSON.stringify(text)})`)
2847
+ .first()
2848
+ .isVisible()
2849
+ if (waiter) break
2850
+ await this.wait(1)
2851
+ count += 1000
2852
+ } while (count <= waitTimeout)
2725
2853
 
2726
- if (!waiter) throw new Error(`${errorMessage}`);
2854
+ if (!waiter) throw new Error(`${errorMessage}`)
2727
2855
  }
2728
2856
  }
2729
2857
 
@@ -2739,8 +2867,8 @@ class Playwright extends Helper {
2739
2867
  * @param {?number} [sec=null] seconds to wait
2740
2868
  */
2741
2869
  async waitForRequest(urlOrPredicate, sec = null) {
2742
- const timeout = sec ? sec * 1000 : this.options.waitForTimeout;
2743
- return this.page.waitForRequest(urlOrPredicate, { timeout });
2870
+ const timeout = sec ? sec * 1000 : this.options.waitForTimeout
2871
+ return this.page.waitForRequest(urlOrPredicate, { timeout })
2744
2872
  }
2745
2873
 
2746
2874
  /**
@@ -2755,8 +2883,8 @@ class Playwright extends Helper {
2755
2883
  * @param {?number} [sec=null] number of seconds to wait
2756
2884
  */
2757
2885
  async waitForResponse(urlOrPredicate, sec = null) {
2758
- const timeout = sec ? sec * 1000 : this.options.waitForTimeout;
2759
- return this.page.waitForResponse(urlOrPredicate, { timeout });
2886
+ const timeout = sec ? sec * 1000 : this.options.waitForTimeout
2887
+ return this.page.waitForResponse(urlOrPredicate, { timeout })
2760
2888
  }
2761
2889
 
2762
2890
  /**
@@ -2766,51 +2894,51 @@ class Playwright extends Helper {
2766
2894
  if (Number.isInteger(locator)) {
2767
2895
  // Select by frame index of current context
2768
2896
 
2769
- let childFrames = null;
2897
+ let childFrames = null
2770
2898
  if (this.context && typeof this.context.childFrames === 'function') {
2771
- childFrames = this.context.childFrames();
2899
+ childFrames = this.context.childFrames()
2772
2900
  } else {
2773
- childFrames = this.page.mainFrame().childFrames();
2901
+ childFrames = this.page.mainFrame().childFrames()
2774
2902
  }
2775
2903
 
2776
2904
  if (locator >= 0 && locator < childFrames.length) {
2777
- this.context = await this.page.frameLocator('iframe').nth(locator);
2778
- this.contextLocator = locator;
2905
+ this.context = await this.page.frameLocator('iframe').nth(locator)
2906
+ this.contextLocator = locator
2779
2907
  } else {
2780
- throw new Error('Element #invalidIframeSelector was not found by text|CSS|XPath');
2908
+ throw new Error('Element #invalidIframeSelector was not found by text|CSS|XPath')
2781
2909
  }
2782
- return;
2910
+ return
2783
2911
  }
2784
2912
 
2785
2913
  if (!locator) {
2786
- this.context = this.page;
2787
- this.contextLocator = null;
2788
- this.frame = null;
2789
- return;
2914
+ this.context = this.page
2915
+ this.contextLocator = null
2916
+ this.frame = null
2917
+ return
2790
2918
  }
2791
2919
 
2792
2920
  // iframe by selector
2793
- locator = buildLocatorString(new Locator(locator, 'css'));
2794
- const frame = await this._locateElement(locator);
2921
+ locator = buildLocatorString(new Locator(locator, 'css'))
2922
+ const frame = await this._locateElement(locator)
2795
2923
 
2796
2924
  if (!frame) {
2797
- throw new Error(`Frame ${JSON.stringify(locator)} was not found by text|CSS|XPath`);
2925
+ throw new Error(`Frame ${JSON.stringify(locator)} was not found by text|CSS|XPath`)
2798
2926
  }
2799
2927
 
2800
2928
  if (this.frame) {
2801
- this.frame = await this.frame.frameLocator(locator);
2929
+ this.frame = await this.frame.frameLocator(locator)
2802
2930
  } else {
2803
- this.frame = await this.page.frameLocator(locator);
2931
+ this.frame = await this.page.frameLocator(locator)
2804
2932
  }
2805
2933
 
2806
- const contentFrame = this.frame;
2934
+ const contentFrame = this.frame
2807
2935
 
2808
2936
  if (contentFrame) {
2809
- this.context = contentFrame;
2810
- this.contextLocator = null;
2937
+ this.context = contentFrame
2938
+ this.contextLocator = null
2811
2939
  } else {
2812
- this.context = this.page.frame(this.page.frames()[1].name());
2813
- this.contextLocator = locator;
2940
+ this.context = this.page.frame(this.page.frames()[1].name())
2941
+ this.contextLocator = locator
2814
2942
  }
2815
2943
  }
2816
2944
 
@@ -2818,17 +2946,17 @@ class Playwright extends Helper {
2818
2946
  * {{> waitForFunction }}
2819
2947
  */
2820
2948
  async waitForFunction(fn, argsOrSec = null, sec = null) {
2821
- let args = [];
2949
+ let args = []
2822
2950
  if (argsOrSec) {
2823
2951
  if (Array.isArray(argsOrSec)) {
2824
- args = argsOrSec;
2952
+ args = argsOrSec
2825
2953
  } else if (typeof argsOrSec === 'number') {
2826
- sec = argsOrSec;
2954
+ sec = argsOrSec
2827
2955
  }
2828
2956
  }
2829
- const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
2830
- const context = await this._getContext();
2831
- return context.waitForFunction(fn, args, { timeout: waitTimeout });
2957
+ const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
2958
+ const context = await this._getContext()
2959
+ return context.waitForFunction(fn, args, { timeout: waitTimeout })
2832
2960
  }
2833
2961
 
2834
2962
  /**
@@ -2840,13 +2968,13 @@ class Playwright extends Helper {
2840
2968
  */
2841
2969
  async waitForNavigation(options = {}) {
2842
2970
  console.log(`waitForNavigation deprecated:
2843
- * This method is inherently racy, please use 'waitForURL' instead.`);
2971
+ * This method is inherently racy, please use 'waitForURL' instead.`)
2844
2972
  options = {
2845
2973
  timeout: this.options.getPageTimeout,
2846
2974
  waitUntil: this.options.waitForNavigation,
2847
2975
  ...options,
2848
- };
2849
- return this.page.waitForNavigation(options);
2976
+ }
2977
+ return this.page.waitForNavigation(options)
2850
2978
  }
2851
2979
 
2852
2980
  /**
@@ -2862,41 +2990,44 @@ class Playwright extends Helper {
2862
2990
  timeout: this.options.getPageTimeout,
2863
2991
  waitUntil: this.options.waitForNavigation,
2864
2992
  ...options,
2865
- };
2866
- return this.page.waitForURL(url, options);
2993
+ }
2994
+ return this.page.waitForURL(url, options)
2867
2995
  }
2868
2996
 
2869
2997
  async waitUntilExists(locator, sec) {
2870
2998
  console.log(`waitUntilExists deprecated:
2871
2999
  * use 'waitForElement' to wait for element to be attached
2872
- * use 'waitForDetached to wait for element to be removed'`);
2873
- return this.waitForDetached(locator, sec);
3000
+ * use 'waitForDetached to wait for element to be removed'`)
3001
+ return this.waitForDetached(locator, sec)
2874
3002
  }
2875
3003
 
2876
3004
  /**
2877
3005
  * {{> waitForDetached }}
2878
3006
  */
2879
3007
  async waitForDetached(locator, sec) {
2880
- const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
2881
- locator = new Locator(locator, 'css');
3008
+ const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
3009
+ locator = new Locator(locator, 'css')
2882
3010
 
2883
- let waiter;
2884
- const context = await this._getContext();
3011
+ let waiter
3012
+ const context = await this._getContext()
2885
3013
  if (!locator.isXPath()) {
2886
3014
  try {
2887
- await context.locator(`${locator.isCustom() ? `${locator.type}=${locator.value}` : locator.simplify()}`).first().waitFor({ timeout: waitTimeout, state: 'detached' });
3015
+ await context
3016
+ .locator(`${locator.isCustom() ? `${locator.type}=${locator.value}` : locator.simplify()}`)
3017
+ .first()
3018
+ .waitFor({ timeout: waitTimeout, state: 'detached' })
2888
3019
  } catch (e) {
2889
- throw new Error(`element (${locator.toString()}) still on page after ${waitTimeout / 1000} sec\n${e.message}`);
3020
+ throw new Error(`element (${locator.toString()}) still on page after ${waitTimeout / 1000} sec\n${e.message}`)
2890
3021
  }
2891
3022
  } else {
2892
3023
  const visibleFn = function ([locator, $XPath]) {
2893
- eval($XPath); // eslint-disable-line no-eval
2894
- return $XPath(null, locator).length === 0;
2895
- };
2896
- waiter = context.waitForFunction(visibleFn, [locator.value, $XPath.toString()], { timeout: waitTimeout });
3024
+ eval($XPath) // eslint-disable-line no-eval
3025
+ return $XPath(null, locator).length === 0
3026
+ }
3027
+ waiter = context.waitForFunction(visibleFn, [locator.value, $XPath.toString()], { timeout: waitTimeout })
2897
3028
  return waiter.catch((err) => {
2898
- throw new Error(`element (${locator.toString()}) still on page after ${waitTimeout / 1000} sec\n${err.message}`);
2899
- });
3029
+ throw new Error(`element (${locator.toString()}) still on page after ${waitTimeout / 1000} sec\n${err.message}`)
3030
+ })
2900
3031
  }
2901
3032
  }
2902
3033
 
@@ -2905,53 +3036,56 @@ class Playwright extends Helper {
2905
3036
  */
2906
3037
  async waitForCookie(name, sec) {
2907
3038
  // by default, we will retry 3 times
2908
- let retries = 3;
2909
- const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
3039
+ let retries = 3
3040
+ const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout
2910
3041
 
2911
3042
  if (sec) {
2912
- retries = sec;
3043
+ retries = sec
2913
3044
  } else {
2914
- retries = Math.ceil(waitTimeout / 1000) - 1;
3045
+ retries = Math.ceil(waitTimeout / 1000) - 1
2915
3046
  }
2916
3047
 
2917
- return promiseRetry(async (retry, number) => {
2918
- const _grabCookie = async (name) => {
2919
- const cookies = await this.browserContext.cookies();
2920
- const cookie = cookies.filter(c => c.name === name);
2921
- if (cookie.length === 0) throw Error(`Cookie ${name} is not found after ${retries}s`);
2922
- };
3048
+ return promiseRetry(
3049
+ async (retry, number) => {
3050
+ const _grabCookie = async (name) => {
3051
+ const cookies = await this.browserContext.cookies()
3052
+ const cookie = cookies.filter((c) => c.name === name)
3053
+ if (cookie.length === 0) throw Error(`Cookie ${name} is not found after ${retries}s`)
3054
+ }
2923
3055
 
2924
- this.debugSection('Wait for cookie: ', name);
2925
- if (number > 1) this.debugSection('Retrying... Attempt #', number);
3056
+ this.debugSection('Wait for cookie: ', name)
3057
+ if (number > 1) this.debugSection('Retrying... Attempt #', number)
2926
3058
 
2927
- try {
2928
- await _grabCookie(name);
2929
- } catch (e) {
2930
- retry(e);
2931
- }
2932
- }, { retries, maxTimeout: 1000 });
3059
+ try {
3060
+ await _grabCookie(name)
3061
+ } catch (e) {
3062
+ retry(e)
3063
+ }
3064
+ },
3065
+ { retries, maxTimeout: 1000 },
3066
+ )
2933
3067
  }
2934
3068
 
2935
3069
  async _waitForAction() {
2936
- return this.wait(this.options.waitForAction / 1000);
3070
+ return this.wait(this.options.waitForAction / 1000)
2937
3071
  }
2938
3072
 
2939
3073
  /**
2940
3074
  * {{> grabDataFromPerformanceTiming }}
2941
3075
  */
2942
3076
  async grabDataFromPerformanceTiming() {
2943
- return perfTiming;
3077
+ return perfTiming
2944
3078
  }
2945
3079
 
2946
3080
  /**
2947
3081
  * {{> grabElementBoundingRect }}
2948
3082
  */
2949
3083
  async grabElementBoundingRect(locator, prop) {
2950
- const el = await this._locateElement(locator);
2951
- assertElementExists(el, locator);
2952
- const rect = await el.boundingBox();
2953
- if (prop) return rect[prop];
2954
- return rect;
3084
+ const el = await this._locateElement(locator)
3085
+ assertElementExists(el, locator)
3086
+ const rect = await el.boundingBox()
3087
+ if (prop) return rect[prop]
3088
+ return rect
2955
3089
  }
2956
3090
 
2957
3091
  /**
@@ -2966,7 +3100,7 @@ class Playwright extends Helper {
2966
3100
  * @param {function} [handler] a function to process request
2967
3101
  */
2968
3102
  async mockRoute(url, handler) {
2969
- return this.browserContext.route(...arguments);
3103
+ return this.browserContext.route(...arguments)
2970
3104
  }
2971
3105
 
2972
3106
  /**
@@ -2982,17 +3116,17 @@ class Playwright extends Helper {
2982
3116
  * @param {function} [handler] a function to process request
2983
3117
  */
2984
3118
  async stopMockingRoute(url, handler) {
2985
- return this.browserContext.unroute(...arguments);
3119
+ return this.browserContext.unroute(...arguments)
2986
3120
  }
2987
3121
 
2988
3122
  /**
2989
- * {{> flushNetworkTraffics }}
3123
+ * {{> startRecordingTraffic }}
2990
3124
  *
2991
3125
  */
2992
3126
  startRecordingTraffic() {
2993
- this.flushNetworkTraffics();
2994
- this.recording = true;
2995
- this.recordedAtLeastOnce = true;
3127
+ this.flushNetworkTraffics()
3128
+ this.recording = true
3129
+ this.recordedAtLeastOnce = true
2996
3130
 
2997
3131
  this.page.on('requestfinished', async (request) => {
2998
3132
  const information = {
@@ -3001,16 +3135,16 @@ class Playwright extends Helper {
3001
3135
  requestHeaders: request.headers(),
3002
3136
  requestPostData: request.postData(),
3003
3137
  response: request.response(),
3004
- };
3138
+ }
3005
3139
 
3006
- this.debugSection('REQUEST: ', JSON.stringify(information));
3140
+ this.debugSection('REQUEST: ', JSON.stringify(information))
3007
3141
 
3008
3142
  if (typeof information.requestPostData === 'object') {
3009
- information.requestPostData = JSON.parse(information.requestPostData);
3143
+ information.requestPostData = JSON.parse(information.requestPostData)
3010
3144
  }
3011
3145
 
3012
- this.requests.push(information);
3013
- });
3146
+ this.requests.push(information)
3147
+ })
3014
3148
  }
3015
3149
 
3016
3150
  /**
@@ -3033,21 +3167,21 @@ class Playwright extends Helper {
3033
3167
  */
3034
3168
  blockTraffic(urls) {
3035
3169
  if (Array.isArray(urls)) {
3036
- urls.forEach(url => {
3170
+ urls.forEach((url) => {
3037
3171
  this.page.route(url, (route) => {
3038
3172
  route
3039
3173
  .abort()
3040
3174
  // Sometimes it happens that browser has been closed in the meantime. It is ok to ignore error then.
3041
- .catch((e) => {});
3042
- });
3043
- });
3175
+ .catch((e) => {})
3176
+ })
3177
+ })
3044
3178
  } else {
3045
3179
  this.page.route(urls, (route) => {
3046
3180
  route
3047
3181
  .abort()
3048
3182
  // Sometimes it happens that browser has been closed in the meantime. It is ok to ignore error then.
3049
- .catch((e) => {});
3050
- });
3183
+ .catch((e) => {})
3184
+ })
3051
3185
  }
3052
3186
  }
3053
3187
 
@@ -3069,10 +3203,10 @@ class Playwright extends Helper {
3069
3203
  */
3070
3204
  mockTraffic(urls, responseString, contentType = 'application/json') {
3071
3205
  // Required to mock cross-domain requests
3072
- const headers = { 'access-control-allow-origin': '*' };
3206
+ const headers = { 'access-control-allow-origin': '*' }
3073
3207
 
3074
3208
  if (typeof urls === 'string') {
3075
- urls = [urls];
3209
+ urls = [urls]
3076
3210
  }
3077
3211
 
3078
3212
  urls.forEach((url) => {
@@ -3080,15 +3214,15 @@ class Playwright extends Helper {
3080
3214
  if (this.page.isClosed()) {
3081
3215
  // Sometimes it happens that browser has been closed in the meantime.
3082
3216
  // In this case we just don't fulfill to prevent error in test scenario.
3083
- return;
3217
+ return
3084
3218
  }
3085
3219
  route.fulfill({
3086
3220
  contentType,
3087
3221
  headers,
3088
3222
  body: responseString,
3089
- });
3090
- });
3091
- });
3223
+ })
3224
+ })
3225
+ })
3092
3226
  }
3093
3227
 
3094
3228
  /**
@@ -3096,7 +3230,7 @@ class Playwright extends Helper {
3096
3230
  * {{> flushNetworkTraffics }}
3097
3231
  */
3098
3232
  flushNetworkTraffics() {
3099
- flushNetworkTraffics.call(this);
3233
+ flushNetworkTraffics.call(this)
3100
3234
  }
3101
3235
 
3102
3236
  /**
@@ -3104,14 +3238,12 @@ class Playwright extends Helper {
3104
3238
  * {{> stopRecordingTraffic }}
3105
3239
  */
3106
3240
  stopRecordingTraffic() {
3107
- stopRecordingTraffic.call(this);
3241
+ stopRecordingTraffic.call(this)
3108
3242
  }
3109
3243
 
3110
3244
  /**
3111
3245
  * Returns full URL of request matching parameter "urlMatch".
3112
3246
  *
3113
- * @param {string|RegExp} urlMatch Expected URL of request in network traffic. Can be a string or a regular expression.
3114
- *
3115
3247
  * Examples:
3116
3248
  *
3117
3249
  * ```js
@@ -3119,25 +3251,28 @@ class Playwright extends Helper {
3119
3251
  * I.grabTrafficUrl(/session.*start/);
3120
3252
  * ```
3121
3253
  *
3254
+ * @param {string|RegExp} urlMatch Expected URL of request in network traffic. Can be a string or a regular expression.
3122
3255
  * @return {Promise<*>}
3123
3256
  */
3124
3257
  grabTrafficUrl(urlMatch) {
3125
3258
  if (!this.recordedAtLeastOnce) {
3126
- throw new Error('Failure in test automation. You use "I.grabTrafficUrl", but "I.startRecordingTraffic" was never called before.');
3259
+ throw new Error(
3260
+ 'Failure in test automation. You use "I.grabTrafficUrl", but "I.startRecordingTraffic" was never called before.',
3261
+ )
3127
3262
  }
3128
3263
 
3129
3264
  for (const i in this.requests) {
3130
3265
  // eslint-disable-next-line no-prototype-builtins
3131
3266
  if (this.requests.hasOwnProperty(i)) {
3132
- const request = this.requests[i];
3267
+ const request = this.requests[i]
3133
3268
 
3134
3269
  if (request.url && request.url.match(new RegExp(urlMatch))) {
3135
- return request.url;
3270
+ return request.url
3136
3271
  }
3137
3272
  }
3138
3273
  }
3139
3274
 
3140
- assert.fail(`Method "getTrafficUrl" failed: No request found in traffic that matches ${urlMatch}`);
3275
+ assert.fail(`Method "getTrafficUrl" failed: No request found in traffic that matches ${urlMatch}`)
3141
3276
  }
3142
3277
 
3143
3278
  /**
@@ -3145,17 +3280,15 @@ class Playwright extends Helper {
3145
3280
  * {{> grabRecordedNetworkTraffics }}
3146
3281
  */
3147
3282
  async grabRecordedNetworkTraffics() {
3148
- return grabRecordedNetworkTraffics.call(this);
3283
+ return grabRecordedNetworkTraffics.call(this)
3149
3284
  }
3150
3285
 
3151
3286
  /**
3152
3287
  *
3153
3288
  * {{> seeTraffic }}
3154
3289
  */
3155
- async seeTraffic({
3156
- name, url, parameters, requestPostData, timeout = 10,
3157
- }) {
3158
- await seeTraffic.call(this, ...arguments);
3290
+ async seeTraffic({ name, url, parameters, requestPostData, timeout = 10 }) {
3291
+ await seeTraffic.call(this, ...arguments)
3159
3292
  }
3160
3293
 
3161
3294
  /**
@@ -3164,51 +3297,42 @@ class Playwright extends Helper {
3164
3297
  *
3165
3298
  */
3166
3299
  dontSeeTraffic({ name, url }) {
3167
- dontSeeTraffic.call(this, ...arguments);
3300
+ dontSeeTraffic.call(this, ...arguments)
3168
3301
  }
3169
3302
 
3170
3303
  /**
3171
3304
  * {{> startRecordingWebSocketMessages }}
3172
3305
  */
3173
3306
  async startRecordingWebSocketMessages() {
3174
- this.flushWebSocketMessages();
3175
- this.recordingWebSocketMessages = true;
3176
- this.recordedWebSocketMessagesAtLeastOnce = true;
3177
-
3178
- this.cdpSession = await this.getNewCDPSession();
3179
- await this.cdpSession.send('Network.enable');
3180
- await this.cdpSession.send('Page.enable');
3181
-
3182
- this.cdpSession.on(
3183
- 'Network.webSocketFrameReceived',
3184
- (payload) => {
3185
- this._logWebsocketMessages(this._getWebSocketLog('RECEIVED', payload));
3186
- },
3187
- );
3307
+ this.flushWebSocketMessages()
3308
+ this.recordingWebSocketMessages = true
3309
+ this.recordedWebSocketMessagesAtLeastOnce = true
3188
3310
 
3189
- this.cdpSession.on(
3190
- 'Network.webSocketFrameSent',
3191
- (payload) => {
3192
- this._logWebsocketMessages(this._getWebSocketLog('SENT', payload));
3193
- },
3194
- );
3311
+ this.cdpSession = await this.getNewCDPSession()
3312
+ await this.cdpSession.send('Network.enable')
3313
+ await this.cdpSession.send('Page.enable')
3195
3314
 
3196
- this.cdpSession.on(
3197
- 'Network.webSocketFrameError',
3198
- (payload) => {
3199
- this._logWebsocketMessages(this._getWebSocketLog('ERROR', payload));
3200
- },
3201
- );
3315
+ this.cdpSession.on('Network.webSocketFrameReceived', (payload) => {
3316
+ this._logWebsocketMessages(this._getWebSocketLog('RECEIVED', payload))
3317
+ })
3318
+
3319
+ this.cdpSession.on('Network.webSocketFrameSent', (payload) => {
3320
+ this._logWebsocketMessages(this._getWebSocketLog('SENT', payload))
3321
+ })
3322
+
3323
+ this.cdpSession.on('Network.webSocketFrameError', (payload) => {
3324
+ this._logWebsocketMessages(this._getWebSocketLog('ERROR', payload))
3325
+ })
3202
3326
  }
3203
3327
 
3204
3328
  /**
3205
3329
  * {{> stopRecordingWebSocketMessages }}
3206
3330
  */
3207
3331
  async stopRecordingWebSocketMessages() {
3208
- await this.cdpSession.send('Network.disable');
3209
- await this.cdpSession.send('Page.disable');
3210
- this.page.removeAllListeners('Network');
3211
- this.recordingWebSocketMessages = false;
3332
+ await this.cdpSession.send('Network.disable')
3333
+ await this.cdpSession.send('Page.disable')
3334
+ this.page.removeAllListeners('Network')
3335
+ this.recordingWebSocketMessages = false
3212
3336
  }
3213
3337
 
3214
3338
  /**
@@ -3220,17 +3344,19 @@ class Playwright extends Helper {
3220
3344
  grabWebSocketMessages() {
3221
3345
  if (!this.recordingWebSocketMessages) {
3222
3346
  if (!this.recordedWebSocketMessagesAtLeastOnce) {
3223
- throw new Error('Failure in test automation. You use "I.grabWebSocketMessages", but "I.startRecordingWebSocketMessages" was never called before.');
3347
+ throw new Error(
3348
+ 'Failure in test automation. You use "I.grabWebSocketMessages", but "I.startRecordingWebSocketMessages" was never called before.',
3349
+ )
3224
3350
  }
3225
3351
  }
3226
- return this.webSocketMessages;
3352
+ return this.webSocketMessages
3227
3353
  }
3228
3354
 
3229
3355
  /**
3230
3356
  * Resets all recorded WS messages.
3231
3357
  */
3232
3358
  flushWebSocketMessages() {
3233
- this.webSocketMessages = [];
3359
+ this.webSocketMessages = []
3234
3360
  }
3235
3361
 
3236
3362
  /**
@@ -3288,426 +3414,443 @@ class Playwright extends Helper {
3288
3414
  * @return {Promise<Array<Object>>}
3289
3415
  */
3290
3416
  async grabMetrics() {
3291
- const client = await this.page.context().newCDPSession(this.page);
3292
- await client.send('Performance.enable');
3293
- const perfMetricObject = await client.send('Performance.getMetrics');
3294
- return perfMetricObject?.metrics;
3417
+ const client = await this.page.context().newCDPSession(this.page)
3418
+ await client.send('Performance.enable')
3419
+ const perfMetricObject = await client.send('Performance.getMetrics')
3420
+ return perfMetricObject?.metrics
3295
3421
  }
3296
3422
 
3297
3423
  _getWebSocketMessage(payload) {
3298
3424
  if (payload.errorMessage) {
3299
- return payload.errorMessage;
3425
+ return payload.errorMessage
3300
3426
  }
3301
3427
 
3302
- return payload.response.payloadData;
3428
+ return payload.response.payloadData
3303
3429
  }
3304
3430
 
3305
3431
  _getWebSocketLog(prefix, payload) {
3306
- return `${prefix} ID: ${payload.requestId} TIMESTAMP: ${payload.timestamp} (${new Date().toISOString()})\n\n${this._getWebSocketMessage(payload)}\n\n`;
3432
+ return `${prefix} ID: ${payload.requestId} TIMESTAMP: ${payload.timestamp} (${new Date().toISOString()})\n\n${this._getWebSocketMessage(payload)}\n\n`
3307
3433
  }
3308
3434
 
3309
3435
  async getNewCDPSession() {
3310
- return this.page.context().newCDPSession(this.page);
3436
+ return this.page.context().newCDPSession(this.page)
3311
3437
  }
3312
3438
 
3313
3439
  _logWebsocketMessages(message) {
3314
- this.webSocketMessages += message;
3440
+ this.webSocketMessages.push(message)
3315
3441
  }
3316
3442
  }
3317
3443
 
3318
- export default Playwright;
3444
+ module.exports = Playwright
3319
3445
 
3320
3446
  function buildLocatorString(locator) {
3321
3447
  if (locator.isCustom()) {
3322
- return `${locator.type}=${locator.value}`;
3323
- } if (locator.isXPath()) {
3324
- return `xpath=${locator.value}`;
3448
+ return `${locator.type}=${locator.value}`
3325
3449
  }
3326
- return locator.simplify();
3450
+ if (locator.isXPath()) {
3451
+ return `xpath=${locator.value}`
3452
+ }
3453
+ return locator.simplify()
3327
3454
  }
3328
3455
 
3329
3456
  async function findElements(matcher, locator) {
3330
- if (locator.react) return findReact(matcher, locator);
3331
- if (locator.vue) return findVue(matcher, locator);
3332
- if (locator.pw) return findByPlaywrightLocator.call(this, matcher, locator);
3333
- locator = new Locator(locator, 'css');
3457
+ if (locator.react) return findReact(matcher, locator)
3458
+ if (locator.vue) return findVue(matcher, locator)
3459
+ if (locator.pw) return findByPlaywrightLocator.call(this, matcher, locator)
3460
+ locator = new Locator(locator, 'css')
3334
3461
 
3335
- return matcher.locator(buildLocatorString(locator)).all();
3462
+ return matcher.locator(buildLocatorString(locator)).all()
3336
3463
  }
3337
3464
 
3338
3465
  async function findElement(matcher, locator) {
3339
- if (locator.react) return findReact(matcher, locator);
3340
- if (locator.vue) return findVue(matcher, locator);
3341
- if (locator.pw) return findByPlaywrightLocator.call(this, matcher, locator);
3342
- locator = new Locator(locator, 'css');
3466
+ if (locator.react) return findReact(matcher, locator)
3467
+ if (locator.vue) return findVue(matcher, locator)
3468
+ if (locator.pw) return findByPlaywrightLocator.call(this, matcher, locator)
3469
+ locator = new Locator(locator, 'css')
3343
3470
 
3344
- return matcher.locator(buildLocatorString(locator)).first();
3471
+ return matcher.locator(buildLocatorString(locator)).first()
3345
3472
  }
3346
3473
 
3347
3474
  async function getVisibleElements(elements) {
3348
- const visibleElements = [];
3475
+ const visibleElements = []
3349
3476
  for (const element of elements) {
3350
3477
  if (await element.isVisible()) {
3351
- visibleElements.push(element);
3478
+ visibleElements.push(element)
3352
3479
  }
3353
3480
  }
3354
3481
  if (visibleElements.length === 0) {
3355
- return elements;
3482
+ return elements
3356
3483
  }
3357
- return visibleElements;
3484
+ return visibleElements
3358
3485
  }
3359
3486
 
3360
3487
  async function proceedClick(locator, context = null, options = {}) {
3361
- let matcher = await this._getContext();
3488
+ let matcher = await this._getContext()
3362
3489
  if (context) {
3363
- const els = await this._locate(context);
3364
- assertElementExists(els, context);
3365
- matcher = els[0];
3490
+ const els = await this._locate(context)
3491
+ assertElementExists(els, context)
3492
+ matcher = els[0]
3366
3493
  }
3367
- const els = await findClickable.call(this, matcher, locator);
3494
+ const els = await findClickable.call(this, matcher, locator)
3368
3495
  if (context) {
3369
- assertElementExists(els, locator, 'Clickable element', `was not found inside element ${new Locator(context).toString()}`);
3496
+ assertElementExists(
3497
+ els,
3498
+ locator,
3499
+ 'Clickable element',
3500
+ `was not found inside element ${new Locator(context).toString()}`,
3501
+ )
3370
3502
  } else {
3371
- assertElementExists(els, locator, 'Clickable element');
3503
+ assertElementExists(els, locator, 'Clickable element')
3372
3504
  }
3373
3505
 
3374
- await highlightActiveElement.call(this, els[0]);
3506
+ await highlightActiveElement.call(this, els[0])
3375
3507
 
3376
3508
  /*
3377
3509
  using the force true options itself but instead dispatching a click
3378
3510
  */
3379
3511
  if (options.force) {
3380
- await els[0].dispatchEvent('click');
3512
+ await els[0].dispatchEvent('click')
3381
3513
  } else {
3382
- const element = els.length > 1 ? (await getVisibleElements(els))[0] : els[0];
3383
- await element.click(options);
3514
+ const element = els.length > 1 ? (await getVisibleElements(els))[0] : els[0]
3515
+ await element.click(options)
3384
3516
  }
3385
- const promises = [];
3517
+ const promises = []
3386
3518
  if (options.waitForNavigation) {
3387
- promises.push(this.waitForURL(/.*/, { waitUntil: options.waitForNavigation }));
3519
+ promises.push(this.waitForURL(/.*/, { waitUntil: options.waitForNavigation }))
3388
3520
  }
3389
- promises.push(this._waitForAction());
3521
+ promises.push(this._waitForAction())
3390
3522
 
3391
- return Promise.all(promises);
3523
+ return Promise.all(promises)
3392
3524
  }
3393
3525
 
3394
3526
  async function findClickable(matcher, locator) {
3395
- if (locator.react) return findReact(matcher, locator);
3396
- if (locator.vue) return findVue(matcher, locator);
3397
- if (locator.pw) return findByPlaywrightLocator.call(this, matcher, locator);
3527
+ if (locator.react) return findReact(matcher, locator)
3528
+ if (locator.vue) return findVue(matcher, locator)
3529
+ if (locator.pw) return findByPlaywrightLocator.call(this, matcher, locator)
3398
3530
 
3399
- locator = new Locator(locator);
3400
- if (!locator.isFuzzy()) return findElements.call(this, matcher, locator);
3531
+ locator = new Locator(locator)
3532
+ if (!locator.isFuzzy()) return findElements.call(this, matcher, locator)
3401
3533
 
3402
- let els;
3403
- const literal = xpathLocator.literal(locator.value);
3534
+ let els
3535
+ const literal = xpathLocator.literal(locator.value)
3404
3536
 
3405
- els = await findElements.call(this, matcher, Locator.clickable.narrow(literal));
3406
- if (els.length) return els;
3537
+ els = await findElements.call(this, matcher, Locator.clickable.narrow(literal))
3538
+ if (els.length) return els
3407
3539
 
3408
- els = await findElements.call(this, matcher, Locator.clickable.wide(literal));
3409
- if (els.length) return els;
3540
+ els = await findElements.call(this, matcher, Locator.clickable.wide(literal))
3541
+ if (els.length) return els
3410
3542
 
3411
3543
  try {
3412
- els = await findElements.call(this, matcher, Locator.clickable.self(literal));
3413
- if (els.length) return els;
3544
+ els = await findElements.call(this, matcher, Locator.clickable.self(literal))
3545
+ if (els.length) return els
3414
3546
  } catch (err) {
3415
3547
  // Do nothing
3416
3548
  }
3417
3549
 
3418
- return findElements.call(this, matcher, locator.value); // by css or xpath
3550
+ return findElements.call(this, matcher, locator.value) // by css or xpath
3419
3551
  }
3420
3552
 
3421
3553
  async function proceedSee(assertType, text, context, strict = false) {
3422
- let description;
3423
- let allText;
3554
+ let description
3555
+ let allText
3424
3556
 
3425
3557
  if (!context) {
3426
- const el = await this.context;
3558
+ const el = await this.context
3427
3559
 
3428
- allText = el.constructor.name !== 'Locator' ? [await el.locator('body').innerText()] : [await el.innerText()];
3560
+ allText = el.constructor.name !== 'Locator' ? [await el.locator('body').innerText()] : [await el.innerText()]
3429
3561
 
3430
- description = 'web application';
3562
+ description = 'web application'
3431
3563
  } else {
3432
- const locator = new Locator(context, 'css');
3433
- description = `element ${locator.toString()}`;
3434
- const els = await this._locate(locator);
3435
- assertElementExists(els, locator.toString());
3436
- allText = await Promise.all(els.map(el => el.innerText()));
3564
+ const locator = new Locator(context, 'css')
3565
+ description = `element ${locator.toString()}`
3566
+ const els = await this._locate(locator)
3567
+ assertElementExists(els, locator.toString())
3568
+ allText = await Promise.all(els.map((el) => el.innerText()))
3437
3569
  }
3438
3570
 
3439
3571
  if (strict) {
3440
- return allText.map(elText => equals(description)[assertType](text, elText));
3572
+ return allText.map((elText) => equals(description)[assertType](text, elText))
3441
3573
  }
3442
- return stringIncludes(description)[assertType](normalizeSpacesInString(text), normalizeSpacesInString(allText.join(' | ')));
3574
+ return stringIncludes(description)[assertType](
3575
+ normalizeSpacesInString(text),
3576
+ normalizeSpacesInString(allText.join(' | ')),
3577
+ )
3443
3578
  }
3444
3579
 
3445
3580
  async function findCheckable(locator, context) {
3446
- let contextEl = await this.context;
3581
+ let contextEl = await this.context
3447
3582
  if (typeof context === 'string') {
3448
- contextEl = await findElements.call(this, contextEl, (new Locator(context, 'css')).simplify());
3449
- contextEl = contextEl[0];
3583
+ contextEl = await findElements.call(this, contextEl, new Locator(context, 'css').simplify())
3584
+ contextEl = contextEl[0]
3450
3585
  }
3451
3586
 
3452
- const matchedLocator = new Locator(locator);
3587
+ const matchedLocator = new Locator(locator)
3453
3588
  if (!matchedLocator.isFuzzy()) {
3454
- return findElements.call(this, contextEl, matchedLocator.simplify());
3589
+ return findElements.call(this, contextEl, matchedLocator.simplify())
3455
3590
  }
3456
3591
 
3457
- const literal = xpathLocator.literal(locator);
3458
- let els = await findElements.call(this, contextEl, Locator.checkable.byText(literal));
3592
+ const literal = xpathLocator.literal(locator)
3593
+ let els = await findElements.call(this, contextEl, Locator.checkable.byText(literal))
3459
3594
  if (els.length) {
3460
- return els;
3595
+ return els
3461
3596
  }
3462
- els = await findElements.call(this, contextEl, Locator.checkable.byName(literal));
3597
+ els = await findElements.call(this, contextEl, Locator.checkable.byName(literal))
3463
3598
  if (els.length) {
3464
- return els;
3599
+ return els
3465
3600
  }
3466
- return findElements.call(this, contextEl, locator);
3601
+ return findElements.call(this, contextEl, locator)
3467
3602
  }
3468
3603
 
3469
3604
  async function proceedIsChecked(assertType, option) {
3470
- let els = await findCheckable.call(this, option);
3471
- assertElementExists(els, option, 'Checkable');
3472
- els = await Promise.all(els.map(el => el.isChecked()));
3473
- const selected = els.reduce((prev, cur) => prev || cur);
3474
- return truth(`checkable ${option}`, 'to be checked')[assertType](selected);
3605
+ let els = await findCheckable.call(this, option)
3606
+ assertElementExists(els, option, 'Checkable')
3607
+ els = await Promise.all(els.map((el) => el.isChecked()))
3608
+ const selected = els.reduce((prev, cur) => prev || cur)
3609
+ return truth(`checkable ${option}`, 'to be checked')[assertType](selected)
3475
3610
  }
3476
3611
 
3477
3612
  async function findFields(locator) {
3478
- const matchedLocator = new Locator(locator);
3613
+ const matchedLocator = new Locator(locator)
3479
3614
  if (!matchedLocator.isFuzzy()) {
3480
- return this._locate(matchedLocator);
3615
+ return this._locate(matchedLocator)
3481
3616
  }
3482
- const literal = xpathLocator.literal(locator);
3617
+ const literal = xpathLocator.literal(locator)
3483
3618
 
3484
- let els = await this._locate({ xpath: Locator.field.labelEquals(literal) });
3619
+ let els = await this._locate({ xpath: Locator.field.labelEquals(literal) })
3485
3620
  if (els.length) {
3486
- return els;
3621
+ return els
3487
3622
  }
3488
3623
 
3489
- els = await this._locate({ xpath: Locator.field.labelContains(literal) });
3624
+ els = await this._locate({ xpath: Locator.field.labelContains(literal) })
3490
3625
  if (els.length) {
3491
- return els;
3626
+ return els
3492
3627
  }
3493
- els = await this._locate({ xpath: Locator.field.byName(literal) });
3628
+ els = await this._locate({ xpath: Locator.field.byName(literal) })
3494
3629
  if (els.length) {
3495
- return els;
3630
+ return els
3496
3631
  }
3497
- return this._locate({ css: locator });
3632
+ return this._locate({ css: locator })
3498
3633
  }
3499
3634
 
3500
3635
  async function proceedSeeInField(assertType, field, value) {
3501
- const els = await findFields.call(this, field);
3502
- assertElementExists(els, field, 'Field');
3503
- const el = els[0];
3504
- const tag = await el.evaluate(e => e.tagName);
3505
- const fieldType = await el.getAttribute('type');
3636
+ const els = await findFields.call(this, field)
3637
+ assertElementExists(els, field, 'Field')
3638
+ const el = els[0]
3639
+ const tag = await el.evaluate((e) => e.tagName)
3640
+ const fieldType = await el.getAttribute('type')
3506
3641
 
3507
3642
  const proceedMultiple = async (elements) => {
3508
- const fields = Array.isArray(elements) ? elements : [elements];
3643
+ const fields = Array.isArray(elements) ? elements : [elements]
3509
3644
 
3510
- const elementValues = [];
3645
+ const elementValues = []
3511
3646
  for (const element of fields) {
3512
- elementValues.push(await element.inputValue());
3647
+ elementValues.push(await element.inputValue())
3513
3648
  }
3514
3649
 
3515
3650
  if (typeof value === 'boolean') {
3516
- equals(`no. of items matching > 0: ${field}`)[assertType](value, !!elementValues.length);
3651
+ equals(`no. of items matching > 0: ${field}`)[assertType](value, !!elementValues.length)
3517
3652
  } else {
3518
3653
  if (assertType === 'assert') {
3519
- equals(`select option by ${field}`)[assertType](true, elementValues.length > 0);
3654
+ equals(`select option by ${field}`)[assertType](true, elementValues.length > 0)
3520
3655
  }
3521
- elementValues.forEach(val => stringIncludes(`fields by ${field}`)[assertType](value, val));
3656
+ elementValues.forEach((val) => stringIncludes(`fields by ${field}`)[assertType](value, val))
3522
3657
  }
3523
- };
3658
+ }
3524
3659
 
3525
3660
  if (tag === 'SELECT') {
3526
3661
  if (await el.getAttribute('multiple')) {
3527
- const selectedOptions = await el.all('option:checked');
3528
- if (!selectedOptions.length) return null;
3662
+ const selectedOptions = await el.all('option:checked')
3663
+ if (!selectedOptions.length) return null
3529
3664
 
3530
- const options = await filterFieldsByValue(selectedOptions, value, true);
3531
- return proceedMultiple(options);
3665
+ const options = await filterFieldsByValue(selectedOptions, value, true)
3666
+ return proceedMultiple(options)
3532
3667
  }
3533
3668
 
3534
- return el.inputValue();
3669
+ return el.inputValue()
3535
3670
  }
3536
3671
 
3537
3672
  if (tag === 'INPUT') {
3538
3673
  if (fieldType === 'checkbox' || fieldType === 'radio') {
3539
3674
  if (typeof value === 'boolean') {
3540
3675
  // Filter by values
3541
- const options = await filterFieldsBySelectionState(els, true);
3542
- return proceedMultiple(options);
3676
+ const options = await filterFieldsBySelectionState(els, true)
3677
+ return proceedMultiple(options)
3543
3678
  }
3544
3679
 
3545
- const options = await filterFieldsByValue(els, value, true);
3546
- return proceedMultiple(options);
3680
+ const options = await filterFieldsByValue(els, value, true)
3681
+ return proceedMultiple(options)
3547
3682
  }
3548
- return proceedMultiple(els[0]);
3683
+ return proceedMultiple(els[0])
3549
3684
  }
3550
3685
 
3551
- let fieldVal;
3686
+ let fieldVal
3552
3687
 
3553
3688
  try {
3554
- fieldVal = await el.inputValue();
3689
+ fieldVal = await el.inputValue()
3555
3690
  } catch (e) {
3556
3691
  if (e.message.includes('Error: Node is not an <input>, <textarea> or <select> element')) {
3557
- fieldVal = await el.innerText();
3692
+ fieldVal = await el.innerText()
3558
3693
  }
3559
3694
  }
3560
3695
 
3561
- return stringIncludes(`fields by ${field}`)[assertType](value, fieldVal);
3696
+ return stringIncludes(`fields by ${field}`)[assertType](value, fieldVal)
3562
3697
  }
3563
3698
 
3564
3699
  async function filterFieldsByValue(elements, value, onlySelected) {
3565
- const matches = [];
3700
+ const matches = []
3566
3701
  for (const element of elements) {
3567
- const val = await element.getAttribute('value');
3568
- let isSelected = true;
3702
+ const val = await element.getAttribute('value')
3703
+ let isSelected = true
3569
3704
  if (onlySelected) {
3570
- isSelected = await elementSelected(element);
3705
+ isSelected = await elementSelected(element)
3571
3706
  }
3572
3707
  if ((value == null || val.indexOf(value) > -1) && isSelected) {
3573
- matches.push(element);
3708
+ matches.push(element)
3574
3709
  }
3575
3710
  }
3576
- return matches;
3711
+ return matches
3577
3712
  }
3578
3713
 
3579
3714
  async function filterFieldsBySelectionState(elements, state) {
3580
- const matches = [];
3715
+ const matches = []
3581
3716
  for (const element of elements) {
3582
- const isSelected = await elementSelected(element);
3717
+ const isSelected = await elementSelected(element)
3583
3718
  if (isSelected === state) {
3584
- matches.push(element);
3719
+ matches.push(element)
3585
3720
  }
3586
3721
  }
3587
- return matches;
3722
+ return matches
3588
3723
  }
3589
3724
 
3590
3725
  async function elementSelected(element) {
3591
- const type = await element.getAttribute('type');
3726
+ const type = await element.getAttribute('type')
3592
3727
 
3593
3728
  if (type === 'checkbox' || type === 'radio') {
3594
- return element.isChecked();
3729
+ return element.isChecked()
3595
3730
  }
3596
- return element.getAttribute('selected');
3731
+ return element.getAttribute('selected')
3597
3732
  }
3598
3733
 
3599
3734
  function isFrameLocator(locator) {
3600
- locator = new Locator(locator);
3735
+ locator = new Locator(locator)
3601
3736
  if (locator.isFrame()) {
3602
- return locator.value;
3737
+ return locator.value
3603
3738
  }
3604
- return false;
3739
+ return false
3605
3740
  }
3606
3741
 
3607
3742
  function assertElementExists(res, locator, prefix, suffix) {
3608
3743
  if (!res || res.length === 0) {
3609
- throw new ElementNotFound(locator, prefix, suffix);
3744
+ throw new ElementNotFound(locator, prefix, suffix)
3610
3745
  }
3611
3746
  }
3612
3747
 
3613
3748
  function $XPath(element, selector) {
3614
- const found = document.evaluate(selector, element || document.body, null, 5, null);
3615
- const res = [];
3616
- let current = null;
3617
- while (current = found.iterateNext()) {
3618
- res.push(current);
3749
+ const found = document.evaluate(selector, element || document.body, null, 5, null)
3750
+ const res = []
3751
+ let current = null
3752
+ while ((current = found.iterateNext())) {
3753
+ res.push(current)
3619
3754
  }
3620
- return res;
3755
+ return res
3621
3756
  }
3622
3757
 
3623
3758
  async function targetCreatedHandler(page) {
3624
- if (!page) return;
3625
- this.withinLocator = null;
3759
+ if (!page) return
3760
+ this.withinLocator = null
3626
3761
  page.on('load', () => {
3627
- page.$('body')
3762
+ page
3763
+ .$('body')
3628
3764
  .catch(() => null)
3629
3765
  .then(async () => {
3630
3766
  if (this.context && this.context._type === 'Frame') {
3631
3767
  // we are inside iframe?
3632
- const frameEl = await this.context.frameElement();
3633
- this.context = await frameEl.contentFrame();
3634
- this.contextLocator = null;
3635
- return;
3768
+ const frameEl = await this.context.frameElement()
3769
+ this.context = await frameEl.contentFrame()
3770
+ this.contextLocator = null
3771
+ return
3636
3772
  }
3637
3773
  // if context element was in iframe - keep it
3638
3774
  // if (await this.context.ownerFrame()) return;
3639
- this.context = page;
3640
- this.contextLocator = null;
3641
- });
3642
- });
3775
+ this.context = page
3776
+ this.contextLocator = null
3777
+ })
3778
+ })
3643
3779
  page.on('console', (msg) => {
3644
3780
  if (!consoleLogStore.includes(msg) && this.options.ignoreLog && !this.options.ignoreLog.includes(msg.type())) {
3645
- this.debugSection(`Browser:${ucfirst(msg.type())}`, (msg.text && msg.text() || msg._text || '') + msg.args().join(' '));
3781
+ this.debugSection(
3782
+ `Browser:${ucfirst(msg.type())}`,
3783
+ ((msg.text && msg.text()) || msg._text || '') + msg.args().join(' '),
3784
+ )
3646
3785
  }
3647
- consoleLogStore.add(msg);
3648
- });
3786
+ consoleLogStore.add(msg)
3787
+ })
3649
3788
 
3650
3789
  if (this.options.windowSize && this.options.windowSize.indexOf('x') > 0 && this._getType() === 'Browser') {
3651
3790
  try {
3652
- await page.setViewportSize(parseWindowSize(this.options.windowSize));
3791
+ await page.setViewportSize(parseWindowSize(this.options.windowSize))
3653
3792
  } catch (err) {
3654
- this.debug('Target can be already closed, ignoring...');
3793
+ this.debug('Target can be already closed, ignoring...')
3655
3794
  }
3656
3795
  }
3657
3796
  }
3658
3797
 
3659
3798
  function parseWindowSize(windowSize) {
3660
- if (!windowSize) return { width: 800, height: 600 };
3661
- const dimensions = windowSize.split('x');
3799
+ if (!windowSize) return { width: 800, height: 600 }
3800
+
3801
+ if (windowSize.width && windowSize.height) {
3802
+ return { width: parseInt(windowSize.width, 10), height: parseInt(windowSize.height, 10) }
3803
+ }
3804
+
3805
+ const dimensions = windowSize.split('x')
3662
3806
  if (dimensions.length < 2 || windowSize === 'maximize') {
3663
- console.log('Invalid window size, setting window to default values');
3664
- return { width: 800, height: 600 }; // invalid size
3807
+ console.log('Invalid window size, setting window to default values')
3808
+ return { width: 800, height: 600 } // invalid size
3665
3809
  }
3666
- const width = parseInt(dimensions[0], 10);
3667
- const height = parseInt(dimensions[1], 10);
3668
- return { width, height };
3810
+ const width = parseInt(dimensions[0], 10)
3811
+ const height = parseInt(dimensions[1], 10)
3812
+ return { width, height }
3669
3813
  }
3670
3814
 
3671
3815
  // List of key values to key definitions
3672
3816
  // https://github.com/puppeteer/puppeteer/blob/v1.20.0/lib/USKeyboardLayout.js
3673
3817
  const keyDefinitionMap = {
3674
- /* eslint-disable quote-props */
3675
- '0': 'Digit0',
3676
- '1': 'Digit1',
3677
- '2': 'Digit2',
3678
- '3': 'Digit3',
3679
- '4': 'Digit4',
3680
- '5': 'Digit5',
3681
- '6': 'Digit6',
3682
- '7': 'Digit7',
3683
- '8': 'Digit8',
3684
- '9': 'Digit9',
3685
- 'a': 'KeyA',
3686
- 'b': 'KeyB',
3687
- 'c': 'KeyC',
3688
- 'd': 'KeyD',
3689
- 'e': 'KeyE',
3690
- 'f': 'KeyF',
3691
- 'g': 'KeyG',
3692
- 'h': 'KeyH',
3693
- 'i': 'KeyI',
3694
- 'j': 'KeyJ',
3695
- 'k': 'KeyK',
3696
- 'l': 'KeyL',
3697
- 'm': 'KeyM',
3698
- 'n': 'KeyN',
3699
- 'o': 'KeyO',
3700
- 'p': 'KeyP',
3701
- 'q': 'KeyQ',
3702
- 'r': 'KeyR',
3703
- 's': 'KeyS',
3704
- 't': 'KeyT',
3705
- 'u': 'KeyU',
3706
- 'v': 'KeyV',
3707
- 'w': 'KeyW',
3708
- 'x': 'KeyX',
3709
- 'y': 'KeyY',
3710
- 'z': 'KeyZ',
3818
+ 0: 'Digit0',
3819
+ 1: 'Digit1',
3820
+ 2: 'Digit2',
3821
+ 3: 'Digit3',
3822
+ 4: 'Digit4',
3823
+ 5: 'Digit5',
3824
+ 6: 'Digit6',
3825
+ 7: 'Digit7',
3826
+ 8: 'Digit8',
3827
+ 9: 'Digit9',
3828
+ a: 'KeyA',
3829
+ b: 'KeyB',
3830
+ c: 'KeyC',
3831
+ d: 'KeyD',
3832
+ e: 'KeyE',
3833
+ f: 'KeyF',
3834
+ g: 'KeyG',
3835
+ h: 'KeyH',
3836
+ i: 'KeyI',
3837
+ j: 'KeyJ',
3838
+ k: 'KeyK',
3839
+ l: 'KeyL',
3840
+ m: 'KeyM',
3841
+ n: 'KeyN',
3842
+ o: 'KeyO',
3843
+ p: 'KeyP',
3844
+ q: 'KeyQ',
3845
+ r: 'KeyR',
3846
+ s: 'KeyS',
3847
+ t: 'KeyT',
3848
+ u: 'KeyU',
3849
+ v: 'KeyV',
3850
+ w: 'KeyW',
3851
+ x: 'KeyX',
3852
+ y: 'KeyY',
3853
+ z: 'KeyZ',
3711
3854
  ';': 'Semicolon',
3712
3855
  '=': 'Equal',
3713
3856
  ',': 'Comma',
@@ -3718,89 +3861,91 @@ const keyDefinitionMap = {
3718
3861
  '[': 'BracketLeft',
3719
3862
  '\\': 'Backslash',
3720
3863
  ']': 'BracketRight',
3721
- '\'': 'Quote',
3722
- /* eslint-enable quote-props */
3723
- };
3864
+ "'": 'Quote',
3865
+ }
3724
3866
 
3725
3867
  function getNormalizedKey(key) {
3726
- const normalizedKey = getNormalizedKeyAttributeValue(key);
3868
+ const normalizedKey = getNormalizedKeyAttributeValue(key)
3727
3869
  if (key !== normalizedKey) {
3728
- this.debugSection('Input', `Mapping key '${key}' to '${normalizedKey}'`);
3870
+ this.debugSection('Input', `Mapping key '${key}' to '${normalizedKey}'`)
3729
3871
  }
3730
3872
  // Use key definition to ensure correct key is displayed when Shift modifier is active
3731
3873
  if (Object.prototype.hasOwnProperty.call(keyDefinitionMap, normalizedKey)) {
3732
- return keyDefinitionMap[normalizedKey];
3874
+ return keyDefinitionMap[normalizedKey]
3733
3875
  }
3734
- return normalizedKey;
3876
+ return normalizedKey
3735
3877
  }
3736
3878
 
3737
3879
  async function clickablePoint(el) {
3738
- const rect = await el.boundingBox();
3739
- if (!rect) throw new ElementNotFound(el);
3740
- const {
3741
- x, y, width, height,
3742
- } = rect;
3743
- return { x: x + width / 2, y: y + height / 2 };
3880
+ const rect = await el.boundingBox()
3881
+ if (!rect) throw new ElementNotFound(el)
3882
+ const { x, y, width, height } = rect
3883
+ return { x: x + width / 2, y: y + height / 2 }
3744
3884
  }
3745
3885
 
3746
3886
  async function refreshContextSession() {
3747
3887
  // close other sessions
3748
3888
  try {
3749
- const contexts = await this.browser.contexts();
3750
- contexts.shift();
3889
+ const contexts = await this.browser.contexts()
3890
+ contexts.shift()
3751
3891
 
3752
- await Promise.all(contexts.map(c => c.close()));
3892
+ await Promise.all(contexts.map((c) => c.close()))
3753
3893
  } catch (e) {
3754
- console.log(e);
3894
+ console.log(e)
3755
3895
  }
3756
3896
 
3757
3897
  if (this.page) {
3758
- const existingPages = await this.browserContext.pages();
3759
- await this._setPage(existingPages[0]);
3898
+ const existingPages = await this.browserContext.pages()
3899
+ await this._setPage(existingPages[0])
3760
3900
  }
3761
3901
 
3762
- if (this.options.keepBrowserState) return;
3902
+ if (this.options.keepBrowserState) return
3763
3903
 
3764
3904
  if (!this.options.keepCookies) {
3765
- this.debugSection('Session', 'cleaning cookies and localStorage');
3766
- await this.clearCookie();
3905
+ this.debugSection('Session', 'cleaning cookies and localStorage')
3906
+ await this.clearCookie()
3767
3907
  }
3768
- const currentUrl = await this.grabCurrentUrl();
3908
+ const currentUrl = await this.grabCurrentUrl()
3769
3909
 
3770
3910
  if (currentUrl.startsWith('http')) {
3771
3911
  await this.executeScript('localStorage.clear();').catch((err) => {
3772
- if (!(err.message.indexOf("Storage is disabled inside 'data:' URLs.") > -1)) throw err;
3773
- });
3912
+ if (!(err.message.indexOf("Storage is disabled inside 'data:' URLs.") > -1)) throw err
3913
+ })
3774
3914
  await this.executeScript('sessionStorage.clear();').catch((err) => {
3775
- if (!(err.message.indexOf("Storage is disabled inside 'data:' URLs.") > -1)) throw err;
3776
- });
3915
+ if (!(err.message.indexOf("Storage is disabled inside 'data:' URLs.") > -1)) throw err
3916
+ })
3777
3917
  }
3778
3918
  }
3779
3919
 
3780
- async function saveVideoForPage(page, name) {
3781
- if (!page.video()) return null;
3782
- const fileName = `${`${global.output_dir}${pathSeparator}videos${pathSeparator}${uuidv4()}_${clearString(name)}`.slice(0, 245)}.webm`;
3783
- page.video().saveAs(fileName).then(() => {
3784
- if (!page) return;
3785
- page.video().delete().catch(e => {});
3786
- });
3787
- return fileName;
3920
+ function saveVideoForPage(page, name) {
3921
+ if (!page.video()) return null
3922
+ const fileName = `${`${global.output_dir}${pathSeparator}videos${pathSeparator}${uuidv4()}_${clearString(name)}`.slice(0, 245)}.webm`
3923
+ page
3924
+ .video()
3925
+ .saveAs(fileName)
3926
+ .then(() => {
3927
+ if (!page) return
3928
+ page
3929
+ .video()
3930
+ .delete()
3931
+ .catch(() => {})
3932
+ })
3933
+ return fileName
3788
3934
  }
3789
-
3790
3935
  async function saveTraceForContext(context, name) {
3791
- if (!context) return;
3792
- if (!context.tracing) return;
3793
- const fileName = `${`${global.output_dir}${pathSeparator}trace${pathSeparator}${uuidv4()}_${clearString(name)}`.slice(0, 245)}.zip`;
3794
- await context.tracing.stop({ path: fileName });
3795
- return fileName;
3936
+ if (!context) return
3937
+ if (!context.tracing) return
3938
+ const fileName = `${`${global.output_dir}${pathSeparator}trace${pathSeparator}${uuidv4()}_${clearString(name)}`.slice(0, 245)}.zip`
3939
+ await context.tracing.stop({ path: fileName })
3940
+ return fileName
3796
3941
  }
3797
3942
 
3798
3943
  async function highlightActiveElement(element) {
3799
3944
  if (this.options.highlightElement && global.debugMode) {
3800
- await element.evaluate(el => {
3801
- const prevStyle = el.style.boxShadow;
3802
- el.style.boxShadow = '0px 0px 4px 3px rgba(255, 0, 0, 0.7)';
3803
- setTimeout(() => el.style.boxShadow = prevStyle, 2000);
3804
- });
3945
+ await element.evaluate((el) => {
3946
+ const prevStyle = el.style.boxShadow
3947
+ el.style.boxShadow = '0px 0px 4px 3px rgba(255, 0, 0, 0.7)'
3948
+ setTimeout(() => (el.style.boxShadow = prevStyle), 2000)
3949
+ })
3805
3950
  }
3806
3951
  }