@bigbinary/neeto-playwright-commons 1.8.16 → 1.8.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.cjs.js CHANGED
@@ -3,16 +3,17 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var test = require('@playwright/test');
6
- var require$$0 = require('fs');
6
+ var require$$0$1 = require('fs');
7
7
  var ramda = require('ramda');
8
8
  var faker = require('@faker-js/faker');
9
9
  var MailosaurClient = require('mailosaur');
10
10
  var dayjs = require('dayjs');
11
- var require$$2 = require('os');
12
- var require$$0$1 = require('path');
13
- var require$$0$2 = require('util');
14
- var require$$0$3 = require('stream');
15
- var require$$0$4 = require('events');
11
+ var require$$1 = require('tty');
12
+ var require$$0$3 = require('util');
13
+ var require$$0$2 = require('os');
14
+ var require$$0$4 = require('path');
15
+ var require$$0$5 = require('stream');
16
+ var require$$0$6 = require('events');
16
17
  var playwrightI18nextFixture = require('playwright-i18next-fixture');
17
18
  var neetoCist = require('@bigbinary/neeto-cist');
18
19
  var require$$3 = require('crypto');
@@ -38,15 +39,16 @@ function _interopNamespace(e) {
38
39
  }
39
40
 
40
41
  var test__default = /*#__PURE__*/_interopDefaultLegacy(test);
41
- var require$$0__namespace = /*#__PURE__*/_interopNamespace(require$$0);
42
- var require$$0__default$3 = /*#__PURE__*/_interopDefaultLegacy(require$$0);
42
+ var require$$0__namespace = /*#__PURE__*/_interopNamespace(require$$0$1);
43
+ var require$$0__default$4 = /*#__PURE__*/_interopDefaultLegacy(require$$0$1);
43
44
  var MailosaurClient__default = /*#__PURE__*/_interopDefaultLegacy(MailosaurClient);
44
45
  var dayjs__default = /*#__PURE__*/_interopDefaultLegacy(dayjs);
45
- var require$$2__default = /*#__PURE__*/_interopDefaultLegacy(require$$2);
46
- var require$$0__default = /*#__PURE__*/_interopDefaultLegacy(require$$0$1);
47
- var require$$0__default$1 = /*#__PURE__*/_interopDefaultLegacy(require$$0$2);
48
- var require$$0__default$2 = /*#__PURE__*/_interopDefaultLegacy(require$$0$3);
49
- var require$$0__default$4 = /*#__PURE__*/_interopDefaultLegacy(require$$0$4);
46
+ var require$$1__default = /*#__PURE__*/_interopDefaultLegacy(require$$1);
47
+ var require$$0__default$1 = /*#__PURE__*/_interopDefaultLegacy(require$$0$3);
48
+ var require$$0__default = /*#__PURE__*/_interopDefaultLegacy(require$$0$2);
49
+ var require$$0__default$2 = /*#__PURE__*/_interopDefaultLegacy(require$$0$4);
50
+ var require$$0__default$3 = /*#__PURE__*/_interopDefaultLegacy(require$$0$5);
51
+ var require$$0__default$5 = /*#__PURE__*/_interopDefaultLegacy(require$$0$6);
50
52
  var require$$3__default = /*#__PURE__*/_interopDefaultLegacy(require$$3);
51
53
 
52
54
  const ENVIRONMENT = {
@@ -193,12 +195,12 @@ const COMMON_SELECTORS = {
193
195
 
194
196
  class CustomCommands {
195
197
  constructor(page, request, baseURL = process.env.BASE_URL) {
196
- this.interceptMultipleResponses = ({ responseUrl = "", times = 1, baseUrl, customPageContext, timeout = 35000, } = {}) => {
198
+ this.interceptMultipleResponses = ({ responseUrl = "", responseStatus = 200, times = 1, baseUrl, customPageContext, timeout = 35000, } = {}) => {
197
199
  const pageContext = customPageContext !== null && customPageContext !== void 0 ? customPageContext : this.page;
198
200
  return Promise.all([...new Array(times)].map(() => pageContext.waitForResponse((response) => {
199
201
  var _a, _b, _c;
200
202
  if (response.request().resourceType() === "xhr" &&
201
- response.status() === 200 &&
203
+ response.status() === responseStatus &&
202
204
  response.url().includes(responseUrl) &&
203
205
  response.url().startsWith((_a = baseUrl !== null && baseUrl !== void 0 ? baseUrl : this.baseURL) !== null && _a !== void 0 ? _a : "") &&
204
206
  !this.responses.includes((_b = response.headers()) === null || _b === void 0 ? void 0 : _b["x-request-id"])) {
@@ -350,6 +352,2821 @@ const generateStagingData = (product = "invoice") => {
350
352
  };
351
353
  };
352
354
 
355
+ var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
356
+
357
+ function getDefaultExportFromCjs (x) {
358
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
359
+ }
360
+
361
+ function getAugmentedNamespace(n) {
362
+ var f = n.default;
363
+ if (typeof f == "function") {
364
+ var a = function () {
365
+ return f.apply(this, arguments);
366
+ };
367
+ a.prototype = f.prototype;
368
+ } else a = {};
369
+ Object.defineProperty(a, '__esModule', {value: true});
370
+ Object.keys(n).forEach(function (k) {
371
+ var d = Object.getOwnPropertyDescriptor(n, k);
372
+ Object.defineProperty(a, k, d.get ? d : {
373
+ enumerable: true,
374
+ get: function () {
375
+ return n[k];
376
+ }
377
+ });
378
+ });
379
+ return a;
380
+ }
381
+
382
+ var src = {exports: {}};
383
+
384
+ var browser$1 = {exports: {}};
385
+
386
+ /**
387
+ * Helpers.
388
+ */
389
+
390
+ var ms;
391
+ var hasRequiredMs;
392
+
393
+ function requireMs () {
394
+ if (hasRequiredMs) return ms;
395
+ hasRequiredMs = 1;
396
+ var s = 1000;
397
+ var m = s * 60;
398
+ var h = m * 60;
399
+ var d = h * 24;
400
+ var w = d * 7;
401
+ var y = d * 365.25;
402
+
403
+ /**
404
+ * Parse or format the given `val`.
405
+ *
406
+ * Options:
407
+ *
408
+ * - `long` verbose formatting [false]
409
+ *
410
+ * @param {String|Number} val
411
+ * @param {Object} [options]
412
+ * @throws {Error} throw an error if val is not a non-empty string or a number
413
+ * @return {String|Number}
414
+ * @api public
415
+ */
416
+
417
+ ms = function(val, options) {
418
+ options = options || {};
419
+ var type = typeof val;
420
+ if (type === 'string' && val.length > 0) {
421
+ return parse(val);
422
+ } else if (type === 'number' && isFinite(val)) {
423
+ return options.long ? fmtLong(val) : fmtShort(val);
424
+ }
425
+ throw new Error(
426
+ 'val is not a non-empty string or a valid number. val=' +
427
+ JSON.stringify(val)
428
+ );
429
+ };
430
+
431
+ /**
432
+ * Parse the given `str` and return milliseconds.
433
+ *
434
+ * @param {String} str
435
+ * @return {Number}
436
+ * @api private
437
+ */
438
+
439
+ function parse(str) {
440
+ str = String(str);
441
+ if (str.length > 100) {
442
+ return;
443
+ }
444
+ var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
445
+ str
446
+ );
447
+ if (!match) {
448
+ return;
449
+ }
450
+ var n = parseFloat(match[1]);
451
+ var type = (match[2] || 'ms').toLowerCase();
452
+ switch (type) {
453
+ case 'years':
454
+ case 'year':
455
+ case 'yrs':
456
+ case 'yr':
457
+ case 'y':
458
+ return n * y;
459
+ case 'weeks':
460
+ case 'week':
461
+ case 'w':
462
+ return n * w;
463
+ case 'days':
464
+ case 'day':
465
+ case 'd':
466
+ return n * d;
467
+ case 'hours':
468
+ case 'hour':
469
+ case 'hrs':
470
+ case 'hr':
471
+ case 'h':
472
+ return n * h;
473
+ case 'minutes':
474
+ case 'minute':
475
+ case 'mins':
476
+ case 'min':
477
+ case 'm':
478
+ return n * m;
479
+ case 'seconds':
480
+ case 'second':
481
+ case 'secs':
482
+ case 'sec':
483
+ case 's':
484
+ return n * s;
485
+ case 'milliseconds':
486
+ case 'millisecond':
487
+ case 'msecs':
488
+ case 'msec':
489
+ case 'ms':
490
+ return n;
491
+ default:
492
+ return undefined;
493
+ }
494
+ }
495
+
496
+ /**
497
+ * Short format for `ms`.
498
+ *
499
+ * @param {Number} ms
500
+ * @return {String}
501
+ * @api private
502
+ */
503
+
504
+ function fmtShort(ms) {
505
+ var msAbs = Math.abs(ms);
506
+ if (msAbs >= d) {
507
+ return Math.round(ms / d) + 'd';
508
+ }
509
+ if (msAbs >= h) {
510
+ return Math.round(ms / h) + 'h';
511
+ }
512
+ if (msAbs >= m) {
513
+ return Math.round(ms / m) + 'm';
514
+ }
515
+ if (msAbs >= s) {
516
+ return Math.round(ms / s) + 's';
517
+ }
518
+ return ms + 'ms';
519
+ }
520
+
521
+ /**
522
+ * Long format for `ms`.
523
+ *
524
+ * @param {Number} ms
525
+ * @return {String}
526
+ * @api private
527
+ */
528
+
529
+ function fmtLong(ms) {
530
+ var msAbs = Math.abs(ms);
531
+ if (msAbs >= d) {
532
+ return plural(ms, msAbs, d, 'day');
533
+ }
534
+ if (msAbs >= h) {
535
+ return plural(ms, msAbs, h, 'hour');
536
+ }
537
+ if (msAbs >= m) {
538
+ return plural(ms, msAbs, m, 'minute');
539
+ }
540
+ if (msAbs >= s) {
541
+ return plural(ms, msAbs, s, 'second');
542
+ }
543
+ return ms + ' ms';
544
+ }
545
+
546
+ /**
547
+ * Pluralization helper.
548
+ */
549
+
550
+ function plural(ms, msAbs, n, name) {
551
+ var isPlural = msAbs >= n * 1.5;
552
+ return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');
553
+ }
554
+ return ms;
555
+ }
556
+
557
+ var common$7;
558
+ var hasRequiredCommon;
559
+
560
+ function requireCommon () {
561
+ if (hasRequiredCommon) return common$7;
562
+ hasRequiredCommon = 1;
563
+ /**
564
+ * This is the common logic for both the Node.js and web browser
565
+ * implementations of `debug()`.
566
+ */
567
+
568
+ function setup(env) {
569
+ createDebug.debug = createDebug;
570
+ createDebug.default = createDebug;
571
+ createDebug.coerce = coerce;
572
+ createDebug.disable = disable;
573
+ createDebug.enable = enable;
574
+ createDebug.enabled = enabled;
575
+ createDebug.humanize = requireMs();
576
+ createDebug.destroy = destroy;
577
+
578
+ Object.keys(env).forEach(key => {
579
+ createDebug[key] = env[key];
580
+ });
581
+
582
+ /**
583
+ * The currently active debug mode names, and names to skip.
584
+ */
585
+
586
+ createDebug.names = [];
587
+ createDebug.skips = [];
588
+
589
+ /**
590
+ * Map of special "%n" handling functions, for the debug "format" argument.
591
+ *
592
+ * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
593
+ */
594
+ createDebug.formatters = {};
595
+
596
+ /**
597
+ * Selects a color for a debug namespace
598
+ * @param {String} namespace The namespace string for the debug instance to be colored
599
+ * @return {Number|String} An ANSI color code for the given namespace
600
+ * @api private
601
+ */
602
+ function selectColor(namespace) {
603
+ let hash = 0;
604
+
605
+ for (let i = 0; i < namespace.length; i++) {
606
+ hash = ((hash << 5) - hash) + namespace.charCodeAt(i);
607
+ hash |= 0; // Convert to 32bit integer
608
+ }
609
+
610
+ return createDebug.colors[Math.abs(hash) % createDebug.colors.length];
611
+ }
612
+ createDebug.selectColor = selectColor;
613
+
614
+ /**
615
+ * Create a debugger with the given `namespace`.
616
+ *
617
+ * @param {String} namespace
618
+ * @return {Function}
619
+ * @api public
620
+ */
621
+ function createDebug(namespace) {
622
+ let prevTime;
623
+ let enableOverride = null;
624
+ let namespacesCache;
625
+ let enabledCache;
626
+
627
+ function debug(...args) {
628
+ // Disabled?
629
+ if (!debug.enabled) {
630
+ return;
631
+ }
632
+
633
+ const self = debug;
634
+
635
+ // Set `diff` timestamp
636
+ const curr = Number(new Date());
637
+ const ms = curr - (prevTime || curr);
638
+ self.diff = ms;
639
+ self.prev = prevTime;
640
+ self.curr = curr;
641
+ prevTime = curr;
642
+
643
+ args[0] = createDebug.coerce(args[0]);
644
+
645
+ if (typeof args[0] !== 'string') {
646
+ // Anything else let's inspect with %O
647
+ args.unshift('%O');
648
+ }
649
+
650
+ // Apply any `formatters` transformations
651
+ let index = 0;
652
+ args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {
653
+ // If we encounter an escaped % then don't increase the array index
654
+ if (match === '%%') {
655
+ return '%';
656
+ }
657
+ index++;
658
+ const formatter = createDebug.formatters[format];
659
+ if (typeof formatter === 'function') {
660
+ const val = args[index];
661
+ match = formatter.call(self, val);
662
+
663
+ // Now we need to remove `args[index]` since it's inlined in the `format`
664
+ args.splice(index, 1);
665
+ index--;
666
+ }
667
+ return match;
668
+ });
669
+
670
+ // Apply env-specific formatting (colors, etc.)
671
+ createDebug.formatArgs.call(self, args);
672
+
673
+ const logFn = self.log || createDebug.log;
674
+ logFn.apply(self, args);
675
+ }
676
+
677
+ debug.namespace = namespace;
678
+ debug.useColors = createDebug.useColors();
679
+ debug.color = createDebug.selectColor(namespace);
680
+ debug.extend = extend;
681
+ debug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release.
682
+
683
+ Object.defineProperty(debug, 'enabled', {
684
+ enumerable: true,
685
+ configurable: false,
686
+ get: () => {
687
+ if (enableOverride !== null) {
688
+ return enableOverride;
689
+ }
690
+ if (namespacesCache !== createDebug.namespaces) {
691
+ namespacesCache = createDebug.namespaces;
692
+ enabledCache = createDebug.enabled(namespace);
693
+ }
694
+
695
+ return enabledCache;
696
+ },
697
+ set: v => {
698
+ enableOverride = v;
699
+ }
700
+ });
701
+
702
+ // Env-specific initialization logic for debug instances
703
+ if (typeof createDebug.init === 'function') {
704
+ createDebug.init(debug);
705
+ }
706
+
707
+ return debug;
708
+ }
709
+
710
+ function extend(namespace, delimiter) {
711
+ const newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);
712
+ newDebug.log = this.log;
713
+ return newDebug;
714
+ }
715
+
716
+ /**
717
+ * Enables a debug mode by namespaces. This can include modes
718
+ * separated by a colon and wildcards.
719
+ *
720
+ * @param {String} namespaces
721
+ * @api public
722
+ */
723
+ function enable(namespaces) {
724
+ createDebug.save(namespaces);
725
+ createDebug.namespaces = namespaces;
726
+
727
+ createDebug.names = [];
728
+ createDebug.skips = [];
729
+
730
+ let i;
731
+ const split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
732
+ const len = split.length;
733
+
734
+ for (i = 0; i < len; i++) {
735
+ if (!split[i]) {
736
+ // ignore empty strings
737
+ continue;
738
+ }
739
+
740
+ namespaces = split[i].replace(/\*/g, '.*?');
741
+
742
+ if (namespaces[0] === '-') {
743
+ createDebug.skips.push(new RegExp('^' + namespaces.slice(1) + '$'));
744
+ } else {
745
+ createDebug.names.push(new RegExp('^' + namespaces + '$'));
746
+ }
747
+ }
748
+ }
749
+
750
+ /**
751
+ * Disable debug output.
752
+ *
753
+ * @return {String} namespaces
754
+ * @api public
755
+ */
756
+ function disable() {
757
+ const namespaces = [
758
+ ...createDebug.names.map(toNamespace),
759
+ ...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace)
760
+ ].join(',');
761
+ createDebug.enable('');
762
+ return namespaces;
763
+ }
764
+
765
+ /**
766
+ * Returns true if the given mode name is enabled, false otherwise.
767
+ *
768
+ * @param {String} name
769
+ * @return {Boolean}
770
+ * @api public
771
+ */
772
+ function enabled(name) {
773
+ if (name[name.length - 1] === '*') {
774
+ return true;
775
+ }
776
+
777
+ let i;
778
+ let len;
779
+
780
+ for (i = 0, len = createDebug.skips.length; i < len; i++) {
781
+ if (createDebug.skips[i].test(name)) {
782
+ return false;
783
+ }
784
+ }
785
+
786
+ for (i = 0, len = createDebug.names.length; i < len; i++) {
787
+ if (createDebug.names[i].test(name)) {
788
+ return true;
789
+ }
790
+ }
791
+
792
+ return false;
793
+ }
794
+
795
+ /**
796
+ * Convert regexp to namespace
797
+ *
798
+ * @param {RegExp} regxep
799
+ * @return {String} namespace
800
+ * @api private
801
+ */
802
+ function toNamespace(regexp) {
803
+ return regexp.toString()
804
+ .substring(2, regexp.toString().length - 2)
805
+ .replace(/\.\*\?$/, '*');
806
+ }
807
+
808
+ /**
809
+ * Coerce `val`.
810
+ *
811
+ * @param {Mixed} val
812
+ * @return {Mixed}
813
+ * @api private
814
+ */
815
+ function coerce(val) {
816
+ if (val instanceof Error) {
817
+ return val.stack || val.message;
818
+ }
819
+ return val;
820
+ }
821
+
822
+ /**
823
+ * XXX DO NOT USE. This is a temporary stub function.
824
+ * XXX It WILL be removed in the next major release.
825
+ */
826
+ function destroy() {
827
+ console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');
828
+ }
829
+
830
+ createDebug.enable(createDebug.load());
831
+
832
+ return createDebug;
833
+ }
834
+
835
+ common$7 = setup;
836
+ return common$7;
837
+ }
838
+
839
+ /* eslint-env browser */
840
+
841
+ var hasRequiredBrowser;
842
+
843
+ function requireBrowser () {
844
+ if (hasRequiredBrowser) return browser$1.exports;
845
+ hasRequiredBrowser = 1;
846
+ (function (module, exports) {
847
+ /**
848
+ * This is the web browser implementation of `debug()`.
849
+ */
850
+
851
+ exports.formatArgs = formatArgs;
852
+ exports.save = save;
853
+ exports.load = load;
854
+ exports.useColors = useColors;
855
+ exports.storage = localstorage();
856
+ exports.destroy = (() => {
857
+ let warned = false;
858
+
859
+ return () => {
860
+ if (!warned) {
861
+ warned = true;
862
+ console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');
863
+ }
864
+ };
865
+ })();
866
+
867
+ /**
868
+ * Colors.
869
+ */
870
+
871
+ exports.colors = [
872
+ '#0000CC',
873
+ '#0000FF',
874
+ '#0033CC',
875
+ '#0033FF',
876
+ '#0066CC',
877
+ '#0066FF',
878
+ '#0099CC',
879
+ '#0099FF',
880
+ '#00CC00',
881
+ '#00CC33',
882
+ '#00CC66',
883
+ '#00CC99',
884
+ '#00CCCC',
885
+ '#00CCFF',
886
+ '#3300CC',
887
+ '#3300FF',
888
+ '#3333CC',
889
+ '#3333FF',
890
+ '#3366CC',
891
+ '#3366FF',
892
+ '#3399CC',
893
+ '#3399FF',
894
+ '#33CC00',
895
+ '#33CC33',
896
+ '#33CC66',
897
+ '#33CC99',
898
+ '#33CCCC',
899
+ '#33CCFF',
900
+ '#6600CC',
901
+ '#6600FF',
902
+ '#6633CC',
903
+ '#6633FF',
904
+ '#66CC00',
905
+ '#66CC33',
906
+ '#9900CC',
907
+ '#9900FF',
908
+ '#9933CC',
909
+ '#9933FF',
910
+ '#99CC00',
911
+ '#99CC33',
912
+ '#CC0000',
913
+ '#CC0033',
914
+ '#CC0066',
915
+ '#CC0099',
916
+ '#CC00CC',
917
+ '#CC00FF',
918
+ '#CC3300',
919
+ '#CC3333',
920
+ '#CC3366',
921
+ '#CC3399',
922
+ '#CC33CC',
923
+ '#CC33FF',
924
+ '#CC6600',
925
+ '#CC6633',
926
+ '#CC9900',
927
+ '#CC9933',
928
+ '#CCCC00',
929
+ '#CCCC33',
930
+ '#FF0000',
931
+ '#FF0033',
932
+ '#FF0066',
933
+ '#FF0099',
934
+ '#FF00CC',
935
+ '#FF00FF',
936
+ '#FF3300',
937
+ '#FF3333',
938
+ '#FF3366',
939
+ '#FF3399',
940
+ '#FF33CC',
941
+ '#FF33FF',
942
+ '#FF6600',
943
+ '#FF6633',
944
+ '#FF9900',
945
+ '#FF9933',
946
+ '#FFCC00',
947
+ '#FFCC33'
948
+ ];
949
+
950
+ /**
951
+ * Currently only WebKit-based Web Inspectors, Firefox >= v31,
952
+ * and the Firebug extension (any Firefox version) are known
953
+ * to support "%c" CSS customizations.
954
+ *
955
+ * TODO: add a `localStorage` variable to explicitly enable/disable colors
956
+ */
957
+
958
+ // eslint-disable-next-line complexity
959
+ function useColors() {
960
+ // NB: In an Electron preload script, document will be defined but not fully
961
+ // initialized. Since we know we're in Chrome, we'll just detect this case
962
+ // explicitly
963
+ if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {
964
+ return true;
965
+ }
966
+
967
+ // Internet Explorer and Edge do not support colors.
968
+ if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
969
+ return false;
970
+ }
971
+
972
+ // Is webkit? http://stackoverflow.com/a/16459606/376773
973
+ // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
974
+ return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||
975
+ // Is firebug? http://stackoverflow.com/a/398120/376773
976
+ (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||
977
+ // Is firefox >= v31?
978
+ // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
979
+ (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||
980
+ // Double check webkit in userAgent just in case we are in a worker
981
+ (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/));
982
+ }
983
+
984
+ /**
985
+ * Colorize log arguments if enabled.
986
+ *
987
+ * @api public
988
+ */
989
+
990
+ function formatArgs(args) {
991
+ args[0] = (this.useColors ? '%c' : '') +
992
+ this.namespace +
993
+ (this.useColors ? ' %c' : ' ') +
994
+ args[0] +
995
+ (this.useColors ? '%c ' : ' ') +
996
+ '+' + module.exports.humanize(this.diff);
997
+
998
+ if (!this.useColors) {
999
+ return;
1000
+ }
1001
+
1002
+ const c = 'color: ' + this.color;
1003
+ args.splice(1, 0, c, 'color: inherit');
1004
+
1005
+ // The final "%c" is somewhat tricky, because there could be other
1006
+ // arguments passed either before or after the %c, so we need to
1007
+ // figure out the correct index to insert the CSS into
1008
+ let index = 0;
1009
+ let lastC = 0;
1010
+ args[0].replace(/%[a-zA-Z%]/g, match => {
1011
+ if (match === '%%') {
1012
+ return;
1013
+ }
1014
+ index++;
1015
+ if (match === '%c') {
1016
+ // We only are interested in the *last* %c
1017
+ // (the user may have provided their own)
1018
+ lastC = index;
1019
+ }
1020
+ });
1021
+
1022
+ args.splice(lastC, 0, c);
1023
+ }
1024
+
1025
+ /**
1026
+ * Invokes `console.debug()` when available.
1027
+ * No-op when `console.debug` is not a "function".
1028
+ * If `console.debug` is not available, falls back
1029
+ * to `console.log`.
1030
+ *
1031
+ * @api public
1032
+ */
1033
+ exports.log = console.debug || console.log || (() => {});
1034
+
1035
+ /**
1036
+ * Save `namespaces`.
1037
+ *
1038
+ * @param {String} namespaces
1039
+ * @api private
1040
+ */
1041
+ function save(namespaces) {
1042
+ try {
1043
+ if (namespaces) {
1044
+ exports.storage.setItem('debug', namespaces);
1045
+ } else {
1046
+ exports.storage.removeItem('debug');
1047
+ }
1048
+ } catch (error) {
1049
+ // Swallow
1050
+ // XXX (@Qix-) should we be logging these?
1051
+ }
1052
+ }
1053
+
1054
+ /**
1055
+ * Load `namespaces`.
1056
+ *
1057
+ * @return {String} returns the previously persisted debug modes
1058
+ * @api private
1059
+ */
1060
+ function load() {
1061
+ let r;
1062
+ try {
1063
+ r = exports.storage.getItem('debug');
1064
+ } catch (error) {
1065
+ // Swallow
1066
+ // XXX (@Qix-) should we be logging these?
1067
+ }
1068
+
1069
+ // If debug isn't set in LS, and we're in Electron, try to load $DEBUG
1070
+ if (!r && typeof process !== 'undefined' && 'env' in process) {
1071
+ r = process.env.DEBUG;
1072
+ }
1073
+
1074
+ return r;
1075
+ }
1076
+
1077
+ /**
1078
+ * Localstorage attempts to return the localstorage.
1079
+ *
1080
+ * This is necessary because safari throws
1081
+ * when a user disables cookies/localstorage
1082
+ * and you attempt to access it.
1083
+ *
1084
+ * @return {LocalStorage}
1085
+ * @api private
1086
+ */
1087
+
1088
+ function localstorage() {
1089
+ try {
1090
+ // TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context
1091
+ // The Browser also has localStorage in the global context.
1092
+ return localStorage;
1093
+ } catch (error) {
1094
+ // Swallow
1095
+ // XXX (@Qix-) should we be logging these?
1096
+ }
1097
+ }
1098
+
1099
+ module.exports = requireCommon()(exports);
1100
+
1101
+ const {formatters} = module.exports;
1102
+
1103
+ /**
1104
+ * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
1105
+ */
1106
+
1107
+ formatters.j = function (v) {
1108
+ try {
1109
+ return JSON.stringify(v);
1110
+ } catch (error) {
1111
+ return '[UnexpectedJSONParseError]: ' + error.message;
1112
+ }
1113
+ };
1114
+ } (browser$1, browser$1.exports));
1115
+ return browser$1.exports;
1116
+ }
1117
+
1118
+ var node = {exports: {}};
1119
+
1120
+ var hasFlag;
1121
+ var hasRequiredHasFlag;
1122
+
1123
+ function requireHasFlag () {
1124
+ if (hasRequiredHasFlag) return hasFlag;
1125
+ hasRequiredHasFlag = 1;
1126
+
1127
+ hasFlag = (flag, argv = process.argv) => {
1128
+ const prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--');
1129
+ const position = argv.indexOf(prefix + flag);
1130
+ const terminatorPosition = argv.indexOf('--');
1131
+ return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
1132
+ };
1133
+ return hasFlag;
1134
+ }
1135
+
1136
+ var supportsColor_1;
1137
+ var hasRequiredSupportsColor;
1138
+
1139
+ function requireSupportsColor () {
1140
+ if (hasRequiredSupportsColor) return supportsColor_1;
1141
+ hasRequiredSupportsColor = 1;
1142
+ const os = require$$0__default["default"];
1143
+ const tty = require$$1__default["default"];
1144
+ const hasFlag = requireHasFlag();
1145
+
1146
+ const {env} = process;
1147
+
1148
+ let forceColor;
1149
+ if (hasFlag('no-color') ||
1150
+ hasFlag('no-colors') ||
1151
+ hasFlag('color=false') ||
1152
+ hasFlag('color=never')) {
1153
+ forceColor = 0;
1154
+ } else if (hasFlag('color') ||
1155
+ hasFlag('colors') ||
1156
+ hasFlag('color=true') ||
1157
+ hasFlag('color=always')) {
1158
+ forceColor = 1;
1159
+ }
1160
+
1161
+ if ('FORCE_COLOR' in env) {
1162
+ if (env.FORCE_COLOR === 'true') {
1163
+ forceColor = 1;
1164
+ } else if (env.FORCE_COLOR === 'false') {
1165
+ forceColor = 0;
1166
+ } else {
1167
+ forceColor = env.FORCE_COLOR.length === 0 ? 1 : Math.min(parseInt(env.FORCE_COLOR, 10), 3);
1168
+ }
1169
+ }
1170
+
1171
+ function translateLevel(level) {
1172
+ if (level === 0) {
1173
+ return false;
1174
+ }
1175
+
1176
+ return {
1177
+ level,
1178
+ hasBasic: true,
1179
+ has256: level >= 2,
1180
+ has16m: level >= 3
1181
+ };
1182
+ }
1183
+
1184
+ function supportsColor(haveStream, streamIsTTY) {
1185
+ if (forceColor === 0) {
1186
+ return 0;
1187
+ }
1188
+
1189
+ if (hasFlag('color=16m') ||
1190
+ hasFlag('color=full') ||
1191
+ hasFlag('color=truecolor')) {
1192
+ return 3;
1193
+ }
1194
+
1195
+ if (hasFlag('color=256')) {
1196
+ return 2;
1197
+ }
1198
+
1199
+ if (haveStream && !streamIsTTY && forceColor === undefined) {
1200
+ return 0;
1201
+ }
1202
+
1203
+ const min = forceColor || 0;
1204
+
1205
+ if (env.TERM === 'dumb') {
1206
+ return min;
1207
+ }
1208
+
1209
+ if (process.platform === 'win32') {
1210
+ // Windows 10 build 10586 is the first Windows release that supports 256 colors.
1211
+ // Windows 10 build 14931 is the first release that supports 16m/TrueColor.
1212
+ const osRelease = os.release().split('.');
1213
+ if (
1214
+ Number(osRelease[0]) >= 10 &&
1215
+ Number(osRelease[2]) >= 10586
1216
+ ) {
1217
+ return Number(osRelease[2]) >= 14931 ? 3 : 2;
1218
+ }
1219
+
1220
+ return 1;
1221
+ }
1222
+
1223
+ if ('CI' in env) {
1224
+ if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI', 'GITHUB_ACTIONS', 'BUILDKITE'].some(sign => sign in env) || env.CI_NAME === 'codeship') {
1225
+ return 1;
1226
+ }
1227
+
1228
+ return min;
1229
+ }
1230
+
1231
+ if ('TEAMCITY_VERSION' in env) {
1232
+ return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
1233
+ }
1234
+
1235
+ if (env.COLORTERM === 'truecolor') {
1236
+ return 3;
1237
+ }
1238
+
1239
+ if ('TERM_PROGRAM' in env) {
1240
+ const version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10);
1241
+
1242
+ switch (env.TERM_PROGRAM) {
1243
+ case 'iTerm.app':
1244
+ return version >= 3 ? 3 : 2;
1245
+ case 'Apple_Terminal':
1246
+ return 2;
1247
+ // No default
1248
+ }
1249
+ }
1250
+
1251
+ if (/-256(color)?$/i.test(env.TERM)) {
1252
+ return 2;
1253
+ }
1254
+
1255
+ if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
1256
+ return 1;
1257
+ }
1258
+
1259
+ if ('COLORTERM' in env) {
1260
+ return 1;
1261
+ }
1262
+
1263
+ return min;
1264
+ }
1265
+
1266
+ function getSupportLevel(stream) {
1267
+ const level = supportsColor(stream, stream && stream.isTTY);
1268
+ return translateLevel(level);
1269
+ }
1270
+
1271
+ supportsColor_1 = {
1272
+ supportsColor: getSupportLevel,
1273
+ stdout: translateLevel(supportsColor(true, tty.isatty(1))),
1274
+ stderr: translateLevel(supportsColor(true, tty.isatty(2)))
1275
+ };
1276
+ return supportsColor_1;
1277
+ }
1278
+
1279
+ /**
1280
+ * Module dependencies.
1281
+ */
1282
+
1283
+ var hasRequiredNode;
1284
+
1285
+ function requireNode () {
1286
+ if (hasRequiredNode) return node.exports;
1287
+ hasRequiredNode = 1;
1288
+ (function (module, exports) {
1289
+ const tty = require$$1__default["default"];
1290
+ const util = require$$0__default$1["default"];
1291
+
1292
+ /**
1293
+ * This is the Node.js implementation of `debug()`.
1294
+ */
1295
+
1296
+ exports.init = init;
1297
+ exports.log = log;
1298
+ exports.formatArgs = formatArgs;
1299
+ exports.save = save;
1300
+ exports.load = load;
1301
+ exports.useColors = useColors;
1302
+ exports.destroy = util.deprecate(
1303
+ () => {},
1304
+ 'Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.'
1305
+ );
1306
+
1307
+ /**
1308
+ * Colors.
1309
+ */
1310
+
1311
+ exports.colors = [6, 2, 3, 4, 5, 1];
1312
+
1313
+ try {
1314
+ // Optional dependency (as in, doesn't need to be installed, NOT like optionalDependencies in package.json)
1315
+ // eslint-disable-next-line import/no-extraneous-dependencies
1316
+ const supportsColor = requireSupportsColor();
1317
+
1318
+ if (supportsColor && (supportsColor.stderr || supportsColor).level >= 2) {
1319
+ exports.colors = [
1320
+ 20,
1321
+ 21,
1322
+ 26,
1323
+ 27,
1324
+ 32,
1325
+ 33,
1326
+ 38,
1327
+ 39,
1328
+ 40,
1329
+ 41,
1330
+ 42,
1331
+ 43,
1332
+ 44,
1333
+ 45,
1334
+ 56,
1335
+ 57,
1336
+ 62,
1337
+ 63,
1338
+ 68,
1339
+ 69,
1340
+ 74,
1341
+ 75,
1342
+ 76,
1343
+ 77,
1344
+ 78,
1345
+ 79,
1346
+ 80,
1347
+ 81,
1348
+ 92,
1349
+ 93,
1350
+ 98,
1351
+ 99,
1352
+ 112,
1353
+ 113,
1354
+ 128,
1355
+ 129,
1356
+ 134,
1357
+ 135,
1358
+ 148,
1359
+ 149,
1360
+ 160,
1361
+ 161,
1362
+ 162,
1363
+ 163,
1364
+ 164,
1365
+ 165,
1366
+ 166,
1367
+ 167,
1368
+ 168,
1369
+ 169,
1370
+ 170,
1371
+ 171,
1372
+ 172,
1373
+ 173,
1374
+ 178,
1375
+ 179,
1376
+ 184,
1377
+ 185,
1378
+ 196,
1379
+ 197,
1380
+ 198,
1381
+ 199,
1382
+ 200,
1383
+ 201,
1384
+ 202,
1385
+ 203,
1386
+ 204,
1387
+ 205,
1388
+ 206,
1389
+ 207,
1390
+ 208,
1391
+ 209,
1392
+ 214,
1393
+ 215,
1394
+ 220,
1395
+ 221
1396
+ ];
1397
+ }
1398
+ } catch (error) {
1399
+ // Swallow - we only care if `supports-color` is available; it doesn't have to be.
1400
+ }
1401
+
1402
+ /**
1403
+ * Build up the default `inspectOpts` object from the environment variables.
1404
+ *
1405
+ * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js
1406
+ */
1407
+
1408
+ exports.inspectOpts = Object.keys(process.env).filter(key => {
1409
+ return /^debug_/i.test(key);
1410
+ }).reduce((obj, key) => {
1411
+ // Camel-case
1412
+ const prop = key
1413
+ .substring(6)
1414
+ .toLowerCase()
1415
+ .replace(/_([a-z])/g, (_, k) => {
1416
+ return k.toUpperCase();
1417
+ });
1418
+
1419
+ // Coerce string value into JS value
1420
+ let val = process.env[key];
1421
+ if (/^(yes|on|true|enabled)$/i.test(val)) {
1422
+ val = true;
1423
+ } else if (/^(no|off|false|disabled)$/i.test(val)) {
1424
+ val = false;
1425
+ } else if (val === 'null') {
1426
+ val = null;
1427
+ } else {
1428
+ val = Number(val);
1429
+ }
1430
+
1431
+ obj[prop] = val;
1432
+ return obj;
1433
+ }, {});
1434
+
1435
+ /**
1436
+ * Is stdout a TTY? Colored output is enabled when `true`.
1437
+ */
1438
+
1439
+ function useColors() {
1440
+ return 'colors' in exports.inspectOpts ?
1441
+ Boolean(exports.inspectOpts.colors) :
1442
+ tty.isatty(process.stderr.fd);
1443
+ }
1444
+
1445
+ /**
1446
+ * Adds ANSI color escape codes if enabled.
1447
+ *
1448
+ * @api public
1449
+ */
1450
+
1451
+ function formatArgs(args) {
1452
+ const {namespace: name, useColors} = this;
1453
+
1454
+ if (useColors) {
1455
+ const c = this.color;
1456
+ const colorCode = '\u001B[3' + (c < 8 ? c : '8;5;' + c);
1457
+ const prefix = ` ${colorCode};1m${name} \u001B[0m`;
1458
+
1459
+ args[0] = prefix + args[0].split('\n').join('\n' + prefix);
1460
+ args.push(colorCode + 'm+' + module.exports.humanize(this.diff) + '\u001B[0m');
1461
+ } else {
1462
+ args[0] = getDate() + name + ' ' + args[0];
1463
+ }
1464
+ }
1465
+
1466
+ function getDate() {
1467
+ if (exports.inspectOpts.hideDate) {
1468
+ return '';
1469
+ }
1470
+ return new Date().toISOString() + ' ';
1471
+ }
1472
+
1473
+ /**
1474
+ * Invokes `util.format()` with the specified arguments and writes to stderr.
1475
+ */
1476
+
1477
+ function log(...args) {
1478
+ return process.stderr.write(util.format(...args) + '\n');
1479
+ }
1480
+
1481
+ /**
1482
+ * Save `namespaces`.
1483
+ *
1484
+ * @param {String} namespaces
1485
+ * @api private
1486
+ */
1487
+ function save(namespaces) {
1488
+ if (namespaces) {
1489
+ process.env.DEBUG = namespaces;
1490
+ } else {
1491
+ // If you set a process.env field to null or undefined, it gets cast to the
1492
+ // string 'null' or 'undefined'. Just delete instead.
1493
+ delete process.env.DEBUG;
1494
+ }
1495
+ }
1496
+
1497
+ /**
1498
+ * Load `namespaces`.
1499
+ *
1500
+ * @return {String} returns the previously persisted debug modes
1501
+ * @api private
1502
+ */
1503
+
1504
+ function load() {
1505
+ return process.env.DEBUG;
1506
+ }
1507
+
1508
+ /**
1509
+ * Init logic for `debug` instances.
1510
+ *
1511
+ * Create a new `inspectOpts` object in case `useColors` is set
1512
+ * differently for a particular `debug` instance.
1513
+ */
1514
+
1515
+ function init(debug) {
1516
+ debug.inspectOpts = {};
1517
+
1518
+ const keys = Object.keys(exports.inspectOpts);
1519
+ for (let i = 0; i < keys.length; i++) {
1520
+ debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]];
1521
+ }
1522
+ }
1523
+
1524
+ module.exports = requireCommon()(exports);
1525
+
1526
+ const {formatters} = module.exports;
1527
+
1528
+ /**
1529
+ * Map %o to `util.inspect()`, all on a single line.
1530
+ */
1531
+
1532
+ formatters.o = function (v) {
1533
+ this.inspectOpts.colors = this.useColors;
1534
+ return util.inspect(v, this.inspectOpts)
1535
+ .split('\n')
1536
+ .map(str => str.trim())
1537
+ .join(' ');
1538
+ };
1539
+
1540
+ /**
1541
+ * Map %O to `util.inspect()`, allowing multiple lines if needed.
1542
+ */
1543
+
1544
+ formatters.O = function (v) {
1545
+ this.inspectOpts.colors = this.useColors;
1546
+ return util.inspect(v, this.inspectOpts);
1547
+ };
1548
+ } (node, node.exports));
1549
+ return node.exports;
1550
+ }
1551
+
1552
+ /**
1553
+ * Detect Electron renderer / nwjs process, which is node, but we should
1554
+ * treat as a browser.
1555
+ */
1556
+
1557
+ (function (module) {
1558
+ if (typeof process === 'undefined' || process.type === 'renderer' || process.browser === true || process.__nwjs) {
1559
+ module.exports = requireBrowser();
1560
+ } else {
1561
+ module.exports = requireNode();
1562
+ }
1563
+ } (src));
1564
+
1565
+ var debug$3 = /*@__PURE__*/getDefaultExportFromCjs(src.exports);
1566
+
1567
+ /*!
1568
+ * playwright-extra v4.3.5 by berstend
1569
+ * https://github.com/berstend/puppeteer-extra/tree/master/packages/playwright-extra#readme
1570
+ * @license MIT
1571
+ */
1572
+
1573
+ /** Node.js module loader helper */
1574
+ class Loader {
1575
+ constructor(moduleName, packageNames) {
1576
+ this.moduleName = moduleName;
1577
+ this.packageNames = packageNames;
1578
+ }
1579
+ /**
1580
+ * Lazy load a top level export from another module by wrapping it in a JS proxy.
1581
+ *
1582
+ * This allows us to re-export e.g. `devices` from `playwright` while redirecting direct calls
1583
+ * to it to the module version the user has installed, rather than shipping with a hardcoded version.
1584
+ *
1585
+ * If we don't do this and the user doesn't have the target module installed we'd throw immediately when our code is imported.
1586
+ *
1587
+ * We use a "super" Proxy defining all traps, so calls like `Object.keys(playwright.devices).length` will return the correct value.
1588
+ */
1589
+ lazyloadExportOrDie(exportName) {
1590
+ const that = this;
1591
+ const trapHandler = Object.fromEntries(Object.getOwnPropertyNames(Reflect).map((name) => [
1592
+ name,
1593
+ function (target, ...args) {
1594
+ const moduleExport = that.loadModuleOrDie()[exportName];
1595
+ const customTarget = moduleExport;
1596
+ const result = Reflect[name](customTarget || target, ...args);
1597
+ return result;
1598
+ }
1599
+ ]));
1600
+ return new Proxy({}, trapHandler);
1601
+ }
1602
+ /** Load the module if possible */
1603
+ loadModule() {
1604
+ return requirePackages(this.packageNames);
1605
+ }
1606
+ /** Load the module if possible or throw */
1607
+ loadModuleOrDie() {
1608
+ const module = requirePackages(this.packageNames);
1609
+ if (module) {
1610
+ return module;
1611
+ }
1612
+ throw this.requireError;
1613
+ }
1614
+ get requireError() {
1615
+ const moduleNamePretty = this.moduleName.charAt(0).toUpperCase() + this.moduleName.slice(1);
1616
+ return new Error(`
1617
+ ${moduleNamePretty} is missing. :-)
1618
+
1619
+ I've tried loading ${this.packageNames
1620
+ .map(p => `"${p}"`)
1621
+ .join(', ')} - no luck.
1622
+
1623
+ Make sure you install one of those packages or use the named 'addExtra' export,
1624
+ to patch a specific (and maybe non-standard) implementation of ${moduleNamePretty}.
1625
+
1626
+ To get the latest stable version of ${moduleNamePretty} run:
1627
+ 'yarn add ${this.moduleName}' or 'npm i ${this.moduleName}'
1628
+ `);
1629
+ }
1630
+ }
1631
+ function requirePackages(packageNames) {
1632
+ for (const name of packageNames) {
1633
+ try {
1634
+ return require(name);
1635
+ }
1636
+ catch (_) {
1637
+ continue; // noop
1638
+ }
1639
+ }
1640
+ return;
1641
+ }
1642
+ /** Playwright specific module loader */
1643
+ const playwrightLoader = new Loader('playwright', [
1644
+ 'playwright-core',
1645
+ 'playwright'
1646
+ ]);
1647
+
1648
+ const debug = debug$3('playwright-extra:puppeteer-compat');
1649
+ const isPlaywrightPage = (obj) => {
1650
+ return 'unroute' in obj;
1651
+ };
1652
+ const isPlaywrightFrame = (obj) => {
1653
+ return ['parentFrame', 'frameLocator'].every(x => x in obj);
1654
+ };
1655
+ const isPlaywrightBrowser = (obj) => {
1656
+ return 'newContext' in obj;
1657
+ };
1658
+ const isPuppeteerCompat = (obj) => {
1659
+ return !!obj && typeof obj === 'object' && !!obj.isCompatShim;
1660
+ };
1661
+ const cache = {
1662
+ objectToShim: new Map(),
1663
+ cdpSession: {
1664
+ page: new Map(),
1665
+ browser: new Map()
1666
+ }
1667
+ };
1668
+ /** Augment a Playwright object with compatibility with certain Puppeteer methods */
1669
+ function addPuppeteerCompat(object) {
1670
+ if (!object || typeof object !== 'object') {
1671
+ return object;
1672
+ }
1673
+ if (cache.objectToShim.has(object)) {
1674
+ return cache.objectToShim.get(object);
1675
+ }
1676
+ if (isPuppeteerCompat(object)) {
1677
+ return object;
1678
+ }
1679
+ debug('addPuppeteerCompat', cache.objectToShim.size);
1680
+ if (isPlaywrightPage(object) || isPlaywrightFrame(object)) {
1681
+ const shim = createPageShim(object);
1682
+ cache.objectToShim.set(object, shim);
1683
+ return shim;
1684
+ }
1685
+ if (isPlaywrightBrowser(object)) {
1686
+ const shim = createBrowserShim(object);
1687
+ cache.objectToShim.set(object, shim);
1688
+ return shim;
1689
+ }
1690
+ debug('Received unknown object:', Reflect.ownKeys(object));
1691
+ return object;
1692
+ }
1693
+ // Only chromium browsers support CDP
1694
+ const dummyCDPClient = {
1695
+ send: async (...args) => {
1696
+ debug('dummy CDP client called', 'send', args);
1697
+ },
1698
+ on: (...args) => {
1699
+ debug('dummy CDP client called', 'on', args);
1700
+ }
1701
+ };
1702
+ async function getPageCDPSession(page) {
1703
+ let session = cache.cdpSession.page.get(page);
1704
+ if (session) {
1705
+ debug('getPageCDPSession: use existing');
1706
+ return session;
1707
+ }
1708
+ debug('getPageCDPSession: use new');
1709
+ const context = isPlaywrightFrame(page)
1710
+ ? page.page().context()
1711
+ : page.context();
1712
+ try {
1713
+ session = await context.newCDPSession(page);
1714
+ cache.cdpSession.page.set(page, session);
1715
+ return session;
1716
+ }
1717
+ catch (err) {
1718
+ debug('getPageCDPSession: error while creating session:', err.message);
1719
+ debug('getPageCDPSession: Unable create CDP session (most likely a different browser than chromium) - returning a dummy');
1720
+ }
1721
+ return dummyCDPClient;
1722
+ }
1723
+ async function getBrowserCDPSession(browser) {
1724
+ let session = cache.cdpSession.browser.get(browser);
1725
+ if (session) {
1726
+ debug('getBrowserCDPSession: use existing');
1727
+ return session;
1728
+ }
1729
+ debug('getBrowserCDPSession: use new');
1730
+ try {
1731
+ session = await browser.newBrowserCDPSession();
1732
+ cache.cdpSession.browser.set(browser, session);
1733
+ return session;
1734
+ }
1735
+ catch (err) {
1736
+ debug('getBrowserCDPSession: error while creating session:', err.message);
1737
+ debug('getBrowserCDPSession: Unable create CDP session (most likely a different browser than chromium) - returning a dummy');
1738
+ }
1739
+ return dummyCDPClient;
1740
+ }
1741
+ function createPageShim(page) {
1742
+ const objId = Math.random().toString(36).substring(2, 7);
1743
+ const shim = new Proxy(page, {
1744
+ get(target, prop) {
1745
+ if (prop === 'isCompatShim' || prop === 'isPlaywright') {
1746
+ return true;
1747
+ }
1748
+ debug('page - get', objId, prop);
1749
+ if (prop === '_client') {
1750
+ return () => ({
1751
+ send: async (method, params) => {
1752
+ const session = await getPageCDPSession(page);
1753
+ return await session.send(method, params);
1754
+ },
1755
+ on: (event, listener) => {
1756
+ getPageCDPSession(page).then(session => {
1757
+ session.on(event, listener);
1758
+ });
1759
+ }
1760
+ });
1761
+ }
1762
+ if (prop === 'setBypassCSP') {
1763
+ return async (enabled) => {
1764
+ const session = await getPageCDPSession(page);
1765
+ return await session.send('Page.setBypassCSP', {
1766
+ enabled
1767
+ });
1768
+ };
1769
+ }
1770
+ if (prop === 'setUserAgent') {
1771
+ return async (userAgent, userAgentMetadata) => {
1772
+ const session = await getPageCDPSession(page);
1773
+ return await session.send('Emulation.setUserAgentOverride', {
1774
+ userAgent,
1775
+ userAgentMetadata
1776
+ });
1777
+ };
1778
+ }
1779
+ if (prop === 'browser') {
1780
+ if (isPlaywrightPage(page)) {
1781
+ return () => {
1782
+ let browser = page.context().browser();
1783
+ if (!browser) {
1784
+ debug('page.browser() - not available, most likely due to launchPersistentContext');
1785
+ // Use a page shim as quick drop-in (so browser.userAgent() still works)
1786
+ browser = page;
1787
+ }
1788
+ return addPuppeteerCompat(browser);
1789
+ };
1790
+ }
1791
+ }
1792
+ if (prop === 'evaluateOnNewDocument') {
1793
+ if (isPlaywrightPage(page)) {
1794
+ return async function (pageFunction, ...args) {
1795
+ return await page.addInitScript(pageFunction, args[0]);
1796
+ };
1797
+ }
1798
+ }
1799
+ // Only relevant when page is being used a pseudo stand-in for the browser object (launchPersistentContext)
1800
+ if (prop === 'userAgent') {
1801
+ return async (enabled) => {
1802
+ const session = await getPageCDPSession(page);
1803
+ const data = await session.send('Browser.getVersion');
1804
+ return data.userAgent;
1805
+ };
1806
+ }
1807
+ return Reflect.get(target, prop);
1808
+ }
1809
+ });
1810
+ return shim;
1811
+ }
1812
+ function createBrowserShim(browser) {
1813
+ const objId = Math.random().toString(36).substring(2, 7);
1814
+ const shim = new Proxy(browser, {
1815
+ get(target, prop) {
1816
+ if (prop === 'isCompatShim' || prop === 'isPlaywright') {
1817
+ return true;
1818
+ }
1819
+ debug('browser - get', objId, prop);
1820
+ if (prop === 'pages') {
1821
+ return () => browser
1822
+ .contexts()
1823
+ .flatMap(c => c.pages().map(page => addPuppeteerCompat(page)));
1824
+ }
1825
+ if (prop === 'userAgent') {
1826
+ return async () => {
1827
+ const session = await getBrowserCDPSession(browser);
1828
+ const data = await session.send('Browser.getVersion');
1829
+ return data.userAgent;
1830
+ };
1831
+ }
1832
+ return Reflect.get(target, prop);
1833
+ }
1834
+ });
1835
+ return shim;
1836
+ }
1837
+
1838
+ const debug$1 = debug$3('playwright-extra:plugins');
1839
+ class PluginList {
1840
+ constructor() {
1841
+ this._plugins = [];
1842
+ this._dependencyDefaults = new Map();
1843
+ this._dependencyResolution = new Map();
1844
+ }
1845
+ /**
1846
+ * Get a list of all registered plugins.
1847
+ */
1848
+ get list() {
1849
+ return this._plugins;
1850
+ }
1851
+ /**
1852
+ * Get the names of all registered plugins.
1853
+ */
1854
+ get names() {
1855
+ return this._plugins.map(p => p.name);
1856
+ }
1857
+ /**
1858
+ * Add a new plugin to the list (after checking if it's well-formed).
1859
+ *
1860
+ * @param plugin
1861
+ * @internal
1862
+ */
1863
+ add(plugin) {
1864
+ var _a;
1865
+ if (!this.isValidPluginInstance(plugin)) {
1866
+ return false;
1867
+ }
1868
+ if (!!plugin.onPluginRegistered) {
1869
+ plugin.onPluginRegistered({ framework: 'playwright' });
1870
+ }
1871
+ // PuppeteerExtraPlugin: Populate `_childClassMembers` list containing methods defined by the plugin
1872
+ if (!!plugin._registerChildClassMembers) {
1873
+ plugin._registerChildClassMembers(Object.getPrototypeOf(plugin));
1874
+ }
1875
+ if ((_a = plugin.requirements) === null || _a === void 0 ? void 0 : _a.has('dataFromPlugins')) {
1876
+ plugin.getDataFromPlugins = this.getData.bind(this);
1877
+ }
1878
+ this._plugins.push(plugin);
1879
+ return true;
1880
+ }
1881
+ /** Check if the shape of a plugin is correct or warn */
1882
+ isValidPluginInstance(plugin) {
1883
+ if (!plugin ||
1884
+ typeof plugin !== 'object' ||
1885
+ !plugin._isPuppeteerExtraPlugin) {
1886
+ console.error(`Warning: Plugin is not derived from PuppeteerExtraPlugin, ignoring.`, plugin);
1887
+ return false;
1888
+ }
1889
+ if (!plugin.name) {
1890
+ console.error(`Warning: Plugin with no name registering, ignoring.`, plugin);
1891
+ return false;
1892
+ }
1893
+ return true;
1894
+ }
1895
+ /** Error callback in case calling a plugin method throws an error. Can be overwritten. */
1896
+ onPluginError(plugin, method, err) {
1897
+ console.warn(`An error occured while executing "${method}" in plugin "${plugin.name}":`, err);
1898
+ }
1899
+ /**
1900
+ * Define default values for plugins implicitly required through the `dependencies` plugin stanza.
1901
+ *
1902
+ * @param dependencyPath - The string by which the dependency is listed (not the plugin name)
1903
+ *
1904
+ * @example
1905
+ * chromium.use(stealth)
1906
+ * chromium.plugins.setDependencyDefaults('stealth/evasions/webgl.vendor', { vendor: 'Bob', renderer: 'Alice' })
1907
+ */
1908
+ setDependencyDefaults(dependencyPath, opts) {
1909
+ this._dependencyDefaults.set(dependencyPath, opts);
1910
+ return this;
1911
+ }
1912
+ /**
1913
+ * Define custom plugin modules for plugins implicitly required through the `dependencies` plugin stanza.
1914
+ *
1915
+ * Using this will prevent dynamic imports from being used, which JS bundlers often have issues with.
1916
+ *
1917
+ * @example
1918
+ * chromium.use(stealth)
1919
+ * chromium.plugins.setDependencyResolution('stealth/evasions/webgl.vendor', VendorPlugin)
1920
+ */
1921
+ setDependencyResolution(dependencyPath, pluginModule) {
1922
+ this._dependencyResolution.set(dependencyPath, pluginModule);
1923
+ return this;
1924
+ }
1925
+ /**
1926
+ * Prepare plugins to be used (resolve dependencies, ordering)
1927
+ * @internal
1928
+ */
1929
+ prepare() {
1930
+ this.resolveDependencies();
1931
+ this.order();
1932
+ }
1933
+ /** Return all plugins using the supplied method */
1934
+ filterByMethod(methodName) {
1935
+ return this._plugins.filter(plugin => {
1936
+ // PuppeteerExtraPlugin: The base class will already define all methods, hence we need to do a different check
1937
+ if (!!plugin._childClassMembers &&
1938
+ Array.isArray(plugin._childClassMembers)) {
1939
+ return plugin._childClassMembers.includes(methodName);
1940
+ }
1941
+ return methodName in plugin;
1942
+ });
1943
+ }
1944
+ /** Conditionally add puppeteer compatibility to values provided to the plugins */
1945
+ _addPuppeteerCompatIfNeeded(plugin, method, args) {
1946
+ const canUseShim = plugin._isPuppeteerExtraPlugin && !plugin.noPuppeteerShim;
1947
+ const methodWhitelist = [
1948
+ 'onBrowser',
1949
+ 'onPageCreated',
1950
+ 'onPageClose',
1951
+ 'afterConnect',
1952
+ 'afterLaunch'
1953
+ ];
1954
+ const shouldUseShim = methodWhitelist.includes(method);
1955
+ if (!canUseShim || !shouldUseShim) {
1956
+ return args;
1957
+ }
1958
+ debug$1('add puppeteer compatibility', plugin.name, method);
1959
+ return [...args.map(arg => addPuppeteerCompat(arg))];
1960
+ }
1961
+ /**
1962
+ * Dispatch plugin lifecycle events in a typesafe way.
1963
+ * Only Plugins that expose the supplied property will be called.
1964
+ *
1965
+ * Will not await results to dispatch events as fast as possible to all plugins.
1966
+ *
1967
+ * @param method - The lifecycle method name
1968
+ * @param args - Optional: Any arguments to be supplied to the plugin methods
1969
+ * @internal
1970
+ */
1971
+ dispatch(method, ...args) {
1972
+ var _a, _b;
1973
+ const plugins = this.filterByMethod(method);
1974
+ debug$1('dispatch', method, {
1975
+ all: this._plugins.length,
1976
+ filteredByMethod: plugins.length
1977
+ });
1978
+ for (const plugin of plugins) {
1979
+ try {
1980
+ args = this._addPuppeteerCompatIfNeeded.bind(this)(plugin, method, args);
1981
+ const fnType = (_b = (_a = plugin[method]) === null || _a === void 0 ? void 0 : _a.constructor) === null || _b === void 0 ? void 0 : _b.name;
1982
+ debug$1('dispatch to plugin', {
1983
+ plugin: plugin.name,
1984
+ method,
1985
+ fnType
1986
+ });
1987
+ if (fnType === 'AsyncFunction') {
1988
+ ;
1989
+ plugin[method](...args).catch((err) => this.onPluginError(plugin, method, err));
1990
+ }
1991
+ else {
1992
+ ;
1993
+ plugin[method](...args);
1994
+ }
1995
+ }
1996
+ catch (err) {
1997
+ this.onPluginError(plugin, method, err);
1998
+ }
1999
+ }
2000
+ }
2001
+ /**
2002
+ * Dispatch plugin lifecycle events in a typesafe way.
2003
+ * Only Plugins that expose the supplied property will be called.
2004
+ *
2005
+ * Can also be used to get a definite return value after passing it to plugins:
2006
+ * Calls plugins sequentially and passes on a value (waterfall style).
2007
+ *
2008
+ * The plugins can either modify the value or return an updated one.
2009
+ * Will return the latest, updated value which ran through all plugins.
2010
+ *
2011
+ * By convention only the first argument will be used as the updated value.
2012
+ *
2013
+ * @param method - The lifecycle method name
2014
+ * @param args - Optional: Any arguments to be supplied to the plugin methods
2015
+ * @internal
2016
+ */
2017
+ async dispatchBlocking(method, ...args) {
2018
+ const plugins = this.filterByMethod(method);
2019
+ debug$1('dispatchBlocking', method, {
2020
+ all: this._plugins.length,
2021
+ filteredByMethod: plugins.length
2022
+ });
2023
+ let retValue = null;
2024
+ for (const plugin of plugins) {
2025
+ try {
2026
+ args = this._addPuppeteerCompatIfNeeded.bind(this)(plugin, method, args);
2027
+ retValue = await plugin[method](...args);
2028
+ // In case we got a return value use that as new first argument for followup function calls
2029
+ if (retValue !== undefined) {
2030
+ args[0] = retValue;
2031
+ }
2032
+ }
2033
+ catch (err) {
2034
+ this.onPluginError(plugin, method, err);
2035
+ return retValue;
2036
+ }
2037
+ }
2038
+ return retValue;
2039
+ }
2040
+ /**
2041
+ * Order plugins that have expressed a special placement requirement.
2042
+ *
2043
+ * This is useful/necessary for e.g. plugins that depend on the data from other plugins.
2044
+ *
2045
+ * @private
2046
+ */
2047
+ order() {
2048
+ debug$1('order:before', this.names);
2049
+ const runLast = this._plugins
2050
+ .filter(p => { var _a; return (_a = p.requirements) === null || _a === void 0 ? void 0 : _a.has('runLast'); })
2051
+ .map(p => p.name);
2052
+ for (const name of runLast) {
2053
+ const index = this._plugins.findIndex(p => p.name === name);
2054
+ this._plugins.push(this._plugins.splice(index, 1)[0]);
2055
+ }
2056
+ debug$1('order:after', this.names);
2057
+ }
2058
+ /**
2059
+ * Collects the exposed `data` property of all registered plugins.
2060
+ * Will be reduced/flattened to a single array.
2061
+ *
2062
+ * Can be accessed by plugins that listed the `dataFromPlugins` requirement.
2063
+ *
2064
+ * Implemented mainly for plugins that need data from other plugins (e.g. `user-preferences`).
2065
+ *
2066
+ * @see [PuppeteerExtraPlugin]/data
2067
+ * @param name - Filter data by optional name
2068
+ *
2069
+ * @private
2070
+ */
2071
+ getData(name) {
2072
+ const data = this._plugins
2073
+ .filter((p) => !!p.data)
2074
+ .map((p) => (Array.isArray(p.data) ? p.data : [p.data]))
2075
+ .reduce((acc, arr) => [...acc, ...arr], []);
2076
+ return name ? data.filter((d) => d.name === name) : data;
2077
+ }
2078
+ /**
2079
+ * Handle `plugins` stanza (already instantiated plugins that don't require dynamic imports)
2080
+ */
2081
+ resolvePluginsStanza() {
2082
+ debug$1('resolvePluginsStanza');
2083
+ const pluginNames = new Set(this.names);
2084
+ this._plugins
2085
+ .filter(p => !!p.plugins && p.plugins.length)
2086
+ .filter(p => !pluginNames.has(p.name)) // TBD: Do we want to filter out existing?
2087
+ .forEach(parent => {
2088
+ (parent.plugins || []).forEach(p => {
2089
+ debug$1(parent.name, 'adding missing plugin', p.name);
2090
+ this.add(p);
2091
+ });
2092
+ });
2093
+ }
2094
+ /**
2095
+ * Handle `dependencies` stanza (which requires dynamic imports)
2096
+ *
2097
+ * Plugins can define `dependencies` as a Set or Array of dependency paths, or a Map with additional opts
2098
+ *
2099
+ * @note
2100
+ * - The default opts for implicit dependencies can be defined using `setDependencyDefaults()`
2101
+ * - Dynamic imports can be avoided by providing plugin modules with `setDependencyResolution()`
2102
+ */
2103
+ resolveDependenciesStanza() {
2104
+ debug$1('resolveDependenciesStanza');
2105
+ /** Attempt to dynamically require a plugin module */
2106
+ const requireDependencyOrDie = (parentName, dependencyPath) => {
2107
+ // If the user provided the plugin module already we use that
2108
+ if (this._dependencyResolution.has(dependencyPath)) {
2109
+ return this._dependencyResolution.get(dependencyPath);
2110
+ }
2111
+ const possiblePrefixes = ['puppeteer-extra-plugin-']; // could be extended later
2112
+ const isAlreadyPrefixed = possiblePrefixes.some(prefix => dependencyPath.startsWith(prefix));
2113
+ const packagePaths = [];
2114
+ // If the dependency is not already prefixed we attempt to require all possible combinations to find one that works
2115
+ if (!isAlreadyPrefixed) {
2116
+ packagePaths.push(...possiblePrefixes.map(prefix => prefix + dependencyPath));
2117
+ }
2118
+ // We always attempt to require the path verbatim (as a last resort)
2119
+ packagePaths.push(dependencyPath);
2120
+ const pluginModule = requirePackages(packagePaths);
2121
+ if (pluginModule) {
2122
+ return pluginModule;
2123
+ }
2124
+ const explanation = `
2125
+ The plugin '${parentName}' listed '${dependencyPath}' as dependency,
2126
+ which could not be found. Please install it:
2127
+
2128
+ ${packagePaths
2129
+ .map(packagePath => `yarn add ${packagePath.split('/')[0]}`)
2130
+ .join(`\n or:\n`)}
2131
+
2132
+ Note: You don't need to require the plugin yourself,
2133
+ unless you want to modify it's default settings.
2134
+
2135
+ If your bundler has issues with dynamic imports take a look at '.plugins.setDependencyResolution()'.
2136
+ `;
2137
+ console.warn(explanation);
2138
+ throw new Error('Plugin dependency not found');
2139
+ };
2140
+ const existingPluginNames = new Set(this.names);
2141
+ const recursivelyLoadMissingDependencies = ({ name: parentName, dependencies }) => {
2142
+ if (!dependencies) {
2143
+ return;
2144
+ }
2145
+ const processDependency = (dependencyPath, opts) => {
2146
+ const pluginModule = requireDependencyOrDie(parentName, dependencyPath);
2147
+ opts = opts || this._dependencyDefaults.get(dependencyPath) || {};
2148
+ const plugin = pluginModule(opts);
2149
+ if (existingPluginNames.has(plugin.name)) {
2150
+ debug$1(parentName, '=> dependency already exists:', plugin.name);
2151
+ return;
2152
+ }
2153
+ existingPluginNames.add(plugin.name);
2154
+ debug$1(parentName, '=> adding new dependency:', plugin.name, opts);
2155
+ this.add(plugin);
2156
+ return recursivelyLoadMissingDependencies(plugin);
2157
+ };
2158
+ if (dependencies instanceof Set || Array.isArray(dependencies)) {
2159
+ return [...dependencies].forEach(dependencyPath => processDependency(dependencyPath));
2160
+ }
2161
+ if (dependencies instanceof Map) {
2162
+ // Note: `k,v => v,k` (Map + forEach will reverse the order)
2163
+ return dependencies.forEach((v, k) => processDependency(k, v));
2164
+ }
2165
+ };
2166
+ this.list.forEach(recursivelyLoadMissingDependencies);
2167
+ }
2168
+ /**
2169
+ * Lightweight plugin dependency management to require plugins and code mods on demand.
2170
+ * @private
2171
+ */
2172
+ resolveDependencies() {
2173
+ debug$1('resolveDependencies');
2174
+ this.resolvePluginsStanza();
2175
+ this.resolveDependenciesStanza();
2176
+ }
2177
+ }
2178
+
2179
+ const debug$2 = debug$3('playwright-extra');
2180
+ /**
2181
+ * Modular plugin framework to teach `playwright` new tricks.
2182
+ */
2183
+ class PlaywrightExtraClass {
2184
+ constructor(_launcher) {
2185
+ this._launcher = _launcher;
2186
+ this.plugins = new PluginList();
2187
+ }
2188
+ /**
2189
+ * The **main interface** to register plugins.
2190
+ *
2191
+ * Can be called multiple times to enable multiple plugins.
2192
+ *
2193
+ * Plugins derived from `PuppeteerExtraPlugin` will be used with a compatiblity layer.
2194
+ *
2195
+ * @example
2196
+ * chromium.use(plugin1).use(plugin2)
2197
+ * firefox.use(plugin1).use(plugin2)
2198
+ *
2199
+ * @see [PuppeteerExtraPlugin]
2200
+ *
2201
+ * @return The same `PlaywrightExtra` instance (for optional chaining)
2202
+ */
2203
+ use(plugin) {
2204
+ const isValid = plugin && 'name' in plugin;
2205
+ if (!isValid) {
2206
+ throw new Error('A plugin must be provided to .use()');
2207
+ }
2208
+ if (this.plugins.add(plugin)) {
2209
+ debug$2('Plugin registered', plugin.name);
2210
+ }
2211
+ return this;
2212
+ }
2213
+ /**
2214
+ * In order to support a default export which will require vanilla playwright automatically,
2215
+ * as well as `addExtra` to patch a provided launcher, we need to so some gymnastics here.
2216
+ *
2217
+ * Otherwise this would throw immediately, even when only using the `addExtra` export with an arbitrary compatible launcher.
2218
+ *
2219
+ * The solution is to make the vanilla launcher optional and only throw once we try to effectively use and can't find it.
2220
+ *
2221
+ * @internal
2222
+ */
2223
+ get launcher() {
2224
+ if (!this._launcher) {
2225
+ throw playwrightLoader.requireError;
2226
+ }
2227
+ return this._launcher;
2228
+ }
2229
+ async launch(...args) {
2230
+ if (!this.launcher.launch) {
2231
+ throw new Error('Launcher does not support "launch"');
2232
+ }
2233
+ let [options] = args;
2234
+ options = Object.assign({ args: [] }, (options || {})); // Initialize args array
2235
+ debug$2('launch', options);
2236
+ this.plugins.prepare();
2237
+ // Give plugins the chance to modify the options before continuing
2238
+ options =
2239
+ (await this.plugins.dispatchBlocking('beforeLaunch', options)) || options;
2240
+ debug$2('launch with options', options);
2241
+ if ('userDataDir' in options) {
2242
+ debug$2("A plugin defined userDataDir during .launch, which isn't supported by playwright - ignoring");
2243
+ delete options.userDataDir;
2244
+ }
2245
+ const browser = await this.launcher['launch'](options);
2246
+ await this.plugins.dispatchBlocking('onBrowser', browser);
2247
+ await this._bindBrowserEvents(browser);
2248
+ await this.plugins.dispatchBlocking('afterLaunch', browser);
2249
+ return browser;
2250
+ }
2251
+ async launchPersistentContext(...args) {
2252
+ if (!this.launcher.launchPersistentContext) {
2253
+ throw new Error('Launcher does not support "launchPersistentContext"');
2254
+ }
2255
+ let [userDataDir, options] = args;
2256
+ options = Object.assign({ args: [] }, (options || {})); // Initialize args array
2257
+ debug$2('launchPersistentContext', options);
2258
+ this.plugins.prepare();
2259
+ // Give plugins the chance to modify the options before continuing
2260
+ options =
2261
+ (await this.plugins.dispatchBlocking('beforeLaunch', options)) || options;
2262
+ const context = await this.launcher['launchPersistentContext'](userDataDir, options);
2263
+ await this.plugins.dispatchBlocking('afterLaunch', context);
2264
+ this._bindBrowserContextEvents(context);
2265
+ return context;
2266
+ }
2267
+ async connect(wsEndpointOrOptions, wsOptions = {}) {
2268
+ if (!this.launcher.connect) {
2269
+ throw new Error('Launcher does not support "connect"');
2270
+ }
2271
+ this.plugins.prepare();
2272
+ // Playwright currently supports two function signatures for .connect
2273
+ let options = {};
2274
+ let wsEndpointAsString = false;
2275
+ if (typeof wsEndpointOrOptions === 'object') {
2276
+ options = Object.assign(Object.assign({}, wsEndpointOrOptions), wsOptions);
2277
+ }
2278
+ else {
2279
+ wsEndpointAsString = true;
2280
+ options = Object.assign({ wsEndpoint: wsEndpointOrOptions }, wsOptions);
2281
+ }
2282
+ debug$2('connect', options);
2283
+ // Give plugins the chance to modify the options before launch/connect
2284
+ options =
2285
+ (await this.plugins.dispatchBlocking('beforeConnect', options)) || options;
2286
+ // Follow call signature of end user
2287
+ const args = [];
2288
+ const wsEndpoint = options.wsEndpoint;
2289
+ if (wsEndpointAsString) {
2290
+ delete options.wsEndpoint;
2291
+ args.push(wsEndpoint, options);
2292
+ }
2293
+ else {
2294
+ args.push(options);
2295
+ }
2296
+ const browser = (await this.launcher['connect'](...args));
2297
+ await this.plugins.dispatchBlocking('onBrowser', browser);
2298
+ await this._bindBrowserEvents(browser);
2299
+ await this.plugins.dispatchBlocking('afterConnect', browser);
2300
+ return browser;
2301
+ }
2302
+ async connectOverCDP(wsEndpointOrOptions, wsOptions = {}) {
2303
+ if (!this.launcher.connectOverCDP) {
2304
+ throw new Error(`Launcher does not implement 'connectOverCDP'`);
2305
+ }
2306
+ this.plugins.prepare();
2307
+ // Playwright currently supports two function signatures for .connectOverCDP
2308
+ let options = {};
2309
+ let wsEndpointAsString = false;
2310
+ if (typeof wsEndpointOrOptions === 'object') {
2311
+ options = Object.assign(Object.assign({}, wsEndpointOrOptions), wsOptions);
2312
+ }
2313
+ else {
2314
+ wsEndpointAsString = true;
2315
+ options = Object.assign({ endpointURL: wsEndpointOrOptions }, wsOptions);
2316
+ }
2317
+ debug$2('connectOverCDP');
2318
+ // Give plugins the chance to modify the options before launch/connect
2319
+ options =
2320
+ (await this.plugins.dispatchBlocking('beforeConnect', options)) || options;
2321
+ // Follow call signature of end user
2322
+ const args = [];
2323
+ const endpointURL = options.endpointURL;
2324
+ if (wsEndpointAsString) {
2325
+ delete options.endpointURL;
2326
+ args.push(endpointURL, options);
2327
+ }
2328
+ else {
2329
+ args.push(options);
2330
+ }
2331
+ const browser = (await this.launcher['connectOverCDP'](...args));
2332
+ await this.plugins.dispatchBlocking('onBrowser', browser);
2333
+ await this._bindBrowserEvents(browser);
2334
+ await this.plugins.dispatchBlocking('afterConnect', browser);
2335
+ return browser;
2336
+ }
2337
+ async _bindBrowserContextEvents(context, contextOptions) {
2338
+ debug$2('_bindBrowserContextEvents');
2339
+ this.plugins.dispatch('onContextCreated', context, contextOptions);
2340
+ // Make sure things like `addInitScript` show an effect on the very first page as well
2341
+ context.newPage = ((originalMethod, ctx) => {
2342
+ return async () => {
2343
+ const page = await originalMethod.call(ctx);
2344
+ await page.goto('about:blank');
2345
+ return page;
2346
+ };
2347
+ })(context.newPage, context);
2348
+ context.on('close', () => {
2349
+ // When using `launchPersistentContext` context closing is the same as browser closing
2350
+ if (!context.browser()) {
2351
+ this.plugins.dispatch('onDisconnected');
2352
+ }
2353
+ });
2354
+ context.on('page', page => {
2355
+ this.plugins.dispatch('onPageCreated', page);
2356
+ page.on('close', () => {
2357
+ this.plugins.dispatch('onPageClose', page);
2358
+ });
2359
+ });
2360
+ }
2361
+ async _bindBrowserEvents(browser) {
2362
+ debug$2('_bindPlaywrightBrowserEvents');
2363
+ browser.on('disconnected', () => {
2364
+ this.plugins.dispatch('onDisconnected', browser);
2365
+ });
2366
+ // Note: `browser.newPage` will implicitly call `browser.newContext` as well
2367
+ browser.newContext = ((originalMethod, ctx) => {
2368
+ return async (options = {}) => {
2369
+ const contextOptions = (await this.plugins.dispatchBlocking('beforeContext', options, browser)) || options;
2370
+ const context = await originalMethod.call(ctx, contextOptions);
2371
+ this._bindBrowserContextEvents(context, contextOptions);
2372
+ return context;
2373
+ };
2374
+ })(browser.newContext, browser);
2375
+ }
2376
+ }
2377
+ /**
2378
+ * PlaywrightExtra class with additional launcher methods.
2379
+ *
2380
+ * Augments the class with an instance proxy to pass on methods that are not augmented to the original target.
2381
+ *
2382
+ */
2383
+ const PlaywrightExtra = new Proxy(PlaywrightExtraClass, {
2384
+ construct(classTarget, args) {
2385
+ debug$2(`create instance of ${classTarget.name}`);
2386
+ const result = Reflect.construct(classTarget, args);
2387
+ return new Proxy(result, {
2388
+ get(target, prop) {
2389
+ if (prop in target) {
2390
+ return Reflect.get(target, prop);
2391
+ }
2392
+ debug$2('proxying property to original launcher: ', prop);
2393
+ return Reflect.get(target.launcher, prop);
2394
+ }
2395
+ });
2396
+ }
2397
+ });
2398
+
2399
+ /**
2400
+ * Augment the provided Playwright browser launcher with plugin functionality.
2401
+ *
2402
+ * Using `addExtra` will always create a fresh PlaywrightExtra instance.
2403
+ *
2404
+ * @example
2405
+ * import playwright from 'playwright'
2406
+ * import { addExtra } from 'playwright-extra'
2407
+ *
2408
+ * const chromium = addExtra(playwright.chromium)
2409
+ * chromium.use(plugin)
2410
+ *
2411
+ * @param launcher - Playwright (or compatible) browser launcher
2412
+ */
2413
+ const addExtra = (launcher) => new PlaywrightExtra(launcher);
2414
+ /**
2415
+ * This object can be used to launch or connect to Chromium with plugin functionality.
2416
+ *
2417
+ * This default export will behave exactly the same as the regular playwright
2418
+ * (just with extra plugin functionality) and can be used as a drop-in replacement.
2419
+ *
2420
+ * Behind the scenes it will try to require either the `playwright-core`
2421
+ * or `playwright` module from the installed dependencies.
2422
+ *
2423
+ * @note
2424
+ * Due to Node.js import caching this will result in a single
2425
+ * PlaywrightExtra instance, even when used in different files. If you need multiple
2426
+ * instances with different plugins please use `addExtra`.
2427
+ *
2428
+ * @example
2429
+ * // javascript import
2430
+ * const { chromium } = require('playwright-extra')
2431
+ *
2432
+ * // typescript/es6 module import
2433
+ * import { chromium } from 'playwright-extra'
2434
+ *
2435
+ * // Add plugins
2436
+ * chromium.use(...)
2437
+ */
2438
+ const chromium = addExtra((playwrightLoader.loadModule() || {}).chromium);
2439
+ /**
2440
+ * This object can be used to launch or connect to Firefox with plugin functionality
2441
+ * @note This export will always return the same instance, if you wish to use multiple instances with different plugins use `addExtra`
2442
+ */
2443
+ addExtra((playwrightLoader.loadModule() || {}).firefox);
2444
+ /**
2445
+ * This object can be used to launch or connect to Webkit with plugin functionality
2446
+ * @note This export will always return the same instance, if you wish to use multiple instances with different plugins use `addExtra`
2447
+ */
2448
+ addExtra((playwrightLoader.loadModule() || {}).webkit);
2449
+ // Other playwright module exports we simply re-export with lazy loading
2450
+ playwrightLoader.lazyloadExportOrDie('_android');
2451
+ playwrightLoader.lazyloadExportOrDie('_electron');
2452
+ playwrightLoader.lazyloadExportOrDie('request');
2453
+ playwrightLoader.lazyloadExportOrDie('selectors');
2454
+ playwrightLoader.lazyloadExportOrDie('devices');
2455
+ playwrightLoader.lazyloadExportOrDie('errors');
2456
+
2457
+ /*!
2458
+ * puppeteer-extra-plugin v3.2.2 by berstend
2459
+ * https://github.com/berstend/puppeteer-extra/tree/master/packages/puppeteer-extra-plugin
2460
+ * @license MIT
2461
+ */
2462
+
2463
+ /** @private */
2464
+ const merge$1 = require('merge-deep');
2465
+ /**
2466
+ * Base class for `puppeteer-extra` plugins.
2467
+ *
2468
+ * Provides convenience methods to avoid boilerplate.
2469
+ *
2470
+ * All common `puppeteer` browser events will be bound to
2471
+ * the plugin instance, if a respectively named class member is found.
2472
+ *
2473
+ * Please refer to the [puppeteer API documentation](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md) as well.
2474
+ *
2475
+ * @example
2476
+ * // hello-world-plugin.js
2477
+ * const { PuppeteerExtraPlugin } = require('puppeteer-extra-plugin')
2478
+ *
2479
+ * class Plugin extends PuppeteerExtraPlugin {
2480
+ * constructor (opts = { }) { super(opts) }
2481
+ *
2482
+ * get name () { return 'hello-world' }
2483
+ *
2484
+ * async onPageCreated (page) {
2485
+ * this.debug('page created', page.url())
2486
+ * const ua = await page.browser().userAgent()
2487
+ * this.debug('user agent', ua)
2488
+ * }
2489
+ * }
2490
+ *
2491
+ * module.exports = function (pluginConfig) { return new Plugin(pluginConfig) }
2492
+ *
2493
+ *
2494
+ * // foo.js
2495
+ * const puppeteer = require('puppeteer-extra')
2496
+ * puppeteer.use(require('./hello-world-plugin')())
2497
+ *
2498
+ * ;(async () => {
2499
+ * const browser = await puppeteer.launch({headless: false})
2500
+ * const page = await browser.newPage()
2501
+ * await page.goto('http://example.com', {waitUntil: 'domcontentloaded'})
2502
+ * await browser.close()
2503
+ * })()
2504
+ *
2505
+ */
2506
+ class PuppeteerExtraPlugin$1 {
2507
+ constructor(opts) {
2508
+ this._debugBase = debug$3(`puppeteer-extra-plugin:base:${this.name}`);
2509
+ this._childClassMembers = [];
2510
+ this._opts = merge$1(this.defaults, opts || {});
2511
+ this._debugBase('Initialized.');
2512
+ }
2513
+ /**
2514
+ * Plugin name (required).
2515
+ *
2516
+ * Convention:
2517
+ * - Package: `puppeteer-extra-plugin-anonymize-ua`
2518
+ * - Name: `anonymize-ua`
2519
+ *
2520
+ * @example
2521
+ * get name () { return 'anonymize-ua' }
2522
+ */
2523
+ get name() {
2524
+ throw new Error('Plugin must override "name"');
2525
+ }
2526
+ /**
2527
+ * Plugin defaults (optional).
2528
+ *
2529
+ * If defined will be ([deep-](https://github.com/jonschlinkert/merge-deep))merged with the (optional) user supplied options (supplied during plugin instantiation).
2530
+ *
2531
+ * The result of merging defaults with user supplied options can be accessed through `this.opts`.
2532
+ *
2533
+ * @see [[opts]]
2534
+ *
2535
+ * @example
2536
+ * get defaults () {
2537
+ * return {
2538
+ * stripHeadless: true,
2539
+ * makeWindows: true,
2540
+ * customFn: null
2541
+ * }
2542
+ * }
2543
+ *
2544
+ * // Users can overwrite plugin defaults during instantiation:
2545
+ * puppeteer.use(require('puppeteer-extra-plugin-foobar')({ makeWindows: false }))
2546
+ */
2547
+ get defaults() {
2548
+ return {};
2549
+ }
2550
+ /**
2551
+ * Plugin requirements (optional).
2552
+ *
2553
+ * Signal certain plugin requirements to the base class and the user.
2554
+ *
2555
+ * Currently supported:
2556
+ * - `launch`
2557
+ * - If the plugin only supports locally created browser instances (no `puppeteer.connect()`),
2558
+ * will output a warning to the user.
2559
+ * - `headful`
2560
+ * - If the plugin doesn't work in `headless: true` mode,
2561
+ * will output a warning to the user.
2562
+ * - `dataFromPlugins`
2563
+ * - In case the plugin requires data from other plugins.
2564
+ * will enable usage of `this.getDataFromPlugins()`.
2565
+ * - `runLast`
2566
+ * - In case the plugin prefers to run after the others.
2567
+ * Useful when the plugin needs data from others.
2568
+ *
2569
+ * @example
2570
+ * get requirements () {
2571
+ * return new Set(['runLast', 'dataFromPlugins'])
2572
+ * }
2573
+ */
2574
+ get requirements() {
2575
+ return new Set([]);
2576
+ }
2577
+ /**
2578
+ * Plugin dependencies (optional).
2579
+ *
2580
+ * Missing plugins will be required() by puppeteer-extra.
2581
+ *
2582
+ * @example
2583
+ * get dependencies () {
2584
+ * return new Set(['user-preferences'])
2585
+ * }
2586
+ * // Will ensure the 'puppeteer-extra-plugin-user-preferences' plugin is loaded.
2587
+ */
2588
+ get dependencies() {
2589
+ return new Set([]);
2590
+ }
2591
+ /**
2592
+ * Plugin data (optional).
2593
+ *
2594
+ * Plugins can expose data (an array of objects), which in turn can be consumed by other plugins,
2595
+ * that list the `dataFromPlugins` requirement (by using `this.getDataFromPlugins()`).
2596
+ *
2597
+ * Convention: `[ {name: 'Any name', value: 'Any value'} ]`
2598
+ *
2599
+ * @see [[getDataFromPlugins]]
2600
+ *
2601
+ * @example
2602
+ * // plugin1.js
2603
+ * get data () {
2604
+ * return [
2605
+ * {
2606
+ * name: 'userPreferences',
2607
+ * value: { foo: 'bar' }
2608
+ * },
2609
+ * {
2610
+ * name: 'userPreferences',
2611
+ * value: { hello: 'world' }
2612
+ * }
2613
+ * ]
2614
+ *
2615
+ * // plugin2.js
2616
+ * get requirements () { return new Set(['dataFromPlugins']) }
2617
+ *
2618
+ * async beforeLaunch () {
2619
+ * const prefs = this.getDataFromPlugins('userPreferences').map(d => d.value)
2620
+ * this.debug(prefs) // => [ { foo: 'bar' }, { hello: 'world' } ]
2621
+ * }
2622
+ */
2623
+ get data() {
2624
+ return [];
2625
+ }
2626
+ /**
2627
+ * Access the plugin options (usually the `defaults` merged with user defined options)
2628
+ *
2629
+ * To skip the auto-merging of defaults with user supplied opts don't define a `defaults`
2630
+ * property and set the `this._opts` Object in your plugin constructor directly.
2631
+ *
2632
+ * @see [[defaults]]
2633
+ *
2634
+ * @example
2635
+ * get defaults () { return { foo: "bar" } }
2636
+ *
2637
+ * async onPageCreated (page) {
2638
+ * this.debug(this.opts.foo) // => bar
2639
+ * }
2640
+ */
2641
+ get opts() {
2642
+ return this._opts;
2643
+ }
2644
+ /**
2645
+ * Convenience debug logger based on the [debug] module.
2646
+ * Will automatically namespace the logging output to the plugin package name.
2647
+ * [debug]: https://www.npmjs.com/package/debug
2648
+ *
2649
+ * ```bash
2650
+ * # toggle output using environment variables
2651
+ * DEBUG=puppeteer-extra-plugin:<plugin_name> node foo.js
2652
+ * # to debug all the things:
2653
+ * DEBUG=puppeteer-extra,puppeteer-extra-plugin:* node foo.js
2654
+ * ```
2655
+ *
2656
+ * @example
2657
+ * this.debug('hello world')
2658
+ * // will output e.g. 'puppeteer-extra-plugin:anonymize-ua hello world'
2659
+ */
2660
+ get debug() {
2661
+ return debug$3(`puppeteer-extra-plugin:${this.name}`);
2662
+ }
2663
+ /**
2664
+ * Before a new browser instance is created/launched.
2665
+ *
2666
+ * Can be used to modify the puppeteer launch options by modifying or returning them.
2667
+ *
2668
+ * Plugins using this method will be called in sequence to each
2669
+ * be able to update the launch options.
2670
+ *
2671
+ * @example
2672
+ * async beforeLaunch (options) {
2673
+ * if (this.opts.flashPluginPath) {
2674
+ * options.args.push(`--ppapi-flash-path=${this.opts.flashPluginPath}`)
2675
+ * }
2676
+ * }
2677
+ *
2678
+ * @param options - Puppeteer launch options
2679
+ */
2680
+ async beforeLaunch(options) {
2681
+ // noop
2682
+ }
2683
+ /**
2684
+ * After the browser has launched.
2685
+ *
2686
+ * Note: Don't assume that there will only be a single browser instance during the lifecycle of a plugin.
2687
+ * It's possible that `pupeeteer.launch` will be called multiple times and more than one browser created.
2688
+ * In order to make the plugins as stateless as possible don't store a reference to the browser instance
2689
+ * in the plugin but rather consider alternatives.
2690
+ *
2691
+ * E.g. when using `onPageCreated` you can get a browser reference by using `page.browser()`.
2692
+ *
2693
+ * Alternatively you could expose a class method that takes a browser instance as a parameter to work with:
2694
+ *
2695
+ * ```es6
2696
+ * const fancyPlugin = require('puppeteer-extra-plugin-fancy')()
2697
+ * puppeteer.use(fancyPlugin)
2698
+ * const browser = await puppeteer.launch()
2699
+ * await fancyPlugin.killBrowser(browser)
2700
+ * ```
2701
+ *
2702
+ * @param browser - The `puppeteer` browser instance.
2703
+ * @param opts.options - Puppeteer launch options used.
2704
+ *
2705
+ * @example
2706
+ * async afterLaunch (browser, opts) {
2707
+ * this.debug('browser has been launched', opts.options)
2708
+ * }
2709
+ */
2710
+ async afterLaunch(browser, opts = { options: {} }) {
2711
+ // noop
2712
+ }
2713
+ /**
2714
+ * Before connecting to an existing browser instance.
2715
+ *
2716
+ * Can be used to modify the puppeteer connect options by modifying or returning them.
2717
+ *
2718
+ * Plugins using this method will be called in sequence to each
2719
+ * be able to update the launch options.
2720
+ *
2721
+ * @param {Object} options - Puppeteer connect options
2722
+ * @return {Object=}
2723
+ */
2724
+ async beforeConnect(options) {
2725
+ // noop
2726
+ }
2727
+ /**
2728
+ * After connecting to an existing browser instance.
2729
+ *
2730
+ * > Note: Don't assume that there will only be a single browser instance during the lifecycle of a plugin.
2731
+ *
2732
+ * @param browser - The `puppeteer` browser instance.
2733
+ * @param {Object} opts
2734
+ * @param {Object} opts.options - Puppeteer connect options used.
2735
+ *
2736
+ */
2737
+ async afterConnect(browser, opts = {}) {
2738
+ // noop
2739
+ }
2740
+ /**
2741
+ * Called when a browser instance is available.
2742
+ *
2743
+ * This applies to both `puppeteer.launch()` and `puppeteer.connect()`.
2744
+ *
2745
+ * Convenience method created for plugins that need access to a browser instance
2746
+ * and don't mind if it has been created through `launch` or `connect`.
2747
+ *
2748
+ * > Note: Don't assume that there will only be a single browser instance during the lifecycle of a plugin.
2749
+ *
2750
+ * @param browser - The `puppeteer` browser instance.
2751
+ */
2752
+ async onBrowser(browser, opts) {
2753
+ // noop
2754
+ }
2755
+ /**
2756
+ * Called when a target is created, for example when a new page is opened by window.open or browser.newPage.
2757
+ *
2758
+ * > Note: This includes target creations in incognito browser contexts.
2759
+ *
2760
+ * > Note: This includes browser instances created through `.launch()` as well as `.connect()`.
2761
+ *
2762
+ * @param {Puppeteer.Target} target
2763
+ */
2764
+ async onTargetCreated(target) {
2765
+ // noop
2766
+ }
2767
+ /**
2768
+ * Same as `onTargetCreated` but prefiltered to only contain Pages, for convenience.
2769
+ *
2770
+ * > Note: This includes page creations in incognito browser contexts.
2771
+ *
2772
+ * > Note: This includes browser instances created through `.launch()` as well as `.connect()`.
2773
+ *
2774
+ * @param {Puppeteer.Target} target
2775
+ *
2776
+ * @example
2777
+ * async onPageCreated (page) {
2778
+ * let ua = await page.browser().userAgent()
2779
+ * if (this.opts.stripHeadless) {
2780
+ * ua = ua.replace('HeadlessChrome/', 'Chrome/')
2781
+ * }
2782
+ * this.debug('new ua', ua)
2783
+ * await page.setUserAgent(ua)
2784
+ * }
2785
+ */
2786
+ async onPageCreated(page) {
2787
+ // noop
2788
+ }
2789
+ /**
2790
+ * Called when the url of a target changes.
2791
+ *
2792
+ * > Note: This includes target changes in incognito browser contexts.
2793
+ *
2794
+ * > Note: This includes browser instances created through `.launch()` as well as `.connect()`.
2795
+ *
2796
+ * @param {Puppeteer.Target} target
2797
+ */
2798
+ async onTargetChanged(target) {
2799
+ // noop
2800
+ }
2801
+ /**
2802
+ * Called when a target is destroyed, for example when a page is closed.
2803
+ *
2804
+ * > Note: This includes target destructions in incognito browser contexts.
2805
+ *
2806
+ * > Note: This includes browser instances created through `.launch()` as well as `.connect()`.
2807
+ *
2808
+ * @param {Puppeteer.Target} target
2809
+ */
2810
+ async onTargetDestroyed(target) {
2811
+ // noop
2812
+ }
2813
+ /**
2814
+ * Called when Puppeteer gets disconnected from the Chromium instance.
2815
+ *
2816
+ * This might happen because of one of the following:
2817
+ * - Chromium is closed or crashed
2818
+ * - The `browser.disconnect` method was called
2819
+ */
2820
+ async onDisconnected() {
2821
+ // noop
2822
+ }
2823
+ /**
2824
+ * **Deprecated:** Since puppeteer v1.6.0 `onDisconnected` has been improved
2825
+ * and should be used instead of `onClose`.
2826
+ *
2827
+ * In puppeteer < v1.6.0 `onDisconnected` was not catching all exit scenarios.
2828
+ * In order for plugins to clean up properly (e.g. deleting temporary files)
2829
+ * the `onClose` method had been introduced.
2830
+ *
2831
+ * > Note: Might be called multiple times on exit.
2832
+ *
2833
+ * > Note: This only includes browser instances created through `.launch()`.
2834
+ */
2835
+ async onClose() {
2836
+ // noop
2837
+ }
2838
+ /**
2839
+ * After the plugin has been registered in `puppeteer-extra`.
2840
+ *
2841
+ * Normally right after `puppeteer.use(plugin)` is called
2842
+ */
2843
+ async onPluginRegistered() {
2844
+ // noop
2845
+ }
2846
+ /**
2847
+ * Helper method to retrieve `data` objects from other plugins.
2848
+ *
2849
+ * A plugin needs to state the `dataFromPlugins` requirement
2850
+ * in order to use this method. Will be mapped to `puppeteer.getPluginData`.
2851
+ *
2852
+ * @param name - Filter data by `name` property
2853
+ *
2854
+ * @see [data]
2855
+ * @see [requirements]
2856
+ */
2857
+ getDataFromPlugins(name) {
2858
+ return [];
2859
+ }
2860
+ /**
2861
+ * Will match plugin dependencies against all currently registered plugins.
2862
+ * Is being called by `puppeteer-extra` and used to require missing dependencies.
2863
+ *
2864
+ * @param {Array<Object>} plugins
2865
+ * @return {Set} - list of missing plugin names
2866
+ *
2867
+ * @private
2868
+ */
2869
+ _getMissingDependencies(plugins) {
2870
+ const pluginNames = new Set(plugins.map((p) => p.name));
2871
+ const missing = new Set(Array.from(this.dependencies.values()).filter(x => !pluginNames.has(x)));
2872
+ return missing;
2873
+ }
2874
+ /**
2875
+ * Conditionally bind browser/process events to class members.
2876
+ * The idea is to reduce event binding boilerplate in plugins.
2877
+ *
2878
+ * For efficiency we make sure the plugin is using the respective event
2879
+ * by checking the child class members before registering the listener.
2880
+ *
2881
+ * @param {<Puppeteer.Browser>} browser
2882
+ * @param {Object} opts - Options
2883
+ * @param {string} opts.context - Puppeteer context (launch/connect)
2884
+ * @param {Object} [opts.options] - Puppeteer launch or connect options
2885
+ * @param {Array<string>} [opts.defaultArgs] - The default flags that Chromium will be launched with
2886
+ *
2887
+ * @private
2888
+ */
2889
+ async _bindBrowserEvents(browser, opts = {}) {
2890
+ if (this._hasChildClassMember('onTargetCreated') ||
2891
+ this._hasChildClassMember('onPageCreated')) {
2892
+ browser.on('targetcreated', this._onTargetCreated.bind(this));
2893
+ }
2894
+ if (this._hasChildClassMember('onTargetChanged') && this.onTargetChanged) {
2895
+ browser.on('targetchanged', this.onTargetChanged.bind(this));
2896
+ }
2897
+ if (this._hasChildClassMember('onTargetDestroyed') &&
2898
+ this.onTargetDestroyed) {
2899
+ browser.on('targetdestroyed', this.onTargetDestroyed.bind(this));
2900
+ }
2901
+ if (this._hasChildClassMember('onDisconnected') && this.onDisconnected) {
2902
+ browser.on('disconnected', this.onDisconnected.bind(this));
2903
+ }
2904
+ if (opts.context === 'launch' && this._hasChildClassMember('onClose')) {
2905
+ // The disconnect event has been improved since puppeteer v1.6.0
2906
+ // onClose is being kept mostly for legacy reasons
2907
+ if (this.onClose) {
2908
+ process.on('exit', this.onClose.bind(this));
2909
+ browser.on('disconnected', this.onClose.bind(this));
2910
+ if (opts.options.handleSIGINT !== false) {
2911
+ process.on('SIGINT', this.onClose.bind(this));
2912
+ }
2913
+ if (opts.options.handleSIGTERM !== false) {
2914
+ process.on('SIGTERM', this.onClose.bind(this));
2915
+ }
2916
+ if (opts.options.handleSIGHUP !== false) {
2917
+ process.on('SIGHUP', this.onClose.bind(this));
2918
+ }
2919
+ }
2920
+ }
2921
+ if (opts.context === 'launch' && this.afterLaunch) {
2922
+ await this.afterLaunch(browser, opts);
2923
+ }
2924
+ if (opts.context === 'connect' && this.afterConnect) {
2925
+ await this.afterConnect(browser, opts);
2926
+ }
2927
+ if (this.onBrowser)
2928
+ await this.onBrowser(browser, opts);
2929
+ }
2930
+ /**
2931
+ * @private
2932
+ */
2933
+ async _onTargetCreated(target) {
2934
+ if (this.onTargetCreated)
2935
+ await this.onTargetCreated(target);
2936
+ // Pre filter pages for plugin developers convenience
2937
+ if (target.type() === 'page') {
2938
+ try {
2939
+ const page = await target.page();
2940
+ if (!page) {
2941
+ return;
2942
+ }
2943
+ const validPage = 'isClosed' in page && !page.isClosed();
2944
+ if (this.onPageCreated && validPage) {
2945
+ await this.onPageCreated(page);
2946
+ }
2947
+ }
2948
+ catch (err) {
2949
+ console.error(err);
2950
+ }
2951
+ }
2952
+ }
2953
+ /**
2954
+ * @private
2955
+ */
2956
+ _register(prototype) {
2957
+ this._registerChildClassMembers(prototype);
2958
+ if (this.onPluginRegistered)
2959
+ this.onPluginRegistered();
2960
+ }
2961
+ /**
2962
+ * @private
2963
+ */
2964
+ _registerChildClassMembers(prototype) {
2965
+ this._childClassMembers = Object.getOwnPropertyNames(prototype);
2966
+ }
2967
+ /**
2968
+ * @private
2969
+ */
2970
+ _hasChildClassMember(name) {
2971
+ return !!this._childClassMembers.includes(name);
2972
+ }
2973
+ /**
2974
+ * @private
2975
+ */
2976
+ get _isPuppeteerExtraPlugin() {
2977
+ return true;
2978
+ }
2979
+ }
2980
+
2981
+ var index_esm = /*#__PURE__*/Object.freeze({
2982
+ __proto__: null,
2983
+ PuppeteerExtraPlugin: PuppeteerExtraPlugin$1
2984
+ });
2985
+
2986
+ var require$$0 = /*@__PURE__*/getAugmentedNamespace(index_esm);
2987
+
2988
+ const { PuppeteerExtraPlugin } = require$$0;
2989
+
2990
+ /**
2991
+ * Stealth mode: Applies various techniques to make detection of headless puppeteer harder. 💯
2992
+ *
2993
+ * ### Purpose
2994
+ * There are a couple of ways the use of puppeteer can easily be detected by a target website.
2995
+ * The addition of `HeadlessChrome` to the user-agent being only the most obvious one.
2996
+ *
2997
+ * The goal of this plugin is to be the definite companion to puppeteer to avoid
2998
+ * detection, applying new techniques as they surface.
2999
+ *
3000
+ * As this cat & mouse game is in it's infancy and fast-paced the plugin
3001
+ * is kept as flexibile as possible, to support quick testing and iterations.
3002
+ *
3003
+ * ### Modularity
3004
+ * This plugin uses `puppeteer-extra`'s dependency system to only require
3005
+ * code mods for evasions that have been enabled, to keep things modular and efficient.
3006
+ *
3007
+ * The `stealth` plugin is a convenience wrapper that requires multiple [evasion techniques](./evasions/)
3008
+ * automatically and comes with defaults. You could also bypass the main module and require
3009
+ * specific evasion plugins yourself, if you whish to do so (as they're standalone `puppeteer-extra` plugins):
3010
+ *
3011
+ * ```es6
3012
+ * // bypass main module and require a specific stealth plugin directly:
3013
+ * puppeteer.use(require('puppeteer-extra-plugin-stealth/evasions/console.debug')())
3014
+ * ```
3015
+ *
3016
+ * ### Contributing
3017
+ * PRs are welcome, if you want to add a new evasion technique I suggest you
3018
+ * look at the [template](./evasions/_template) to kickstart things.
3019
+ *
3020
+ * ### Kudos
3021
+ * Thanks to [Evan Sangaline](https://intoli.com/blog/not-possible-to-block-chrome-headless/) and [Paul Irish](https://github.com/paulirish/headless-cat-n-mouse) for kickstarting the discussion!
3022
+ *
3023
+ * ---
3024
+ *
3025
+ * @todo
3026
+ * - white-/blacklist with url globs (make this a generic plugin method?)
3027
+ * - dynamic whitelist based on function evaluation
3028
+ *
3029
+ * @example
3030
+ * const puppeteer = require('puppeteer-extra')
3031
+ * // Enable stealth plugin with all evasions
3032
+ * puppeteer.use(require('puppeteer-extra-plugin-stealth')())
3033
+ *
3034
+ *
3035
+ * ;(async () => {
3036
+ * // Launch the browser in headless mode and set up a page.
3037
+ * const browser = await puppeteer.launch({ args: ['--no-sandbox'], headless: true })
3038
+ * const page = await browser.newPage()
3039
+ *
3040
+ * // Navigate to the page that will perform the tests.
3041
+ * const testUrl = 'https://intoli.com/blog/' +
3042
+ * 'not-possible-to-block-chrome-headless/chrome-headless-test.html'
3043
+ * await page.goto(testUrl)
3044
+ *
3045
+ * // Save a screenshot of the results.
3046
+ * const screenshotPath = '/tmp/headless-test-result.png'
3047
+ * await page.screenshot({path: screenshotPath})
3048
+ * console.log('have a look at the screenshot:', screenshotPath)
3049
+ *
3050
+ * await browser.close()
3051
+ * })()
3052
+ *
3053
+ * @param {Object} [opts] - Options
3054
+ * @param {Set<string>} [opts.enabledEvasions] - Specify which evasions to use (by default all)
3055
+ *
3056
+ */
3057
+ class StealthPlugin extends PuppeteerExtraPlugin {
3058
+ constructor(opts = {}) {
3059
+ super(opts);
3060
+ }
3061
+
3062
+ get name() {
3063
+ return 'stealth'
3064
+ }
3065
+
3066
+ get defaults() {
3067
+ const availableEvasions = new Set([
3068
+ 'chrome.app',
3069
+ 'chrome.csi',
3070
+ 'chrome.loadTimes',
3071
+ 'chrome.runtime',
3072
+ 'defaultArgs',
3073
+ 'iframe.contentWindow',
3074
+ 'media.codecs',
3075
+ 'navigator.hardwareConcurrency',
3076
+ 'navigator.languages',
3077
+ 'navigator.permissions',
3078
+ 'navigator.plugins',
3079
+ 'navigator.webdriver',
3080
+ 'sourceurl',
3081
+ 'user-agent-override',
3082
+ 'webgl.vendor',
3083
+ 'window.outerdimensions'
3084
+ ]);
3085
+ return {
3086
+ availableEvasions,
3087
+ // Enable all available evasions by default
3088
+ enabledEvasions: new Set([...availableEvasions])
3089
+ }
3090
+ }
3091
+
3092
+ /**
3093
+ * Requires evasion techniques dynamically based on configuration.
3094
+ *
3095
+ * @private
3096
+ */
3097
+ get dependencies() {
3098
+ return new Set(
3099
+ [...this.opts.enabledEvasions].map(e => `${this.name}/evasions/${e}`)
3100
+ )
3101
+ }
3102
+
3103
+ /**
3104
+ * Get all available evasions.
3105
+ *
3106
+ * Please look into the [evasions directory](./evasions/) for an up to date list.
3107
+ *
3108
+ * @type {Set<string>} - A Set of all available evasions.
3109
+ *
3110
+ * @example
3111
+ * const pluginStealth = require('puppeteer-extra-plugin-stealth')()
3112
+ * console.log(pluginStealth.availableEvasions) // => Set { 'user-agent', 'console.debug' }
3113
+ * puppeteer.use(pluginStealth)
3114
+ */
3115
+ get availableEvasions() {
3116
+ return this.defaults.availableEvasions
3117
+ }
3118
+
3119
+ /**
3120
+ * Get all enabled evasions.
3121
+ *
3122
+ * Enabled evasions can be configured either through `opts` or by modifying this property.
3123
+ *
3124
+ * @type {Set<string>} - A Set of all enabled evasions.
3125
+ *
3126
+ * @example
3127
+ * // Remove specific evasion from enabled ones dynamically
3128
+ * const pluginStealth = require('puppeteer-extra-plugin-stealth')()
3129
+ * pluginStealth.enabledEvasions.delete('console.debug')
3130
+ * puppeteer.use(pluginStealth)
3131
+ */
3132
+ get enabledEvasions() {
3133
+ return this.opts.enabledEvasions
3134
+ }
3135
+
3136
+ /**
3137
+ * @private
3138
+ */
3139
+ set enabledEvasions(evasions) {
3140
+ this.opts.enabledEvasions = evasions;
3141
+ }
3142
+
3143
+ async onBrowser(browser) {
3144
+ if (browser && browser.setMaxListeners) {
3145
+ // Increase event emitter listeners to prevent MaxListenersExceededWarning
3146
+ browser.setMaxListeners(30);
3147
+ }
3148
+ }
3149
+ }
3150
+
3151
+ /**
3152
+ * Default export, PuppeteerExtraStealthPlugin
3153
+ *
3154
+ * @param {Object} [opts] - Options
3155
+ * @param {Set<string>} [opts.enabledEvasions] - Specify which evasions to use (by default all)
3156
+ */
3157
+ const defaultExport = opts => new StealthPlugin(opts);
3158
+ var puppeteerExtraPluginStealth = defaultExport;
3159
+
3160
+ var stealth = test.test.extend({
3161
+ browser: async ({ browser }, use) => {
3162
+ await browser.close();
3163
+ chromium.use(puppeteerExtraPluginStealth());
3164
+ const stealthBrowser = await chromium.launch();
3165
+ await use(stealthBrowser);
3166
+ await stealthBrowser.close();
3167
+ },
3168
+ });
3169
+
353
3170
  const LOWERCASED = "__LOWERCASED__";
354
3171
  const FORMATS = {
355
3172
  boldList: "boldList",
@@ -406,8 +3223,6 @@ const removeTagsProcessor = {
406
3223
  },
407
3224
  };
408
3225
 
409
- var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
410
-
411
3226
  var tasks = {};
412
3227
 
413
3228
  var utils$k = {};
@@ -470,8 +3285,8 @@ var path$a = {};
470
3285
 
471
3286
  Object.defineProperty(path$a, "__esModule", { value: true });
472
3287
  path$a.convertPosixPathToPattern = path$a.convertWindowsPathToPattern = path$a.convertPathToPattern = path$a.escapePosixPath = path$a.escapeWindowsPath = path$a.escape = path$a.removeLeadingDotSegment = path$a.makeAbsolute = path$a.unixify = void 0;
473
- const os$1 = require$$2__default["default"];
474
- const path$9 = require$$0__default["default"];
3288
+ const os$1 = require$$0__default["default"];
3289
+ const path$9 = require$$0__default$2["default"];
475
3290
  const IS_WINDOWS_PLATFORM = os$1.platform() === 'win32';
476
3291
  const LEADING_DOT_SEGMENT_CHARACTERS_COUNT = 2; // ./ or .\\
477
3292
  /**
@@ -711,8 +3526,8 @@ var isGlob$1 = function isGlob(str, options) {
711
3526
  };
712
3527
 
713
3528
  var isGlob = isGlob$1;
714
- var pathPosixDirname = require$$0__default["default"].posix.dirname;
715
- var isWin32 = require$$2__default["default"].platform() === 'win32';
3529
+ var pathPosixDirname = require$$0__default$2["default"].posix.dirname;
3530
+ var isWin32 = require$$0__default["default"].platform() === 'win32';
716
3531
 
717
3532
  var slash = '/';
718
3533
  var backslash = /\\/g;
@@ -2175,7 +4990,7 @@ var picomatch$2 = {exports: {}};
2175
4990
 
2176
4991
  var utils$f = {};
2177
4992
 
2178
- const path$8 = require$$0__default["default"];
4993
+ const path$8 = require$$0__default$2["default"];
2179
4994
  const WIN_SLASH = '\\\\/';
2180
4995
  const WIN_NO_SLASH = `[^${WIN_SLASH}]`;
2181
4996
 
@@ -2355,7 +5170,7 @@ var constants$3 = {
2355
5170
 
2356
5171
  (function (exports) {
2357
5172
 
2358
- const path = require$$0__default["default"];
5173
+ const path = require$$0__default$2["default"];
2359
5174
  const win32 = process.platform === 'win32';
2360
5175
  const {
2361
5176
  REGEX_BACKSLASH,
@@ -3899,7 +6714,7 @@ parse$2.fastpaths = (input, options) => {
3899
6714
 
3900
6715
  var parse_1 = parse$2;
3901
6716
 
3902
- const path$7 = require$$0__default["default"];
6717
+ const path$7 = require$$0__default$2["default"];
3903
6718
  const scan = scan_1;
3904
6719
  const parse$1 = parse_1;
3905
6720
  const utils$c = utils$f;
@@ -4713,7 +7528,7 @@ var micromatch_1 = micromatch$1;
4713
7528
 
4714
7529
  Object.defineProperty(pattern$1, "__esModule", { value: true });
4715
7530
  pattern$1.removeDuplicateSlashes = pattern$1.matchAny = pattern$1.convertPatternsToRe = pattern$1.makeRe = pattern$1.getPatternParts = pattern$1.expandBraceExpansion = pattern$1.expandPatternsWithBraceExpansion = pattern$1.isAffectDepthOfReadingPattern = pattern$1.endsWithSlashGlobStar = pattern$1.hasGlobStar = pattern$1.getBaseDirectory = pattern$1.isPatternRelatedToParentDirectory = pattern$1.getPatternsOutsideCurrentDirectory = pattern$1.getPatternsInsideCurrentDirectory = pattern$1.getPositivePatterns = pattern$1.getNegativePatterns = pattern$1.isPositivePattern = pattern$1.isNegativePattern = pattern$1.convertToNegativePattern = pattern$1.convertToPositivePattern = pattern$1.isDynamicPattern = pattern$1.isStaticPattern = void 0;
4716
- const path$6 = require$$0__default["default"];
7531
+ const path$6 = require$$0__default$2["default"];
4717
7532
  const globParent = globParent$1;
4718
7533
  const micromatch = micromatch_1;
4719
7534
  const GLOBSTAR = '**';
@@ -4908,7 +7723,7 @@ var stream$4 = {};
4908
7723
  * Copyright (c) 2014-2020 Teambition
4909
7724
  * Licensed under the MIT license.
4910
7725
  */
4911
- const Stream = require$$0__default$2["default"];
7726
+ const Stream = require$$0__default$3["default"];
4912
7727
  const PassThrough = Stream.PassThrough;
4913
7728
  const slice = Array.prototype.slice;
4914
7729
 
@@ -5288,7 +8103,7 @@ var fs$6 = {};
5288
8103
  (function (exports) {
5289
8104
  Object.defineProperty(exports, "__esModule", { value: true });
5290
8105
  exports.createFileSystemAdapter = exports.FILE_SYSTEM_ADAPTER = void 0;
5291
- const fs = require$$0__default$3["default"];
8106
+ const fs = require$$0__default$4["default"];
5292
8107
  exports.FILE_SYSTEM_ADAPTER = {
5293
8108
  lstat: fs.lstat,
5294
8109
  stat: fs.stat,
@@ -5639,7 +8454,7 @@ var fs$2 = {};
5639
8454
  (function (exports) {
5640
8455
  Object.defineProperty(exports, "__esModule", { value: true });
5641
8456
  exports.createFileSystemAdapter = exports.FILE_SYSTEM_ADAPTER = void 0;
5642
- const fs = require$$0__default$3["default"];
8457
+ const fs = require$$0__default$4["default"];
5643
8458
  exports.FILE_SYSTEM_ADAPTER = {
5644
8459
  lstat: fs.lstat,
5645
8460
  stat: fs.stat,
@@ -5658,7 +8473,7 @@ var fs$2 = {};
5658
8473
  } (fs$2));
5659
8474
 
5660
8475
  Object.defineProperty(settings$2, "__esModule", { value: true });
5661
- const path$4 = require$$0__default["default"];
8476
+ const path$4 = require$$0__default$2["default"];
5662
8477
  const fsStat$3 = out$1;
5663
8478
  const fs$1 = fs$2;
5664
8479
  class Settings$1 {
@@ -6077,7 +8892,7 @@ class Reader$1 {
6077
8892
  reader$1.default = Reader$1;
6078
8893
 
6079
8894
  Object.defineProperty(async$4, "__esModule", { value: true });
6080
- const events_1 = require$$0__default$4["default"];
8895
+ const events_1 = require$$0__default$5["default"];
6081
8896
  const fsScandir$2 = out$2;
6082
8897
  const fastq = queue.exports;
6083
8898
  const common$1 = common$3;
@@ -6206,7 +9021,7 @@ function callSuccessCallback(callback, entries) {
6206
9021
  var stream$2 = {};
6207
9022
 
6208
9023
  Object.defineProperty(stream$2, "__esModule", { value: true });
6209
- const stream_1$5 = require$$0__default$2["default"];
9024
+ const stream_1$5 = require$$0__default$3["default"];
6210
9025
  const async_1$3 = async$4;
6211
9026
  class StreamProvider {
6212
9027
  constructor(_root, _settings) {
@@ -6319,7 +9134,7 @@ sync$3.default = SyncProvider;
6319
9134
  var settings$1 = {};
6320
9135
 
6321
9136
  Object.defineProperty(settings$1, "__esModule", { value: true });
6322
- const path$3 = require$$0__default["default"];
9137
+ const path$3 = require$$0__default$2["default"];
6323
9138
  const fsScandir = out$2;
6324
9139
  class Settings {
6325
9140
  constructor(_options = {}) {
@@ -6381,7 +9196,7 @@ function getSettings(settingsOrOptions = {}) {
6381
9196
  var reader = {};
6382
9197
 
6383
9198
  Object.defineProperty(reader, "__esModule", { value: true });
6384
- const path$2 = require$$0__default["default"];
9199
+ const path$2 = require$$0__default$2["default"];
6385
9200
  const fsStat$2 = out$1;
6386
9201
  const utils$6 = utils$k;
6387
9202
  class Reader {
@@ -6416,7 +9231,7 @@ reader.default = Reader;
6416
9231
  var stream$1 = {};
6417
9232
 
6418
9233
  Object.defineProperty(stream$1, "__esModule", { value: true });
6419
- const stream_1$3 = require$$0__default$2["default"];
9234
+ const stream_1$3 = require$$0__default$3["default"];
6420
9235
  const fsStat$1 = out$1;
6421
9236
  const fsWalk$2 = out$3;
6422
9237
  const reader_1$2 = reader;
@@ -6769,7 +9584,7 @@ class EntryTransformer {
6769
9584
  entry.default = EntryTransformer;
6770
9585
 
6771
9586
  Object.defineProperty(provider, "__esModule", { value: true });
6772
- const path$1 = require$$0__default["default"];
9587
+ const path$1 = require$$0__default$2["default"];
6773
9588
  const deep_1 = deep;
6774
9589
  const entry_1 = entry$1;
6775
9590
  const error_1 = error;
@@ -6842,7 +9657,7 @@ async$7.default = ProviderAsync;
6842
9657
  var stream = {};
6843
9658
 
6844
9659
  Object.defineProperty(stream, "__esModule", { value: true });
6845
- const stream_1$1 = require$$0__default$2["default"];
9660
+ const stream_1$1 = require$$0__default$3["default"];
6846
9661
  const stream_2 = stream$1;
6847
9662
  const provider_1$1 = provider;
6848
9663
  class ProviderStream extends provider_1$1.default {
@@ -6947,8 +9762,8 @@ var settings = {};
6947
9762
  (function (exports) {
6948
9763
  Object.defineProperty(exports, "__esModule", { value: true });
6949
9764
  exports.DEFAULT_FILE_SYSTEM_ADAPTER = void 0;
6950
- const fs = require$$0__default$3["default"];
6951
- const os = require$$2__default["default"];
9765
+ const fs = require$$0__default$4["default"];
9766
+ const os = require$$0__default["default"];
6952
9767
  /**
6953
9768
  * The `os.cpus` method can return zero. We expect the number of cores to be greater than zero.
6954
9769
  * https://github.com/nodejs/node/blob/7faeddf23a98c53896f8b574a6e66589e8fb1eb8/lib/os.js#L106-L107
@@ -8255,9 +11070,9 @@ var require$$4 = {
8255
11070
  browser: browser
8256
11071
  };
8257
11072
 
8258
- const fs = require$$0__default$3["default"];
8259
- const path = require$$0__default["default"];
8260
- const os = require$$2__default["default"];
11073
+ const fs = require$$0__default$4["default"];
11074
+ const path = require$$0__default$2["default"];
11075
+ const os = require$$0__default["default"];
8261
11076
  const crypto = require$$3__default["default"];
8262
11077
  const packageJson = require$$4;
8263
11078
 
@@ -8769,6 +11584,7 @@ exports.readFileSyncIfExists = readFileSyncIfExists;
8769
11584
  exports.removeCredentialFile = removeCredentialFile;
8770
11585
  exports.shouldSkipSetupAndTeardown = shouldSkipSetupAndTeardown;
8771
11586
  exports.skipTest = skipTest;
11587
+ exports.stealthTest = stealth;
8772
11588
  exports.tableUtils = tableUtils;
8773
11589
  exports.updateCredentials = updateCredentials;
8774
11590
  exports.writeDataToFile = writeDataToFile;