codeceptjs 3.6.4-beta.2 → 3.6.5-beta.1

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