@telefonica/acceptance-testing 3.0.0-beta9 → 4.0.0

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.
@@ -5,6 +5,7 @@ import { queries, getDocument } from 'pptr-testing-library';
5
5
  import { configureToMatchImageSnapshot } from 'jest-image-snapshot';
6
6
  import globToRegExp from 'glob-to-regexp';
7
7
  import { execSync } from 'child_process';
8
+ import istanbul from 'istanbul-lib-coverage';
8
9
 
9
10
  function _regeneratorRuntime() {
10
11
  _regeneratorRuntime = function () {
@@ -364,6 +365,27 @@ function _objectWithoutPropertiesLoose(source, excluded) {
364
365
  return target;
365
366
  }
366
367
 
368
+ /**
369
+ * Debug function that logs to the console if the DEBUG_ACCEPTANCE_TESTING environment variable is set
370
+ */
371
+ var debug = function debug() {
372
+ if (process.env.DEBUG_ACCEPTANCE_TESTING) {
373
+ var _console;
374
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
375
+ args[_key] = arguments[_key];
376
+ }
377
+ (_console = console).debug.apply(_console, ['[acceptance-testing]'].concat(args));
378
+ }
379
+ };
380
+ /**
381
+ * Returns true if the current path matches the spied path, including parameters
382
+ */
383
+ var matchPath = function matchPath(spiedPath, currentPath) {
384
+ var normalizedCurrentPath = path.normalize(currentPath);
385
+ var pattern = globToRegExp(spiedPath);
386
+ return pattern.test(normalizedCurrentPath);
387
+ };
388
+
367
389
  var getGlobalPage = function getGlobalPage() {
368
390
  return global.page;
369
391
  };
@@ -374,90 +396,159 @@ var getRootPath = function getRootPath() {
374
396
  }
375
397
  return rootPath;
376
398
  };
377
- /**
378
- * We want to clear coverage files from previous runs, but at this point it is not easy because each
379
- * worker runs a different instance of this script, so we can't just clear the coverage folder at
380
- * the beginning of the test run.
381
- *
382
- * The solution is to remove the coverage folder when the stored ppid (parent process id) is
383
- * different from the current one
399
+ /**
400
+ * We want to clear coverage files from previous runs, but at this point it is not easy because each
401
+ * worker runs a different instance of this script, so we can't just clear the coverage folder at
402
+ * the beginning of the test run.
403
+ *
404
+ * The solution is to remove the coverage folder when the stored ppid (parent process id) is
405
+ * different from the current one
384
406
  */
385
407
  var prepareCoverageReportPath = function prepareCoverageReportPath(_ref) {
386
408
  var coveragePath = _ref.coveragePath;
387
409
  var ppidFile = path.join(coveragePath, '.ppid');
410
+ var nycOutputPath = path.join(coveragePath, '.nyc_output');
388
411
  var ppid = process.ppid.toString();
389
412
  if (!fs.existsSync(ppidFile) || fs.readFileSync(ppidFile, 'utf-8') !== ppid) {
390
413
  // the condition is just to make sure we don't remove files outside the repo
391
414
  if (getRootPath() === process.cwd() && path.normalize(coveragePath).startsWith(process.cwd())) {
392
- fs.rmSync(coveragePath, {
415
+ fs.rmSync(nycOutputPath, {
393
416
  recursive: true,
394
417
  force: true
395
418
  });
396
419
  }
397
- fs.mkdirSync(coveragePath, {
420
+ fs.mkdirSync(nycOutputPath, {
398
421
  recursive: true
399
422
  });
400
423
  fs.writeFileSync(ppidFile, ppid);
401
424
  }
402
425
  };
403
- /**
404
- * Asumes the code was instrumented with istanbul and the coverage report stored in `window.__coverage__`.
405
- * If not, this function does nothing.
426
+ var workerId = process.env.JEST_WORKER_ID || '0';
427
+ /**
428
+ * Writes the coverage reports into single files, one per each coverage object (path). This makes it easier to merge them.
429
+ * The `workerId` from jest is used to avoid race conditions when multiple workers are running in parallel.
430
+ */
431
+ var writeCombinedCoverage = function writeCombinedCoverage(nycOutputPath, coverage) {
432
+ Object.values(coverage).forEach(function (value) {
433
+ if (value && value.path && value.hash) {
434
+ var _currentCoverage;
435
+ var filename = path.join(nycOutputPath, value.hash + "-" + workerId + ".json");
436
+ var currentCoverage = (_currentCoverage = {}, _currentCoverage[value.path] = value, _currentCoverage);
437
+ var previousCoverage = fs.existsSync(filename) ? JSON.parse(fs.readFileSync(filename, 'utf8')) : {};
438
+ var mergedCoverage = istanbul.createCoverageMap(previousCoverage);
439
+ mergedCoverage.merge(currentCoverage);
440
+ debug('Writing merged coverage:', value.path, value.hash);
441
+ fs.writeFileSync(filename, JSON.stringify(mergedCoverage.toJSON(), null, 2));
442
+ } else {
443
+ debug('Skip write coverage. Missing path or hash:', value);
444
+ }
445
+ });
446
+ };
447
+ /**
448
+ * Assumes the code was instrumented with istanbul/nyc and the coverage report stored in `window.__coverage__`.
449
+ * If not, this function does nothing.
406
450
  */
407
- var collectCoverageIfAvailable = /*#__PURE__*/function () {
451
+ var collectFrontendCoverage = /*#__PURE__*/function () {
408
452
  var _ref3 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(_ref2) {
409
- var coveragePath, coverage, nycOutputPath;
453
+ var coveragePath, nycOutputPath, coverage;
410
454
  return _regeneratorRuntime().wrap(function _callee$(_context) {
411
455
  while (1) switch (_context.prev = _context.next) {
412
456
  case 0:
413
457
  coveragePath = _ref2.coveragePath;
414
- _context.next = 3;
458
+ nycOutputPath = path.join(coveragePath, '.nyc_output');
459
+ _context.next = 4;
415
460
  return getGlobalPage().evaluate(function () {
416
461
  return window.__coverage__;
417
462
  });
418
- case 3:
463
+ case 4:
419
464
  coverage = _context.sent;
420
465
  if (coverage) {
421
- _context.next = 6;
466
+ _context.next = 8;
422
467
  break;
423
468
  }
469
+ debug('Skipping coverage collection. No coverage found.');
424
470
  return _context.abrupt("return");
425
- case 6:
471
+ case 8:
472
+ debug('Frontend coverage found');
426
473
  prepareCoverageReportPath({
427
474
  coveragePath: coveragePath
428
475
  });
429
- nycOutputPath = path.join(coveragePath, '.nyc_output');
430
476
  fs.mkdirSync(nycOutputPath, {
431
477
  recursive: true
432
478
  });
433
- Object.values(coverage).forEach(function (cov) {
434
- if (cov && cov.path && cov.hash) {
435
- var _JSON$stringify;
436
- fs.writeFileSync(path.join(nycOutputPath, cov.hash + '.json'), JSON.stringify((_JSON$stringify = {}, _JSON$stringify[cov.path] = cov, _JSON$stringify)));
437
- }
438
- });
439
- case 10:
479
+ writeCombinedCoverage(nycOutputPath, coverage);
480
+ case 12:
440
481
  case "end":
441
482
  return _context.stop();
442
483
  }
443
484
  }, _callee);
444
485
  }));
445
- return function collectCoverageIfAvailable(_x) {
486
+ return function collectFrontendCoverage(_x) {
446
487
  return _ref3.apply(this, arguments);
447
488
  };
448
489
  }();
449
-
450
- /**
451
- * Returns true if the current path matches the spied path, including parameters
452
- */
453
- var matchPath = function matchPath(spiedPath, currentPath) {
454
- var normalizedCurrentPath = path.normalize(currentPath);
455
- var pattern = globToRegExp(spiedPath);
456
- return pattern.test(normalizedCurrentPath);
490
+ var writeCoverage = function writeCoverage(nycOutputPath, nameSuffix, coverage) {
491
+ Object.values(coverage).forEach(function (value) {
492
+ if (value && value.path && value.hash) {
493
+ var _JSON$stringify;
494
+ var filename = path.join(nycOutputPath, "" + value.hash + nameSuffix + ".json");
495
+ debug('Writing coverage:', value.path, value.hash);
496
+ fs.writeFileSync(filename, JSON.stringify((_JSON$stringify = {}, _JSON$stringify[value.path] = value, _JSON$stringify), null, 2));
497
+ } else {
498
+ debug('Skip write coverage. Missing path or hash:', value);
499
+ }
500
+ });
457
501
  };
502
+ /**
503
+ * Collects backend coverage reports from the provided URLs and stores them in the coverage folder
504
+ */
505
+ var collectBackendCoverage = /*#__PURE__*/function () {
506
+ var _ref5 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(_ref4) {
507
+ var coveragePath, coverageUrls, nycOutputPath, serverReports;
508
+ return _regeneratorRuntime().wrap(function _callee2$(_context2) {
509
+ while (1) switch (_context2.prev = _context2.next) {
510
+ case 0:
511
+ coveragePath = _ref4.coveragePath, coverageUrls = _ref4.coverageUrls;
512
+ nycOutputPath = path.join(coveragePath, '.nyc_output');
513
+ debug('Collecting backend coverage reports', coverageUrls);
514
+ _context2.next = 5;
515
+ return Promise.all(coverageUrls.map(function (url) {
516
+ return fetch(url).then(function (res) {
517
+ var _res$headers$get;
518
+ if (res.ok && res.status === 200 && (_res$headers$get = res.headers.get('content-type')) != null && _res$headers$get.includes('application/json')) {
519
+ return res.json();
520
+ }
521
+ debug('Error fetching coverage report:', {
522
+ url: url,
523
+ status: res.status
524
+ });
525
+ return null;
526
+ })["catch"](function () {
527
+ debug('Error fetching coverage report:', {
528
+ url: url
529
+ });
530
+ return null;
531
+ });
532
+ }));
533
+ case 5:
534
+ serverReports = _context2.sent;
535
+ serverReports.forEach(function (report, index) {
536
+ writeCoverage(nycOutputPath, "-backend" + index, report.coverage);
537
+ });
538
+ case 7:
539
+ case "end":
540
+ return _context2.stop();
541
+ }
542
+ }, _callee2);
543
+ }));
544
+ return function collectBackendCoverage(_x2) {
545
+ return _ref5.apply(this, arguments);
546
+ };
547
+ }();
458
548
 
459
- var _excluded = ["userAgent", "isDarkMode", "viewport", "cookies"];
460
- var _pkg$acceptanceTests, _ref, _projectConfig$covera;
549
+ var _excluded = ["captureBeyondViewport"],
550
+ _excluded2 = ["userAgent", "isDarkMode", "viewport", "cookies"];
551
+ var _pkg$acceptanceTests, _ref, _projectConfig$covera, _projectConfig$covera2;
461
552
  var LINUX_DOCKER_HOST_IP = '172.17.0.1';
462
553
  var getGlobalBrowser = function getGlobalBrowser() {
463
554
  return global.browser;
@@ -466,7 +557,7 @@ var getGlobalPage$1 = function getGlobalPage() {
466
557
  return global.page;
467
558
  };
468
559
  var isCi = /*#__PURE__*/process.argv.includes('--ci') || process.env.CI;
469
- var isUsingDockerizedChromium = !!isCi || /*#__PURE__*/new URL( /*#__PURE__*/getGlobalBrowser().wsEndpoint()).port === '9223';
560
+ var isUsingDockerizedChromium = isCi || /*#__PURE__*/new URL( /*#__PURE__*/getGlobalBrowser().wsEndpoint()).port === '9223';
470
561
  /** Check if running inside WSL */
471
562
  var isWsl = function isWsl() {
472
563
  if (process.platform !== 'linux') {
@@ -529,15 +620,17 @@ var serverHostName = /*#__PURE__*/function () {
529
620
  var rootDir = /*#__PURE__*/findRoot( /*#__PURE__*/process.cwd());
530
621
  var pkg = /*#__PURE__*/JSON.parse( /*#__PURE__*/fs.readFileSync( /*#__PURE__*/path.join(rootDir, 'package.json'), 'utf-8'));
531
622
  var projectConfig = (_pkg$acceptanceTests = pkg.acceptanceTests) != null ? _pkg$acceptanceTests : {};
623
+ debug('Project config:', projectConfig);
532
624
  var server = (_ref = isCi ? projectConfig.ciServer : projectConfig.devServer) != null ? _ref : projectConfig.server;
533
625
  var coveragePath = /*#__PURE__*/path.join(rootDir, (_projectConfig$covera = projectConfig.coveragePath) != null ? _projectConfig$covera : 'reports/coverage-acceptance');
626
+ var coverageUrls = (_projectConfig$covera2 = projectConfig.coverageUrls) != null ? _projectConfig$covera2 : [];
534
627
  var serverPort = server == null ? void 0 : server.port;
535
628
  var toMatchImageSnapshot = /*#__PURE__*/configureToMatchImageSnapshot({
536
629
  failureThreshold: 0,
537
630
  failureThresholdType: 'percent',
538
631
  customSnapshotIdentifier: function customSnapshotIdentifier(_ref2) {
539
632
  var defaultIdentifier = _ref2.defaultIdentifier;
540
- return defaultIdentifier + '-snap';
633
+ return defaultIdentifier;
541
634
  }
542
635
  });
543
636
  var calledToMatchImageSnapshotOutsideDocker = false;
@@ -627,15 +720,18 @@ var waitForPaintEnd = /*#__PURE__*/function () {
627
720
  return _ref3.apply(this, arguments);
628
721
  };
629
722
  }();
630
- var normalizeSreenshotOptions = function normalizeSreenshotOptions(options) {
631
- return options;
723
+ var normalizeSreenshotOptions = function normalizeSreenshotOptions(_temp2) {
724
+ var _ref5 = _temp2 === void 0 ? {} : _temp2,
725
+ _ref5$captureBeyondVi = _ref5.captureBeyondViewport,
726
+ captureBeyondViewport = _ref5$captureBeyondVi === void 0 ? false : _ref5$captureBeyondVi,
727
+ options = _objectWithoutPropertiesLoose(_ref5, _excluded);
728
+ // Puppeter default for captureBeyondViewport is true, but we think false is a better default.
729
+ // When this is true, the fixed elements (like fixed footers) are relative to the original page
730
+ // viewport, not to the full page, so those elements look weird in fullPage screenshots.
731
+ return _extends({}, options, {
732
+ captureBeyondViewport: captureBeyondViewport
733
+ });
632
734
  };
633
- // const normalizeSreenshotOptions = ({captureBeyondViewport = false, ...options}: ScreenshotOptions = {}) => {
634
- // // Puppeter default for captureBeyondViewport is true, but we think false is a better default.
635
- // // When this is true, the fixed elements (like fixed footers) are relative to the original page
636
- // // viewport, not to the full page, so those elements look weird in fullPage screenshots.
637
- // return {...options, captureBeyondViewport};
638
- // };
639
735
  // Puppeteer already calls scrollIntoViewIfNeeded before clicking an element. But it doesn't work in all situations
640
736
  // For example, when there is a fixed footer in the page and the element to click is under it, the browser won't scroll
641
737
  // because the element is already in the viewport (the ifNeeded part is important here). By forcing the scroll to the
@@ -648,238 +744,144 @@ var scrollIntoView = function scrollIntoView(el) {
648
744
  });
649
745
  };
650
746
  var getPageApi = function getPageApi(page) {
651
- return {
652
- type: function () {
653
- var _type = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(elementHandle, text, options) {
654
- return _regeneratorRuntime().wrap(function _callee2$(_context2) {
655
- while (1) switch (_context2.prev = _context2.next) {
656
- case 0:
657
- _context2.next = 2;
658
- return scrollIntoView(elementHandle);
659
- case 2:
660
- return _context2.abrupt("return", elementHandle.type(text, options));
661
- case 3:
662
- case "end":
663
- return _context2.stop();
664
- }
665
- }, _callee2);
666
- }));
667
- function type(_x3, _x4, _x5) {
668
- return _type.apply(this, arguments);
669
- }
670
- return type;
671
- }(),
672
- click: function () {
673
- var _click = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(elementHandle, options) {
674
- return _regeneratorRuntime().wrap(function _callee3$(_context3) {
675
- while (1) switch (_context3.prev = _context3.next) {
676
- case 0:
677
- _context3.next = 2;
678
- return scrollIntoView(elementHandle);
679
- case 2:
680
- return _context3.abrupt("return", elementHandle.click(options));
681
- case 3:
682
- case "end":
683
- return _context3.stop();
684
- }
685
- }, _callee3);
686
- }));
687
- function click(_x6, _x7) {
688
- return _click.apply(this, arguments);
689
- }
690
- return click;
691
- }(),
692
- select: function () {
693
- var _select = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(elementHandle) {
694
- var _len,
695
- values,
696
- _key,
697
- _args4 = arguments;
698
- return _regeneratorRuntime().wrap(function _callee4$(_context4) {
699
- while (1) switch (_context4.prev = _context4.next) {
700
- case 0:
701
- _context4.next = 2;
702
- return scrollIntoView(elementHandle);
703
- case 2:
704
- for (_len = _args4.length, values = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
705
- values[_key - 1] = _args4[_key];
706
- }
707
- return _context4.abrupt("return", elementHandle.select.apply(elementHandle, values));
708
- case 4:
709
- case "end":
710
- return _context4.stop();
711
- }
712
- }, _callee4);
713
- }));
714
- function select(_x8) {
715
- return _select.apply(this, arguments);
716
- }
717
- return select;
718
- }(),
719
- screenshot: function () {
720
- var _screenshot = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(options) {
721
- return _regeneratorRuntime().wrap(function _callee5$(_context5) {
722
- while (1) switch (_context5.prev = _context5.next) {
723
- case 0:
724
- if (options != null && options.skipNetworkWait) {
725
- _context5.next = 3;
726
- break;
727
- }
747
+ var api = Object.create(page);
748
+ api.type = /*#__PURE__*/function () {
749
+ var _ref6 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(elementHandle, text, options) {
750
+ return _regeneratorRuntime().wrap(function _callee2$(_context2) {
751
+ while (1) switch (_context2.prev = _context2.next) {
752
+ case 0:
753
+ _context2.next = 2;
754
+ return scrollIntoView(elementHandle);
755
+ case 2:
756
+ return _context2.abrupt("return", elementHandle.type(text, options));
757
+ case 3:
758
+ case "end":
759
+ return _context2.stop();
760
+ }
761
+ }, _callee2);
762
+ }));
763
+ return function (_x3, _x4, _x5) {
764
+ return _ref6.apply(this, arguments);
765
+ };
766
+ }();
767
+ api.click = /*#__PURE__*/function () {
768
+ var _ref7 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(elementHandle, options) {
769
+ return _regeneratorRuntime().wrap(function _callee3$(_context3) {
770
+ while (1) switch (_context3.prev = _context3.next) {
771
+ case 0:
772
+ _context3.next = 2;
773
+ return scrollIntoView(elementHandle);
774
+ case 2:
775
+ return _context3.abrupt("return", elementHandle.click(options));
776
+ case 3:
777
+ case "end":
778
+ return _context3.stop();
779
+ }
780
+ }, _callee3);
781
+ }));
782
+ return function (_x6, _x7) {
783
+ return _ref7.apply(this, arguments);
784
+ };
785
+ }();
786
+ api.select = /*#__PURE__*/function () {
787
+ var _ref8 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4(elementHandle) {
788
+ var _len,
789
+ values,
790
+ _key,
791
+ _args4 = arguments;
792
+ return _regeneratorRuntime().wrap(function _callee4$(_context4) {
793
+ while (1) switch (_context4.prev = _context4.next) {
794
+ case 0:
795
+ _context4.next = 2;
796
+ return scrollIntoView(elementHandle);
797
+ case 2:
798
+ for (_len = _args4.length, values = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
799
+ values[_key - 1] = _args4[_key];
800
+ }
801
+ return _context4.abrupt("return", elementHandle.select.apply(elementHandle, values));
802
+ case 4:
803
+ case "end":
804
+ return _context4.stop();
805
+ }
806
+ }, _callee4);
807
+ }));
808
+ return function (_x8) {
809
+ return _ref8.apply(this, arguments);
810
+ };
811
+ }();
812
+ api.screenshot = /*#__PURE__*/function () {
813
+ var _ref9 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(options) {
814
+ return _regeneratorRuntime().wrap(function _callee5$(_context5) {
815
+ while (1) switch (_context5.prev = _context5.next) {
816
+ case 0:
817
+ if (options != null && options.skipNetworkWait) {
728
818
  _context5.next = 3;
729
- return page.waitForNetworkIdle();
730
- case 3:
731
- _context5.next = 5;
732
- return waitForPaintEnd(page, options);
733
- case 5:
734
- return _context5.abrupt("return", page.screenshot(normalizeSreenshotOptions(options)));
735
- case 6:
736
- case "end":
737
- return _context5.stop();
738
- }
739
- }, _callee5);
740
- }));
741
- function screenshot(_x9) {
742
- return _screenshot.apply(this, arguments);
743
- }
744
- return screenshot;
745
- }(),
746
- clear: function () {
747
- var _clear = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6(elementHandle) {
748
- return _regeneratorRuntime().wrap(function _callee6$(_context6) {
749
- while (1) switch (_context6.prev = _context6.next) {
750
- case 0:
751
- _context6.next = 2;
752
- return elementHandle.click({
753
- clickCount: 3
754
- });
755
- case 2:
756
- _context6.next = 4;
757
- return elementHandle.press('Delete');
758
- case 4:
759
- case "end":
760
- return _context6.stop();
761
- }
762
- }, _callee6);
763
- }));
764
- function clear(_x10) {
765
- return _clear.apply(this, arguments);
766
- }
767
- return clear;
768
- }(),
769
- // For some reason, puppeteer browserContext.overridePermissions doesn't work with newer chrome versions.
770
- // This workaround polyfills the browser geolocation api to return the mocked position
771
- setGeolocation: function setGeolocation(position) {
772
- return page.evaluate(function (position) {
773
- window.navigator.geolocation.getCurrentPosition = function (callback) {
774
- // @ts-expect-error - puppeteer's setGeoLocation does not expect a timestamp to be passed
775
- callback({
776
- coords: position
777
- });
778
- };
779
- }, position);
780
- },
781
- $: page.$.bind(page),
782
- $$: page.$$.bind(page),
783
- $$eval: page.$$eval.bind(page),
784
- $eval: page.$eval.bind(page),
785
- accessibility: page.accessibility,
786
- addScriptTag: page.addScriptTag.bind(page),
787
- addStyleTag: page.addStyleTag.bind(page),
788
- authenticate: page.authenticate.bind(page),
789
- bringToFront: page.bringToFront.bind(page),
790
- browser: page.browser.bind(page),
791
- browserContext: page.browserContext.bind(page),
792
- close: page.close.bind(page),
793
- content: page.content,
794
- cookies: page.cookies.bind(page),
795
- coverage: page.coverage,
796
- createCDPSession: page.createCDPSession.bind(page),
797
- createPDFStream: page.createPDFStream.bind(page),
798
- deleteCookie: page.deleteCookie.bind(page),
799
- emit: page.emit.bind(page),
800
- emulate: page.emulate.bind(page),
801
- emulateCPUThrottling: page.emulateCPUThrottling.bind(page),
802
- emulateIdleState: page.emulateIdleState.bind(page),
803
- emulateMediaFeatures: page.emulateMediaFeatures.bind(page),
804
- emulateMediaType: page.emulateMediaType.bind(page),
805
- emulateNetworkConditions: page.emulateNetworkConditions.bind(page),
806
- emulateTimezone: page.emulateTimezone.bind(page),
807
- emulateVisionDeficiency: page.emulateVisionDeficiency.bind(page),
808
- evaluate: page.evaluate.bind(page),
809
- evaluateHandle: page.evaluateHandle.bind(page),
810
- evaluateOnNewDocument: page.evaluateOnNewDocument.bind(page),
811
- exposeFunction: page.exposeFunction.bind(page),
812
- focus: page.focus.bind(page),
813
- frames: page.frames.bind(page),
814
- getDefaultTimeout: page.getDefaultTimeout.bind(page),
815
- goBack: page.goBack.bind(page),
816
- goForward: page.goForward.bind(page),
817
- "goto": page["goto"].bind(page),
818
- hover: page.hover.bind(page),
819
- isClosed: page.isClosed.bind(page),
820
- isDragInterceptionEnabled: page.isDragInterceptionEnabled.bind(page),
821
- isJavaScriptEnabled: page.isJavaScriptEnabled.bind(page),
822
- isServiceWorkerBypassed: page.isServiceWorkerBypassed.bind(page),
823
- keyboard: page.keyboard,
824
- listenerCount: page.listenerCount.bind(page),
825
- locator: page.locator.bind(page),
826
- mainFrame: page.mainFrame.bind(page),
827
- metrics: page.metrics.bind(page),
828
- mouse: page.mouse,
829
- off: page.off.bind(page),
830
- on: page.on.bind(page),
831
- once: page.once.bind(page),
832
- pdf: page.pdf,
833
- queryObjects: page.queryObjects.bind(page),
834
- reload: page.reload.bind(page),
835
- removeAllListeners: page.removeAllListeners.bind(page),
836
- removeExposedFunction: page.removeExposedFunction.bind(page),
837
- removeScriptToEvaluateOnNewDocument: page.removeScriptToEvaluateOnNewDocument.bind(page),
838
- screencast: page.screencast,
839
- setBypassCSP: page.setBypassCSP.bind(page),
840
- setBypassServiceWorker: page.setBypassServiceWorker.bind(page),
841
- setCacheEnabled: page.setCacheEnabled.bind(page),
842
- setContent: page.setContent.bind(page),
843
- setCookie: page.setCookie.bind(page),
844
- setDefaultNavigationTimeout: page.setDefaultNavigationTimeout.bind(page),
845
- setDefaultTimeout: page.setDefaultTimeout.bind(page),
846
- setDragInterception: page.setDragInterception.bind(page),
847
- setExtraHTTPHeaders: page.setExtraHTTPHeaders.bind(page),
848
- setJavaScriptEnabled: page.setJavaScriptEnabled.bind(page),
849
- setOfflineMode: page.setOfflineMode.bind(page),
850
- setRequestInterception: page.setRequestInterception.bind(page),
851
- setUserAgent: page.setUserAgent.bind(page),
852
- setViewport: page.setViewport.bind(page),
853
- tap: page.tap.bind(page),
854
- target: page.target.bind(page),
855
- title: page.title,
856
- touchscreen: page.touchscreen,
857
- tracing: page.tracing,
858
- url: page.url,
859
- viewport: page.viewport,
860
- waitForDevicePrompt: page.waitForDevicePrompt.bind(page),
861
- waitForFileChooser: page.waitForFileChooser.bind(page),
862
- waitForFrame: page.waitForFrame.bind(page),
863
- waitForFunction: page.waitForFunction.bind(page),
864
- waitForNavigation: page.waitForNavigation.bind(page),
865
- waitForNetworkIdle: page.waitForNetworkIdle.bind(page),
866
- waitForRequest: page.waitForRequest.bind(page),
867
- waitForResponse: page.waitForResponse.bind(page),
868
- waitForSelector: page.waitForSelector.bind(page),
869
- workers: page.workers
819
+ break;
820
+ }
821
+ _context5.next = 3;
822
+ return page.waitForNetworkIdle();
823
+ case 3:
824
+ _context5.next = 5;
825
+ return waitForPaintEnd(page, options);
826
+ case 5:
827
+ return _context5.abrupt("return", page.screenshot(normalizeSreenshotOptions(options)));
828
+ case 6:
829
+ case "end":
830
+ return _context5.stop();
831
+ }
832
+ }, _callee5);
833
+ }));
834
+ return function (_x9) {
835
+ return _ref9.apply(this, arguments);
836
+ };
837
+ }();
838
+ api.clear = /*#__PURE__*/function () {
839
+ var _ref10 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6(elementHandle) {
840
+ return _regeneratorRuntime().wrap(function _callee6$(_context6) {
841
+ while (1) switch (_context6.prev = _context6.next) {
842
+ case 0:
843
+ _context6.next = 2;
844
+ return elementHandle.click({
845
+ clickCount: 3
846
+ });
847
+ case 2:
848
+ _context6.next = 4;
849
+ return elementHandle.press('Delete');
850
+ case 4:
851
+ case "end":
852
+ return _context6.stop();
853
+ }
854
+ }, _callee6);
855
+ }));
856
+ return function (_x10) {
857
+ return _ref10.apply(this, arguments);
858
+ };
859
+ }();
860
+ // For some reason, puppeteer browserContext.overridePermissions doesn't work with newer chrome versions.
861
+ // This workaround polyfills the browser geolocation api to return the mocked position
862
+ api.setGeolocation = function (position) {
863
+ return page.evaluate(function (position) {
864
+ window.navigator.geolocation.getCurrentPosition = function (callback) {
865
+ // @ts-expect-error - puppeteer's setGeoLocation does not expect a timestamp to be passed
866
+ callback({
867
+ coords: position
868
+ });
869
+ };
870
+ }, position);
870
871
  };
872
+ return api;
871
873
  };
872
874
  var needsRequestInterception = false;
873
875
  var requestHandlers = [];
874
876
  var requestInterceptor = function requestInterceptor(req) {
875
877
  var _requestHandlers$find;
876
- var _ref5 = (_requestHandlers$find = requestHandlers.find(function (_ref6) {
877
- var matcher = _ref6.matcher;
878
+ var _ref11 = (_requestHandlers$find = requestHandlers.find(function (_ref12) {
879
+ var matcher = _ref12.matcher;
878
880
  return matcher(req);
879
881
  })) != null ? _requestHandlers$find : {
880
882
  handler: null
881
883
  },
882
- handler = _ref5.handler;
884
+ handler = _ref11.handler;
883
885
  if (!handler) {
884
886
  req["continue"]();
885
887
  return;
@@ -896,12 +898,12 @@ var interceptRequest = function interceptRequest(matcher) {
896
898
  });
897
899
  return spy;
898
900
  };
899
- var createApiEndpointMock = function createApiEndpointMock(_temp2) {
900
- var _ref8;
901
- var _ref7 = _temp2 === void 0 ? {} : _temp2,
902
- origin = _ref7.origin,
903
- baseUrl = _ref7.baseUrl;
904
- var originRegExp = globToRegExp((_ref8 = origin != null ? origin : baseUrl) != null ? _ref8 : '*');
901
+ var createApiEndpointMock = function createApiEndpointMock(_temp3) {
902
+ var _ref14;
903
+ var _ref13 = _temp3 === void 0 ? {} : _temp3,
904
+ origin = _ref13.origin,
905
+ baseUrl = _ref13.baseUrl;
906
+ var originRegExp = globToRegExp((_ref14 = origin != null ? origin : baseUrl) != null ? _ref14 : '*');
905
907
  interceptRequest(function (req) {
906
908
  var _URL = new URL(req.url()),
907
909
  origin = _URL.origin;
@@ -949,12 +951,12 @@ var createApiEndpointMock = function createApiEndpointMock(_temp2) {
949
951
  };
950
952
  };
951
953
  var openPage = /*#__PURE__*/function () {
952
- var _ref10 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee7(_ref9) {
954
+ var _ref16 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee7(_ref15) {
953
955
  var userAgent, isDarkMode, viewport, cookies, urlConfig, url, currentUserAgent, page, connectionError;
954
956
  return _regeneratorRuntime().wrap(function _callee7$(_context7) {
955
957
  while (1) switch (_context7.prev = _context7.next) {
956
958
  case 0:
957
- userAgent = _ref9.userAgent, isDarkMode = _ref9.isDarkMode, viewport = _ref9.viewport, cookies = _ref9.cookies, urlConfig = /*#__PURE__*/_objectWithoutPropertiesLoose(_ref9, _excluded);
959
+ userAgent = _ref15.userAgent, isDarkMode = _ref15.isDarkMode, viewport = _ref15.viewport, cookies = _ref15.cookies, urlConfig = /*#__PURE__*/_objectWithoutPropertiesLoose(_ref15, _excluded2);
958
960
  url = function () {
959
961
  if (urlConfig.url !== undefined) {
960
962
  return urlConfig.url;
@@ -973,45 +975,46 @@ var openPage = /*#__PURE__*/function () {
973
975
  }
974
976
  return protocol + "://" + hostname + ":" + port + path;
975
977
  }();
978
+ debug('Opening page:', url);
976
979
  _context7.t0 = userAgent;
977
980
  if (_context7.t0) {
978
- _context7.next = 7;
981
+ _context7.next = 8;
979
982
  break;
980
983
  }
981
- _context7.next = 6;
984
+ _context7.next = 7;
982
985
  return getGlobalBrowser().userAgent();
983
- case 6:
984
- _context7.t0 = _context7.sent;
985
986
  case 7:
987
+ _context7.t0 = _context7.sent;
988
+ case 8:
986
989
  currentUserAgent = _context7.t0;
987
990
  page = getGlobalPage$1();
988
- _context7.next = 11;
991
+ _context7.next = 12;
989
992
  return page.bringToFront();
990
- case 11:
993
+ case 12:
991
994
  if (!viewport) {
992
- _context7.next = 14;
995
+ _context7.next = 15;
993
996
  break;
994
997
  }
995
- _context7.next = 14;
998
+ _context7.next = 15;
996
999
  return page.setViewport(viewport);
997
- case 14:
1000
+ case 15:
998
1001
  if (!cookies) {
999
- _context7.next = 17;
1002
+ _context7.next = 18;
1000
1003
  break;
1001
1004
  }
1002
- _context7.next = 17;
1005
+ _context7.next = 18;
1003
1006
  return page.setCookie.apply(page, cookies);
1004
- case 17:
1005
- _context7.next = 19;
1007
+ case 18:
1008
+ _context7.next = 20;
1006
1009
  return page.setUserAgent(currentUserAgent + " acceptance-test");
1007
- case 19:
1008
- _context7.next = 21;
1010
+ case 20:
1011
+ _context7.next = 22;
1009
1012
  return page.emulateMediaFeatures([{
1010
1013
  name: 'prefers-color-scheme',
1011
1014
  value: isDarkMode ? 'dark' : 'light'
1012
1015
  }]);
1013
- case 21:
1014
- _context7.next = 23;
1016
+ case 22:
1017
+ _context7.next = 24;
1015
1018
  return page.evaluateOnNewDocument(function (viewport) {
1016
1019
  var _viewport$safeAreaIns;
1017
1020
  var overriddenSafeAreaInsets = !viewport ? [] : Object.keys((_viewport$safeAreaIns = viewport == null ? void 0 : viewport.safeAreaInset) != null ? _viewport$safeAreaIns : {}).map(function (key) {
@@ -1025,53 +1028,53 @@ var openPage = /*#__PURE__*/function () {
1025
1028
  document.head.appendChild(style);
1026
1029
  });
1027
1030
  }, viewport);
1028
- case 23:
1031
+ case 24:
1029
1032
  if (!needsRequestInterception) {
1030
- _context7.next = 27;
1033
+ _context7.next = 28;
1031
1034
  break;
1032
1035
  }
1033
- _context7.next = 26;
1036
+ _context7.next = 27;
1034
1037
  return page.setRequestInterception(true);
1035
- case 26:
1036
- page.on('request', requestInterceptor);
1037
1038
  case 27:
1038
- _context7.prev = 27;
1039
- _context7.next = 30;
1039
+ page.on('request', requestInterceptor);
1040
+ case 28:
1041
+ _context7.prev = 28;
1042
+ _context7.next = 31;
1040
1043
  return page["goto"](url);
1041
- case 30:
1042
- _context7.next = 41;
1044
+ case 31:
1045
+ _context7.next = 42;
1043
1046
  break;
1044
- case 32:
1045
- _context7.prev = 32;
1046
- _context7.t1 = _context7["catch"](27);
1047
+ case 33:
1048
+ _context7.prev = 33;
1049
+ _context7.t1 = _context7["catch"](28);
1047
1050
  if (!_context7.t1.message.includes('net::ERR_CONNECTION_REFUSED')) {
1048
- _context7.next = 40;
1051
+ _context7.next = 41;
1049
1052
  break;
1050
1053
  }
1051
1054
  connectionError = new Error("Could not connect to " + url + ". Is the server running?");
1052
1055
  Error.captureStackTrace(connectionError, openPage);
1053
1056
  throw connectionError;
1054
- case 40:
1055
- throw _context7.t1;
1056
1057
  case 41:
1057
- _context7.next = 43;
1058
+ throw _context7.t1;
1059
+ case 42:
1060
+ _context7.next = 44;
1058
1061
  return page.waitForFunction('document.fonts.status === "loaded"');
1059
- case 43:
1060
- return _context7.abrupt("return", getPageApi(page));
1061
1062
  case 44:
1063
+ return _context7.abrupt("return", getPageApi(page));
1064
+ case 45:
1062
1065
  case "end":
1063
1066
  return _context7.stop();
1064
1067
  }
1065
- }, _callee7, null, [[27, 32]]);
1068
+ }, _callee7, null, [[28, 33]]);
1066
1069
  }));
1067
1070
  return function openPage(_x11) {
1068
- return _ref10.apply(this, arguments);
1071
+ return _ref16.apply(this, arguments);
1069
1072
  };
1070
1073
  }();
1071
- var buildQueryMethods = function buildQueryMethods(_temp3) {
1072
- var _ref11 = _temp3 === void 0 ? {} : _temp3,
1073
- page = _ref11.page,
1074
- element = _ref11.element;
1074
+ var buildQueryMethods = function buildQueryMethods(_temp4) {
1075
+ var _ref17 = _temp4 === void 0 ? {} : _temp4,
1076
+ page = _ref17.page,
1077
+ element = _ref17.element;
1075
1078
  var boundQueries = {};
1076
1079
  var _loop = function _loop() {
1077
1080
  var _Object$entries$_i = _Object$entries[_i],
@@ -1116,7 +1119,7 @@ var buildQueryMethods = function buildQueryMethods(_temp3) {
1116
1119
  elementHandle = _context12.sent;
1117
1120
  newElementHandle = Object.create(elementHandle);
1118
1121
  newElementHandle.screenshot = /*#__PURE__*/function () {
1119
- var _ref13 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee8(options) {
1122
+ var _ref19 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee8(options) {
1120
1123
  return _regeneratorRuntime().wrap(function _callee8$(_context8) {
1121
1124
  while (1) switch (_context8.prev = _context8.next) {
1122
1125
  case 0:
@@ -1140,11 +1143,11 @@ var buildQueryMethods = function buildQueryMethods(_temp3) {
1140
1143
  }, _callee8);
1141
1144
  }));
1142
1145
  return function (_x12) {
1143
- return _ref13.apply(this, arguments);
1146
+ return _ref19.apply(this, arguments);
1144
1147
  };
1145
1148
  }();
1146
1149
  newElementHandle.click = /*#__PURE__*/function () {
1147
- var _ref14 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee9(options) {
1150
+ var _ref20 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee9(options) {
1148
1151
  return _regeneratorRuntime().wrap(function _callee9$(_context9) {
1149
1152
  while (1) switch (_context9.prev = _context9.next) {
1150
1153
  case 0:
@@ -1159,11 +1162,11 @@ var buildQueryMethods = function buildQueryMethods(_temp3) {
1159
1162
  }, _callee9);
1160
1163
  }));
1161
1164
  return function (_x13) {
1162
- return _ref14.apply(this, arguments);
1165
+ return _ref20.apply(this, arguments);
1163
1166
  };
1164
1167
  }();
1165
1168
  newElementHandle.type = /*#__PURE__*/function () {
1166
- var _ref15 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee10(text, options) {
1169
+ var _ref21 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee10(text, options) {
1167
1170
  return _regeneratorRuntime().wrap(function _callee10$(_context10) {
1168
1171
  while (1) switch (_context10.prev = _context10.next) {
1169
1172
  case 0:
@@ -1178,7 +1181,7 @@ var buildQueryMethods = function buildQueryMethods(_temp3) {
1178
1181
  }, _callee10);
1179
1182
  }));
1180
1183
  return function (_x14, _x15) {
1181
- return _ref15.apply(this, arguments);
1184
+ return _ref21.apply(this, arguments);
1182
1185
  };
1183
1186
  }();
1184
1187
  newElementHandle.select = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee11() {
@@ -1240,39 +1243,62 @@ afterEach( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().ma
1240
1243
  return _regeneratorRuntime().wrap(function _callee14$(_context14) {
1241
1244
  while (1) switch (_context14.prev = _context14.next) {
1242
1245
  case 0:
1243
- _context14.next = 2;
1244
- return collectCoverageIfAvailable({
1246
+ if (!process.env.COLLECT_ACCEPTANCE_COVERAGE) {
1247
+ _context14.next = 3;
1248
+ break;
1249
+ }
1250
+ _context14.next = 3;
1251
+ return collectFrontendCoverage({
1245
1252
  coveragePath: coveragePath
1246
1253
  });
1247
- case 2:
1248
- _context14.prev = 2;
1254
+ case 3:
1255
+ _context14.prev = 3;
1249
1256
  page = getGlobalPage$1();
1250
1257
  requestHandlers = [];
1251
1258
  needsRequestInterception = false;
1252
1259
  page.off('request', requestInterceptor);
1253
1260
  // clear tab, this way we clear the DOM and stop js execution or pending requests
1254
- _context14.next = 9;
1261
+ _context14.next = 10;
1255
1262
  return page["goto"]('about:blank');
1256
- case 9:
1257
- _context14.next = 13;
1263
+ case 10:
1264
+ _context14.next = 14;
1258
1265
  break;
1259
- case 11:
1260
- _context14.prev = 11;
1261
- _context14.t0 = _context14["catch"](2);
1262
- case 13:
1266
+ case 12:
1267
+ _context14.prev = 12;
1268
+ _context14.t0 = _context14["catch"](3);
1269
+ case 14:
1263
1270
  case "end":
1264
1271
  return _context14.stop();
1265
1272
  }
1266
- }, _callee14, null, [[2, 11]]);
1273
+ }, _callee14, null, [[3, 12]]);
1274
+ })));
1275
+ afterAll( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee15() {
1276
+ return _regeneratorRuntime().wrap(function _callee15$(_context15) {
1277
+ while (1) switch (_context15.prev = _context15.next) {
1278
+ case 0:
1279
+ if (!process.env.COLLECT_ACCEPTANCE_COVERAGE) {
1280
+ _context15.next = 3;
1281
+ break;
1282
+ }
1283
+ _context15.next = 3;
1284
+ return collectBackendCoverage({
1285
+ coveragePath: coveragePath,
1286
+ coverageUrls: coverageUrls
1287
+ });
1288
+ case 3:
1289
+ case "end":
1290
+ return _context15.stop();
1291
+ }
1292
+ }, _callee15);
1267
1293
  })));
1268
- /**
1269
- * Returns a new path to the file that can be used by chromium in acceptance tests
1270
- *
1271
- * To be able to use `element.uploadFile()` in a dockerized chromium, the file must exist in the
1272
- * host and the docker, and both sides must use the same path.
1273
- *
1274
- * To workaround this bug or limitation, this function prepares the file by copying it to /tmp in
1275
- * the host and the container.
1294
+ /**
1295
+ * Returns a new path to the file that can be used by chromium in acceptance tests
1296
+ *
1297
+ * To be able to use `element.uploadFile()` in a dockerized chromium, the file must exist in the
1298
+ * host and the docker, and both sides must use the same path.
1299
+ *
1300
+ * To workaround this bug or limitation, this function prepares the file by copying it to /tmp in
1301
+ * the host and the container.
1276
1302
  */
1277
1303
  var prepareFile = function prepareFile(filepath) {
1278
1304
  var isLocal = !isCi;
@@ -1292,8 +1318,8 @@ var prepareFile = function prepareFile(filepath) {
1292
1318
  return filepath;
1293
1319
  }
1294
1320
  };
1295
- /**
1296
- * A convenience method to defer an expectation
1321
+ /**
1322
+ * A convenience method to defer an expectation
1297
1323
  */
1298
1324
  var wait = function wait(expectation, timeout, interval) {
1299
1325
  if (timeout === void 0) {
@@ -1339,44 +1365,44 @@ var waitForElementToBeRemoved = function waitForElementToBeRemoved(element, time
1339
1365
  }
1340
1366
  var startStack = new Error().stack;
1341
1367
  var wait = /*#__PURE__*/function () {
1342
- var _ref19 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee15() {
1368
+ var _ref26 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee16() {
1343
1369
  var t0, box;
1344
- return _regeneratorRuntime().wrap(function _callee15$(_context15) {
1345
- while (1) switch (_context15.prev = _context15.next) {
1370
+ return _regeneratorRuntime().wrap(function _callee16$(_context16) {
1371
+ while (1) switch (_context16.prev = _context16.next) {
1346
1372
  case 0:
1347
1373
  t0 = Date.now();
1348
1374
  case 1:
1349
1375
  if (!(Date.now() - t0 < timeout)) {
1350
- _context15.next = 11;
1376
+ _context16.next = 11;
1351
1377
  break;
1352
1378
  }
1353
- _context15.next = 4;
1379
+ _context16.next = 4;
1354
1380
  return element.boundingBox();
1355
1381
  case 4:
1356
- box = _context15.sent;
1382
+ box = _context16.sent;
1357
1383
  if (box) {
1358
- _context15.next = 7;
1384
+ _context16.next = 7;
1359
1385
  break;
1360
1386
  }
1361
- return _context15.abrupt("return");
1387
+ return _context16.abrupt("return");
1362
1388
  case 7:
1363
- _context15.next = 9;
1389
+ _context16.next = 9;
1364
1390
  return new Promise(function (resolve) {
1365
1391
  return setTimeout(resolve, interval);
1366
1392
  });
1367
1393
  case 9:
1368
- _context15.next = 1;
1394
+ _context16.next = 1;
1369
1395
  break;
1370
1396
  case 11:
1371
1397
  throw new Error('Element not removed');
1372
1398
  case 12:
1373
1399
  case "end":
1374
- return _context15.stop();
1400
+ return _context16.stop();
1375
1401
  }
1376
- }, _callee15);
1402
+ }, _callee16);
1377
1403
  }));
1378
1404
  return function wait() {
1379
- return _ref19.apply(this, arguments);
1405
+ return _ref26.apply(this, arguments);
1380
1406
  };
1381
1407
  }();
1382
1408
  return wait()["catch"](function (error) {