@bigbinary/neeto-playwright-commons 3.3.13 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/index.d.ts +63 -80
- package/index.js +66 -1119
- package/package.json +11 -8
- package/index.cjs.js +0 -127377
- package/index.cjs.js.map +0 -1
- package/index.js.map +0 -1
package/index.js
CHANGED
|
@@ -4,16 +4,16 @@ import * as fs from 'fs';
|
|
|
4
4
|
import fs__default, { readFileSync, promises, existsSync, writeFileSync, unlinkSync, mkdirSync, rmSync, createWriteStream } from 'fs';
|
|
5
5
|
import os from 'os';
|
|
6
6
|
import * as path from 'path';
|
|
7
|
-
import path__default from 'path';
|
|
8
|
-
import test, { expect, test as test$1, chromium
|
|
7
|
+
import path__default, { dirname } from 'path';
|
|
8
|
+
import test, { expect, test as test$1, chromium, defineConfig, devices } from '@playwright/test';
|
|
9
9
|
import { getI18nInstance, initI18n } from 'playwright-i18next-fixture';
|
|
10
10
|
import { curry, isNotNil, not, isEmpty, pluck, mergeAll, isNil, mergeDeepLeft } from 'ramda';
|
|
11
11
|
import { execSync, spawn } from 'child_process';
|
|
12
|
+
import require$$2$2, { fileURLToPath } from 'url';
|
|
12
13
|
import dayjs from 'dayjs';
|
|
13
14
|
import require$$1$3 from 'events';
|
|
14
15
|
import require$$0$5 from 'assert';
|
|
15
16
|
import require$$0$4 from 'util';
|
|
16
|
-
import require$$2$2 from 'url';
|
|
17
17
|
import require$$1$2 from 'tty';
|
|
18
18
|
import require$$0$6 from 'stream';
|
|
19
19
|
import require$$0$7 from 'crypto';
|
|
@@ -25,11 +25,12 @@ import require$$1$5 from 'string_decoder';
|
|
|
25
25
|
import require$$0$b from 'node:buffer';
|
|
26
26
|
import require$$1$6 from 'node:stream';
|
|
27
27
|
import require$$1$7 from 'zlib';
|
|
28
|
+
import { addExtra } from 'playwright-extra';
|
|
28
29
|
import stealth$1 from 'puppeteer-extra-plugin-stealth';
|
|
29
30
|
import { globSync } from 'node:fs';
|
|
30
|
-
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
|
31
|
-
import timezone from 'dayjs/plugin/timezone';
|
|
32
|
-
import utc from 'dayjs/plugin/utc';
|
|
31
|
+
import customParseFormat from 'dayjs/plugin/customParseFormat.js';
|
|
32
|
+
import timezone from 'dayjs/plugin/timezone.js';
|
|
33
|
+
import utc from 'dayjs/plugin/utc.js';
|
|
33
34
|
import https from 'https';
|
|
34
35
|
import * as http from 'http';
|
|
35
36
|
|
|
@@ -1150,6 +1151,7 @@ const readFileSyncIfExists = (path = STORAGE_STATE) => {
|
|
|
1150
1151
|
return {};
|
|
1151
1152
|
}
|
|
1152
1153
|
};
|
|
1154
|
+
const getDirname = (metaUrl) => dirname(fileURLToPath(metaUrl));
|
|
1153
1155
|
const getGlobalUserState = () => readFileSyncIfExists()?.user;
|
|
1154
1156
|
const writeDataToFile = data => {
|
|
1155
1157
|
try {
|
|
@@ -1979,12 +1981,14 @@ const generateRandomFile = ({ sizeInKB, fileType, fileName = `sample.${fileType}
|
|
|
1979
1981
|
return { file, fileName };
|
|
1980
1982
|
};
|
|
1981
1983
|
|
|
1984
|
+
const __dirname$6 = getDirname(import.meta.url);
|
|
1982
1985
|
const getImagePathAndName = (localImagePath) => {
|
|
1983
|
-
const imagePath = path__default.join(__dirname, localImagePath);
|
|
1986
|
+
const imagePath = path__default.join(__dirname$6, localImagePath);
|
|
1984
1987
|
const imageName = path__default.basename(localImagePath, path__default.extname(localImagePath));
|
|
1985
1988
|
return { imagePath, imageName };
|
|
1986
1989
|
};
|
|
1987
1990
|
|
|
1991
|
+
const __dirname$5 = getDirname(import.meta.url);
|
|
1988
1992
|
class CustomCommands {
|
|
1989
1993
|
page;
|
|
1990
1994
|
t;
|
|
@@ -2157,7 +2161,7 @@ class CustomCommands {
|
|
|
2157
2161
|
await expect(this.page.getByTestId(NEETO_IMAGE_UPLOADER_SELECTORS.uploadedImage)).toHaveAttribute("src", new RegExp(imageName), { timeout: 20_000 });
|
|
2158
2162
|
};
|
|
2159
2163
|
uploadFileViaDispatch = async ({ fileNameWithType, assetsPath = "../../../e2e/assets/", dispatchEvent = "drop", droppableZone = this.page.getByTestId(COMMON_SELECTORS.fileUploadBody), }) => {
|
|
2160
|
-
const filePath = path__default.join(__dirname, `${assetsPath}/${fileNameWithType}`);
|
|
2164
|
+
const filePath = path__default.join(__dirname$5, `${assetsPath}/${fileNameWithType}`);
|
|
2161
2165
|
const buffer = readFileSync(filePath).toString("base64");
|
|
2162
2166
|
const dataTransfer = await droppableZone.evaluateHandle((_, { buffer, fileNameWithType }) => {
|
|
2163
2167
|
const dataTransfer = new DataTransfer();
|
|
@@ -4685,7 +4689,7 @@ var dbsize = {
|
|
|
4685
4689
|
keyStop: 0,
|
|
4686
4690
|
step: 0
|
|
4687
4691
|
};
|
|
4688
|
-
var debug$
|
|
4692
|
+
var debug$1 = {
|
|
4689
4693
|
arity: -2,
|
|
4690
4694
|
flags: [
|
|
4691
4695
|
"admin",
|
|
@@ -7011,7 +7015,7 @@ var require$$0$3 = {
|
|
|
7011
7015
|
config: config$1,
|
|
7012
7016
|
copy: copy,
|
|
7013
7017
|
dbsize: dbsize,
|
|
7014
|
-
debug: debug$
|
|
7018
|
+
debug: debug$1,
|
|
7015
7019
|
decr: decr,
|
|
7016
7020
|
decrby: decrby,
|
|
7017
7021
|
del: del,
|
|
@@ -8903,7 +8907,7 @@ function requireLodash () {
|
|
|
8903
8907
|
return lodash;
|
|
8904
8908
|
}
|
|
8905
8909
|
|
|
8906
|
-
var debug
|
|
8910
|
+
var debug = {};
|
|
8907
8911
|
|
|
8908
8912
|
var src$2 = {exports: {}};
|
|
8909
8913
|
|
|
@@ -10096,13 +10100,13 @@ function requireSrc$2 () {
|
|
|
10096
10100
|
var hasRequiredDebug;
|
|
10097
10101
|
|
|
10098
10102
|
function requireDebug () {
|
|
10099
|
-
if (hasRequiredDebug) return debug
|
|
10103
|
+
if (hasRequiredDebug) return debug;
|
|
10100
10104
|
hasRequiredDebug = 1;
|
|
10101
|
-
Object.defineProperty(debug
|
|
10102
|
-
debug
|
|
10105
|
+
Object.defineProperty(debug, "__esModule", { value: true });
|
|
10106
|
+
debug.genRedactedString = debug.getStringValue = debug.MAX_ARGUMENT_LENGTH = void 0;
|
|
10103
10107
|
const debug_1 = requireSrc$2();
|
|
10104
10108
|
const MAX_ARGUMENT_LENGTH = 200;
|
|
10105
|
-
debug
|
|
10109
|
+
debug.MAX_ARGUMENT_LENGTH = MAX_ARGUMENT_LENGTH;
|
|
10106
10110
|
const NAMESPACE_PREFIX = "ioredis";
|
|
10107
10111
|
/**
|
|
10108
10112
|
* helper function that tried to get a string value for
|
|
@@ -10134,7 +10138,7 @@ function requireDebug () {
|
|
|
10134
10138
|
return v;
|
|
10135
10139
|
}
|
|
10136
10140
|
}
|
|
10137
|
-
debug
|
|
10141
|
+
debug.getStringValue = getStringValue;
|
|
10138
10142
|
/**
|
|
10139
10143
|
* helper function that redacts a string representation of a "debug" arg
|
|
10140
10144
|
*/
|
|
@@ -10144,7 +10148,7 @@ function requireDebug () {
|
|
|
10144
10148
|
? str
|
|
10145
10149
|
: str.slice(0, maxLen) + ' ... <REDACTED full-length="' + length + '">';
|
|
10146
10150
|
}
|
|
10147
|
-
debug
|
|
10151
|
+
debug.genRedactedString = genRedactedString;
|
|
10148
10152
|
/**
|
|
10149
10153
|
* a wrapper for the `debug` module, used to generate
|
|
10150
10154
|
* "debug functions" that trim the values in their output
|
|
@@ -10191,8 +10195,8 @@ function requireDebug () {
|
|
|
10191
10195
|
});
|
|
10192
10196
|
return wrappedDebug;
|
|
10193
10197
|
}
|
|
10194
|
-
debug
|
|
10195
|
-
return debug
|
|
10198
|
+
debug.default = genDebugFunction;
|
|
10199
|
+
return debug;
|
|
10196
10200
|
}
|
|
10197
10201
|
|
|
10198
10202
|
var TLSProfiles = {};
|
|
@@ -77073,16 +77077,16 @@ function requireSrc () {
|
|
|
77073
77077
|
return src;
|
|
77074
77078
|
}
|
|
77075
77079
|
|
|
77076
|
-
var srcExports
|
|
77080
|
+
var srcExports = requireSrc();
|
|
77077
77081
|
|
|
77078
77082
|
function gif() {
|
|
77079
77083
|
return {
|
|
77080
77084
|
mime: "image/gif",
|
|
77081
77085
|
encode: async (bitmap) => {
|
|
77082
|
-
const gif = new srcExports
|
|
77083
|
-
srcExports
|
|
77084
|
-
const newFrame = new srcExports
|
|
77085
|
-
const gifCodec = new srcExports
|
|
77086
|
+
const gif = new srcExports.BitmapImage(bitmap);
|
|
77087
|
+
srcExports.GifUtil.quantizeDekker(gif, 256);
|
|
77088
|
+
const newFrame = new srcExports.GifFrame(bitmap);
|
|
77089
|
+
const gifCodec = new srcExports.GifCodec();
|
|
77086
77090
|
const newGif = await gifCodec.encodeGif([newFrame], {});
|
|
77087
77091
|
return newGif.buffer;
|
|
77088
77092
|
},
|
|
@@ -116569,904 +116573,11 @@ const commands = {
|
|
|
116569
116573
|
},
|
|
116570
116574
|
};
|
|
116571
116575
|
|
|
116572
|
-
var srcExports = requireSrc$2();
|
|
116573
|
-
var Debug = /*@__PURE__*/getDefaultExportFromCjs(srcExports);
|
|
116574
|
-
|
|
116575
|
-
/*!
|
|
116576
|
-
* playwright-extra v4.3.5 by berstend
|
|
116577
|
-
* https://github.com/berstend/puppeteer-extra/tree/master/packages/playwright-extra#readme
|
|
116578
|
-
* @license MIT
|
|
116579
|
-
*/
|
|
116580
|
-
|
|
116581
|
-
/** Node.js module loader helper */
|
|
116582
|
-
class Loader {
|
|
116583
|
-
constructor(moduleName, packageNames) {
|
|
116584
|
-
this.moduleName = moduleName;
|
|
116585
|
-
this.packageNames = packageNames;
|
|
116586
|
-
}
|
|
116587
|
-
/**
|
|
116588
|
-
* Lazy load a top level export from another module by wrapping it in a JS proxy.
|
|
116589
|
-
*
|
|
116590
|
-
* This allows us to re-export e.g. `devices` from `playwright` while redirecting direct calls
|
|
116591
|
-
* to it to the module version the user has installed, rather than shipping with a hardcoded version.
|
|
116592
|
-
*
|
|
116593
|
-
* 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.
|
|
116594
|
-
*
|
|
116595
|
-
* We use a "super" Proxy defining all traps, so calls like `Object.keys(playwright.devices).length` will return the correct value.
|
|
116596
|
-
*/
|
|
116597
|
-
lazyloadExportOrDie(exportName) {
|
|
116598
|
-
const that = this;
|
|
116599
|
-
const trapHandler = Object.fromEntries(Object.getOwnPropertyNames(Reflect).map((name) => [
|
|
116600
|
-
name,
|
|
116601
|
-
function (target, ...args) {
|
|
116602
|
-
const moduleExport = that.loadModuleOrDie()[exportName];
|
|
116603
|
-
const customTarget = moduleExport;
|
|
116604
|
-
const result = Reflect[name](customTarget || target, ...args);
|
|
116605
|
-
return result;
|
|
116606
|
-
}
|
|
116607
|
-
]));
|
|
116608
|
-
return new Proxy({}, trapHandler);
|
|
116609
|
-
}
|
|
116610
|
-
/** Load the module if possible */
|
|
116611
|
-
loadModule() {
|
|
116612
|
-
return requirePackages(this.packageNames);
|
|
116613
|
-
}
|
|
116614
|
-
/** Load the module if possible or throw */
|
|
116615
|
-
loadModuleOrDie() {
|
|
116616
|
-
const module = requirePackages(this.packageNames);
|
|
116617
|
-
if (module) {
|
|
116618
|
-
return module;
|
|
116619
|
-
}
|
|
116620
|
-
throw this.requireError;
|
|
116621
|
-
}
|
|
116622
|
-
get requireError() {
|
|
116623
|
-
const moduleNamePretty = this.moduleName.charAt(0).toUpperCase() + this.moduleName.slice(1);
|
|
116624
|
-
return new Error(`
|
|
116625
|
-
${moduleNamePretty} is missing. :-)
|
|
116626
|
-
|
|
116627
|
-
I've tried loading ${this.packageNames
|
|
116628
|
-
.map(p => `"${p}"`)
|
|
116629
|
-
.join(', ')} - no luck.
|
|
116630
|
-
|
|
116631
|
-
Make sure you install one of those packages or use the named 'addExtra' export,
|
|
116632
|
-
to patch a specific (and maybe non-standard) implementation of ${moduleNamePretty}.
|
|
116633
|
-
|
|
116634
|
-
To get the latest stable version of ${moduleNamePretty} run:
|
|
116635
|
-
'yarn add ${this.moduleName}' or 'npm i ${this.moduleName}'
|
|
116636
|
-
`);
|
|
116637
|
-
}
|
|
116638
|
-
}
|
|
116639
|
-
function requirePackages(packageNames) {
|
|
116640
|
-
for (const name of packageNames) {
|
|
116641
|
-
try {
|
|
116642
|
-
return require(name);
|
|
116643
|
-
}
|
|
116644
|
-
catch (_) {
|
|
116645
|
-
continue; // noop
|
|
116646
|
-
}
|
|
116647
|
-
}
|
|
116648
|
-
return;
|
|
116649
|
-
}
|
|
116650
|
-
/** Playwright specific module loader */
|
|
116651
|
-
const playwrightLoader = new Loader('playwright', [
|
|
116652
|
-
'playwright-core',
|
|
116653
|
-
'playwright'
|
|
116654
|
-
]);
|
|
116655
|
-
|
|
116656
|
-
const debug = Debug('playwright-extra:puppeteer-compat');
|
|
116657
|
-
const isPlaywrightPage = (obj) => {
|
|
116658
|
-
return 'unroute' in obj;
|
|
116659
|
-
};
|
|
116660
|
-
const isPlaywrightFrame = (obj) => {
|
|
116661
|
-
return ['parentFrame', 'frameLocator'].every(x => x in obj);
|
|
116662
|
-
};
|
|
116663
|
-
const isPlaywrightBrowser = (obj) => {
|
|
116664
|
-
return 'newContext' in obj;
|
|
116665
|
-
};
|
|
116666
|
-
const isPuppeteerCompat = (obj) => {
|
|
116667
|
-
return !!obj && typeof obj === 'object' && !!obj.isCompatShim;
|
|
116668
|
-
};
|
|
116669
|
-
const cache = {
|
|
116670
|
-
objectToShim: new Map(),
|
|
116671
|
-
cdpSession: {
|
|
116672
|
-
page: new Map(),
|
|
116673
|
-
browser: new Map()
|
|
116674
|
-
}
|
|
116675
|
-
};
|
|
116676
|
-
/** Augment a Playwright object with compatibility with certain Puppeteer methods */
|
|
116677
|
-
function addPuppeteerCompat(object) {
|
|
116678
|
-
if (!object || typeof object !== 'object') {
|
|
116679
|
-
return object;
|
|
116680
|
-
}
|
|
116681
|
-
if (cache.objectToShim.has(object)) {
|
|
116682
|
-
return cache.objectToShim.get(object);
|
|
116683
|
-
}
|
|
116684
|
-
if (isPuppeteerCompat(object)) {
|
|
116685
|
-
return object;
|
|
116686
|
-
}
|
|
116687
|
-
debug('addPuppeteerCompat', cache.objectToShim.size);
|
|
116688
|
-
if (isPlaywrightPage(object) || isPlaywrightFrame(object)) {
|
|
116689
|
-
const shim = createPageShim(object);
|
|
116690
|
-
cache.objectToShim.set(object, shim);
|
|
116691
|
-
return shim;
|
|
116692
|
-
}
|
|
116693
|
-
if (isPlaywrightBrowser(object)) {
|
|
116694
|
-
const shim = createBrowserShim(object);
|
|
116695
|
-
cache.objectToShim.set(object, shim);
|
|
116696
|
-
return shim;
|
|
116697
|
-
}
|
|
116698
|
-
debug('Received unknown object:', Reflect.ownKeys(object));
|
|
116699
|
-
return object;
|
|
116700
|
-
}
|
|
116701
|
-
// Only chromium browsers support CDP
|
|
116702
|
-
const dummyCDPClient = {
|
|
116703
|
-
send: async (...args) => {
|
|
116704
|
-
debug('dummy CDP client called', 'send', args);
|
|
116705
|
-
},
|
|
116706
|
-
on: (...args) => {
|
|
116707
|
-
debug('dummy CDP client called', 'on', args);
|
|
116708
|
-
}
|
|
116709
|
-
};
|
|
116710
|
-
async function getPageCDPSession(page) {
|
|
116711
|
-
let session = cache.cdpSession.page.get(page);
|
|
116712
|
-
if (session) {
|
|
116713
|
-
debug('getPageCDPSession: use existing');
|
|
116714
|
-
return session;
|
|
116715
|
-
}
|
|
116716
|
-
debug('getPageCDPSession: use new');
|
|
116717
|
-
const context = isPlaywrightFrame(page)
|
|
116718
|
-
? page.page().context()
|
|
116719
|
-
: page.context();
|
|
116720
|
-
try {
|
|
116721
|
-
session = await context.newCDPSession(page);
|
|
116722
|
-
cache.cdpSession.page.set(page, session);
|
|
116723
|
-
return session;
|
|
116724
|
-
}
|
|
116725
|
-
catch (err) {
|
|
116726
|
-
debug('getPageCDPSession: error while creating session:', err.message);
|
|
116727
|
-
debug('getPageCDPSession: Unable create CDP session (most likely a different browser than chromium) - returning a dummy');
|
|
116728
|
-
}
|
|
116729
|
-
return dummyCDPClient;
|
|
116730
|
-
}
|
|
116731
|
-
async function getBrowserCDPSession(browser) {
|
|
116732
|
-
let session = cache.cdpSession.browser.get(browser);
|
|
116733
|
-
if (session) {
|
|
116734
|
-
debug('getBrowserCDPSession: use existing');
|
|
116735
|
-
return session;
|
|
116736
|
-
}
|
|
116737
|
-
debug('getBrowserCDPSession: use new');
|
|
116738
|
-
try {
|
|
116739
|
-
session = await browser.newBrowserCDPSession();
|
|
116740
|
-
cache.cdpSession.browser.set(browser, session);
|
|
116741
|
-
return session;
|
|
116742
|
-
}
|
|
116743
|
-
catch (err) {
|
|
116744
|
-
debug('getBrowserCDPSession: error while creating session:', err.message);
|
|
116745
|
-
debug('getBrowserCDPSession: Unable create CDP session (most likely a different browser than chromium) - returning a dummy');
|
|
116746
|
-
}
|
|
116747
|
-
return dummyCDPClient;
|
|
116748
|
-
}
|
|
116749
|
-
function createPageShim(page) {
|
|
116750
|
-
const objId = Math.random().toString(36).substring(2, 7);
|
|
116751
|
-
const shim = new Proxy(page, {
|
|
116752
|
-
get(target, prop) {
|
|
116753
|
-
if (prop === 'isCompatShim' || prop === 'isPlaywright') {
|
|
116754
|
-
return true;
|
|
116755
|
-
}
|
|
116756
|
-
debug('page - get', objId, prop);
|
|
116757
|
-
if (prop === '_client') {
|
|
116758
|
-
return () => ({
|
|
116759
|
-
send: async (method, params) => {
|
|
116760
|
-
const session = await getPageCDPSession(page);
|
|
116761
|
-
return await session.send(method, params);
|
|
116762
|
-
},
|
|
116763
|
-
on: (event, listener) => {
|
|
116764
|
-
getPageCDPSession(page).then(session => {
|
|
116765
|
-
session.on(event, listener);
|
|
116766
|
-
});
|
|
116767
|
-
}
|
|
116768
|
-
});
|
|
116769
|
-
}
|
|
116770
|
-
if (prop === 'setBypassCSP') {
|
|
116771
|
-
return async (enabled) => {
|
|
116772
|
-
const session = await getPageCDPSession(page);
|
|
116773
|
-
return await session.send('Page.setBypassCSP', {
|
|
116774
|
-
enabled
|
|
116775
|
-
});
|
|
116776
|
-
};
|
|
116777
|
-
}
|
|
116778
|
-
if (prop === 'setUserAgent') {
|
|
116779
|
-
return async (userAgent, userAgentMetadata) => {
|
|
116780
|
-
const session = await getPageCDPSession(page);
|
|
116781
|
-
return await session.send('Emulation.setUserAgentOverride', {
|
|
116782
|
-
userAgent,
|
|
116783
|
-
userAgentMetadata
|
|
116784
|
-
});
|
|
116785
|
-
};
|
|
116786
|
-
}
|
|
116787
|
-
if (prop === 'browser') {
|
|
116788
|
-
if (isPlaywrightPage(page)) {
|
|
116789
|
-
return () => {
|
|
116790
|
-
let browser = page.context().browser();
|
|
116791
|
-
if (!browser) {
|
|
116792
|
-
debug('page.browser() - not available, most likely due to launchPersistentContext');
|
|
116793
|
-
// Use a page shim as quick drop-in (so browser.userAgent() still works)
|
|
116794
|
-
browser = page;
|
|
116795
|
-
}
|
|
116796
|
-
return addPuppeteerCompat(browser);
|
|
116797
|
-
};
|
|
116798
|
-
}
|
|
116799
|
-
}
|
|
116800
|
-
if (prop === 'evaluateOnNewDocument') {
|
|
116801
|
-
if (isPlaywrightPage(page)) {
|
|
116802
|
-
return async function (pageFunction, ...args) {
|
|
116803
|
-
return await page.addInitScript(pageFunction, args[0]);
|
|
116804
|
-
};
|
|
116805
|
-
}
|
|
116806
|
-
}
|
|
116807
|
-
// Only relevant when page is being used a pseudo stand-in for the browser object (launchPersistentContext)
|
|
116808
|
-
if (prop === 'userAgent') {
|
|
116809
|
-
return async (enabled) => {
|
|
116810
|
-
const session = await getPageCDPSession(page);
|
|
116811
|
-
const data = await session.send('Browser.getVersion');
|
|
116812
|
-
return data.userAgent;
|
|
116813
|
-
};
|
|
116814
|
-
}
|
|
116815
|
-
return Reflect.get(target, prop);
|
|
116816
|
-
}
|
|
116817
|
-
});
|
|
116818
|
-
return shim;
|
|
116819
|
-
}
|
|
116820
|
-
function createBrowserShim(browser) {
|
|
116821
|
-
const objId = Math.random().toString(36).substring(2, 7);
|
|
116822
|
-
const shim = new Proxy(browser, {
|
|
116823
|
-
get(target, prop) {
|
|
116824
|
-
if (prop === 'isCompatShim' || prop === 'isPlaywright') {
|
|
116825
|
-
return true;
|
|
116826
|
-
}
|
|
116827
|
-
debug('browser - get', objId, prop);
|
|
116828
|
-
if (prop === 'pages') {
|
|
116829
|
-
return () => browser
|
|
116830
|
-
.contexts()
|
|
116831
|
-
.flatMap(c => c.pages().map(page => addPuppeteerCompat(page)));
|
|
116832
|
-
}
|
|
116833
|
-
if (prop === 'userAgent') {
|
|
116834
|
-
return async () => {
|
|
116835
|
-
const session = await getBrowserCDPSession(browser);
|
|
116836
|
-
const data = await session.send('Browser.getVersion');
|
|
116837
|
-
return data.userAgent;
|
|
116838
|
-
};
|
|
116839
|
-
}
|
|
116840
|
-
return Reflect.get(target, prop);
|
|
116841
|
-
}
|
|
116842
|
-
});
|
|
116843
|
-
return shim;
|
|
116844
|
-
}
|
|
116845
|
-
|
|
116846
|
-
const debug$1 = Debug('playwright-extra:plugins');
|
|
116847
|
-
class PluginList {
|
|
116848
|
-
constructor() {
|
|
116849
|
-
this._plugins = [];
|
|
116850
|
-
this._dependencyDefaults = new Map();
|
|
116851
|
-
this._dependencyResolution = new Map();
|
|
116852
|
-
}
|
|
116853
|
-
/**
|
|
116854
|
-
* Get a list of all registered plugins.
|
|
116855
|
-
*/
|
|
116856
|
-
get list() {
|
|
116857
|
-
return this._plugins;
|
|
116858
|
-
}
|
|
116859
|
-
/**
|
|
116860
|
-
* Get the names of all registered plugins.
|
|
116861
|
-
*/
|
|
116862
|
-
get names() {
|
|
116863
|
-
return this._plugins.map(p => p.name);
|
|
116864
|
-
}
|
|
116865
|
-
/**
|
|
116866
|
-
* Add a new plugin to the list (after checking if it's well-formed).
|
|
116867
|
-
*
|
|
116868
|
-
* @param plugin
|
|
116869
|
-
* @internal
|
|
116870
|
-
*/
|
|
116871
|
-
add(plugin) {
|
|
116872
|
-
var _a;
|
|
116873
|
-
if (!this.isValidPluginInstance(plugin)) {
|
|
116874
|
-
return false;
|
|
116875
|
-
}
|
|
116876
|
-
if (!!plugin.onPluginRegistered) {
|
|
116877
|
-
plugin.onPluginRegistered({ framework: 'playwright' });
|
|
116878
|
-
}
|
|
116879
|
-
// PuppeteerExtraPlugin: Populate `_childClassMembers` list containing methods defined by the plugin
|
|
116880
|
-
if (!!plugin._registerChildClassMembers) {
|
|
116881
|
-
plugin._registerChildClassMembers(Object.getPrototypeOf(plugin));
|
|
116882
|
-
}
|
|
116883
|
-
if ((_a = plugin.requirements) === null || _a === void 0 ? void 0 : _a.has('dataFromPlugins')) {
|
|
116884
|
-
plugin.getDataFromPlugins = this.getData.bind(this);
|
|
116885
|
-
}
|
|
116886
|
-
this._plugins.push(plugin);
|
|
116887
|
-
return true;
|
|
116888
|
-
}
|
|
116889
|
-
/** Check if the shape of a plugin is correct or warn */
|
|
116890
|
-
isValidPluginInstance(plugin) {
|
|
116891
|
-
if (!plugin ||
|
|
116892
|
-
typeof plugin !== 'object' ||
|
|
116893
|
-
!plugin._isPuppeteerExtraPlugin) {
|
|
116894
|
-
console.error(`Warning: Plugin is not derived from PuppeteerExtraPlugin, ignoring.`, plugin);
|
|
116895
|
-
return false;
|
|
116896
|
-
}
|
|
116897
|
-
if (!plugin.name) {
|
|
116898
|
-
console.error(`Warning: Plugin with no name registering, ignoring.`, plugin);
|
|
116899
|
-
return false;
|
|
116900
|
-
}
|
|
116901
|
-
return true;
|
|
116902
|
-
}
|
|
116903
|
-
/** Error callback in case calling a plugin method throws an error. Can be overwritten. */
|
|
116904
|
-
onPluginError(plugin, method, err) {
|
|
116905
|
-
console.warn(`An error occured while executing "${method}" in plugin "${plugin.name}":`, err);
|
|
116906
|
-
}
|
|
116907
|
-
/**
|
|
116908
|
-
* Define default values for plugins implicitly required through the `dependencies` plugin stanza.
|
|
116909
|
-
*
|
|
116910
|
-
* @param dependencyPath - The string by which the dependency is listed (not the plugin name)
|
|
116911
|
-
*
|
|
116912
|
-
* @example
|
|
116913
|
-
* chromium.use(stealth)
|
|
116914
|
-
* chromium.plugins.setDependencyDefaults('stealth/evasions/webgl.vendor', { vendor: 'Bob', renderer: 'Alice' })
|
|
116915
|
-
*/
|
|
116916
|
-
setDependencyDefaults(dependencyPath, opts) {
|
|
116917
|
-
this._dependencyDefaults.set(dependencyPath, opts);
|
|
116918
|
-
return this;
|
|
116919
|
-
}
|
|
116920
|
-
/**
|
|
116921
|
-
* Define custom plugin modules for plugins implicitly required through the `dependencies` plugin stanza.
|
|
116922
|
-
*
|
|
116923
|
-
* Using this will prevent dynamic imports from being used, which JS bundlers often have issues with.
|
|
116924
|
-
*
|
|
116925
|
-
* @example
|
|
116926
|
-
* chromium.use(stealth)
|
|
116927
|
-
* chromium.plugins.setDependencyResolution('stealth/evasions/webgl.vendor', VendorPlugin)
|
|
116928
|
-
*/
|
|
116929
|
-
setDependencyResolution(dependencyPath, pluginModule) {
|
|
116930
|
-
this._dependencyResolution.set(dependencyPath, pluginModule);
|
|
116931
|
-
return this;
|
|
116932
|
-
}
|
|
116933
|
-
/**
|
|
116934
|
-
* Prepare plugins to be used (resolve dependencies, ordering)
|
|
116935
|
-
* @internal
|
|
116936
|
-
*/
|
|
116937
|
-
prepare() {
|
|
116938
|
-
this.resolveDependencies();
|
|
116939
|
-
this.order();
|
|
116940
|
-
}
|
|
116941
|
-
/** Return all plugins using the supplied method */
|
|
116942
|
-
filterByMethod(methodName) {
|
|
116943
|
-
return this._plugins.filter(plugin => {
|
|
116944
|
-
// PuppeteerExtraPlugin: The base class will already define all methods, hence we need to do a different check
|
|
116945
|
-
if (!!plugin._childClassMembers &&
|
|
116946
|
-
Array.isArray(plugin._childClassMembers)) {
|
|
116947
|
-
return plugin._childClassMembers.includes(methodName);
|
|
116948
|
-
}
|
|
116949
|
-
return methodName in plugin;
|
|
116950
|
-
});
|
|
116951
|
-
}
|
|
116952
|
-
/** Conditionally add puppeteer compatibility to values provided to the plugins */
|
|
116953
|
-
_addPuppeteerCompatIfNeeded(plugin, method, args) {
|
|
116954
|
-
const canUseShim = plugin._isPuppeteerExtraPlugin && !plugin.noPuppeteerShim;
|
|
116955
|
-
const methodWhitelist = [
|
|
116956
|
-
'onBrowser',
|
|
116957
|
-
'onPageCreated',
|
|
116958
|
-
'onPageClose',
|
|
116959
|
-
'afterConnect',
|
|
116960
|
-
'afterLaunch'
|
|
116961
|
-
];
|
|
116962
|
-
const shouldUseShim = methodWhitelist.includes(method);
|
|
116963
|
-
if (!canUseShim || !shouldUseShim) {
|
|
116964
|
-
return args;
|
|
116965
|
-
}
|
|
116966
|
-
debug$1('add puppeteer compatibility', plugin.name, method);
|
|
116967
|
-
return [...args.map(arg => addPuppeteerCompat(arg))];
|
|
116968
|
-
}
|
|
116969
|
-
/**
|
|
116970
|
-
* Dispatch plugin lifecycle events in a typesafe way.
|
|
116971
|
-
* Only Plugins that expose the supplied property will be called.
|
|
116972
|
-
*
|
|
116973
|
-
* Will not await results to dispatch events as fast as possible to all plugins.
|
|
116974
|
-
*
|
|
116975
|
-
* @param method - The lifecycle method name
|
|
116976
|
-
* @param args - Optional: Any arguments to be supplied to the plugin methods
|
|
116977
|
-
* @internal
|
|
116978
|
-
*/
|
|
116979
|
-
dispatch(method, ...args) {
|
|
116980
|
-
var _a, _b;
|
|
116981
|
-
const plugins = this.filterByMethod(method);
|
|
116982
|
-
debug$1('dispatch', method, {
|
|
116983
|
-
all: this._plugins.length,
|
|
116984
|
-
filteredByMethod: plugins.length
|
|
116985
|
-
});
|
|
116986
|
-
for (const plugin of plugins) {
|
|
116987
|
-
try {
|
|
116988
|
-
args = this._addPuppeteerCompatIfNeeded.bind(this)(plugin, method, args);
|
|
116989
|
-
const fnType = (_b = (_a = plugin[method]) === null || _a === void 0 ? void 0 : _a.constructor) === null || _b === void 0 ? void 0 : _b.name;
|
|
116990
|
-
debug$1('dispatch to plugin', {
|
|
116991
|
-
plugin: plugin.name,
|
|
116992
|
-
method,
|
|
116993
|
-
fnType
|
|
116994
|
-
});
|
|
116995
|
-
if (fnType === 'AsyncFunction') {
|
|
116996
|
-
;
|
|
116997
|
-
plugin[method](...args).catch((err) => this.onPluginError(plugin, method, err));
|
|
116998
|
-
}
|
|
116999
|
-
else {
|
|
117000
|
-
;
|
|
117001
|
-
plugin[method](...args);
|
|
117002
|
-
}
|
|
117003
|
-
}
|
|
117004
|
-
catch (err) {
|
|
117005
|
-
this.onPluginError(plugin, method, err);
|
|
117006
|
-
}
|
|
117007
|
-
}
|
|
117008
|
-
}
|
|
117009
|
-
/**
|
|
117010
|
-
* Dispatch plugin lifecycle events in a typesafe way.
|
|
117011
|
-
* Only Plugins that expose the supplied property will be called.
|
|
117012
|
-
*
|
|
117013
|
-
* Can also be used to get a definite return value after passing it to plugins:
|
|
117014
|
-
* Calls plugins sequentially and passes on a value (waterfall style).
|
|
117015
|
-
*
|
|
117016
|
-
* The plugins can either modify the value or return an updated one.
|
|
117017
|
-
* Will return the latest, updated value which ran through all plugins.
|
|
117018
|
-
*
|
|
117019
|
-
* By convention only the first argument will be used as the updated value.
|
|
117020
|
-
*
|
|
117021
|
-
* @param method - The lifecycle method name
|
|
117022
|
-
* @param args - Optional: Any arguments to be supplied to the plugin methods
|
|
117023
|
-
* @internal
|
|
117024
|
-
*/
|
|
117025
|
-
async dispatchBlocking(method, ...args) {
|
|
117026
|
-
const plugins = this.filterByMethod(method);
|
|
117027
|
-
debug$1('dispatchBlocking', method, {
|
|
117028
|
-
all: this._plugins.length,
|
|
117029
|
-
filteredByMethod: plugins.length
|
|
117030
|
-
});
|
|
117031
|
-
let retValue = null;
|
|
117032
|
-
for (const plugin of plugins) {
|
|
117033
|
-
try {
|
|
117034
|
-
args = this._addPuppeteerCompatIfNeeded.bind(this)(plugin, method, args);
|
|
117035
|
-
retValue = await plugin[method](...args);
|
|
117036
|
-
// In case we got a return value use that as new first argument for followup function calls
|
|
117037
|
-
if (retValue !== undefined) {
|
|
117038
|
-
args[0] = retValue;
|
|
117039
|
-
}
|
|
117040
|
-
}
|
|
117041
|
-
catch (err) {
|
|
117042
|
-
this.onPluginError(plugin, method, err);
|
|
117043
|
-
return retValue;
|
|
117044
|
-
}
|
|
117045
|
-
}
|
|
117046
|
-
return retValue;
|
|
117047
|
-
}
|
|
117048
|
-
/**
|
|
117049
|
-
* Order plugins that have expressed a special placement requirement.
|
|
117050
|
-
*
|
|
117051
|
-
* This is useful/necessary for e.g. plugins that depend on the data from other plugins.
|
|
117052
|
-
*
|
|
117053
|
-
* @private
|
|
117054
|
-
*/
|
|
117055
|
-
order() {
|
|
117056
|
-
debug$1('order:before', this.names);
|
|
117057
|
-
const runLast = this._plugins
|
|
117058
|
-
.filter(p => { var _a; return (_a = p.requirements) === null || _a === void 0 ? void 0 : _a.has('runLast'); })
|
|
117059
|
-
.map(p => p.name);
|
|
117060
|
-
for (const name of runLast) {
|
|
117061
|
-
const index = this._plugins.findIndex(p => p.name === name);
|
|
117062
|
-
this._plugins.push(this._plugins.splice(index, 1)[0]);
|
|
117063
|
-
}
|
|
117064
|
-
debug$1('order:after', this.names);
|
|
117065
|
-
}
|
|
117066
|
-
/**
|
|
117067
|
-
* Collects the exposed `data` property of all registered plugins.
|
|
117068
|
-
* Will be reduced/flattened to a single array.
|
|
117069
|
-
*
|
|
117070
|
-
* Can be accessed by plugins that listed the `dataFromPlugins` requirement.
|
|
117071
|
-
*
|
|
117072
|
-
* Implemented mainly for plugins that need data from other plugins (e.g. `user-preferences`).
|
|
117073
|
-
*
|
|
117074
|
-
* @see [PuppeteerExtraPlugin]/data
|
|
117075
|
-
* @param name - Filter data by optional name
|
|
117076
|
-
*
|
|
117077
|
-
* @private
|
|
117078
|
-
*/
|
|
117079
|
-
getData(name) {
|
|
117080
|
-
const data = this._plugins
|
|
117081
|
-
.filter((p) => !!p.data)
|
|
117082
|
-
.map((p) => (Array.isArray(p.data) ? p.data : [p.data]))
|
|
117083
|
-
.reduce((acc, arr) => [...acc, ...arr], []);
|
|
117084
|
-
return name ? data.filter((d) => d.name === name) : data;
|
|
117085
|
-
}
|
|
117086
|
-
/**
|
|
117087
|
-
* Handle `plugins` stanza (already instantiated plugins that don't require dynamic imports)
|
|
117088
|
-
*/
|
|
117089
|
-
resolvePluginsStanza() {
|
|
117090
|
-
debug$1('resolvePluginsStanza');
|
|
117091
|
-
const pluginNames = new Set(this.names);
|
|
117092
|
-
this._plugins
|
|
117093
|
-
.filter(p => !!p.plugins && p.plugins.length)
|
|
117094
|
-
.filter(p => !pluginNames.has(p.name)) // TBD: Do we want to filter out existing?
|
|
117095
|
-
.forEach(parent => {
|
|
117096
|
-
(parent.plugins || []).forEach(p => {
|
|
117097
|
-
debug$1(parent.name, 'adding missing plugin', p.name);
|
|
117098
|
-
this.add(p);
|
|
117099
|
-
});
|
|
117100
|
-
});
|
|
117101
|
-
}
|
|
117102
|
-
/**
|
|
117103
|
-
* Handle `dependencies` stanza (which requires dynamic imports)
|
|
117104
|
-
*
|
|
117105
|
-
* Plugins can define `dependencies` as a Set or Array of dependency paths, or a Map with additional opts
|
|
117106
|
-
*
|
|
117107
|
-
* @note
|
|
117108
|
-
* - The default opts for implicit dependencies can be defined using `setDependencyDefaults()`
|
|
117109
|
-
* - Dynamic imports can be avoided by providing plugin modules with `setDependencyResolution()`
|
|
117110
|
-
*/
|
|
117111
|
-
resolveDependenciesStanza() {
|
|
117112
|
-
debug$1('resolveDependenciesStanza');
|
|
117113
|
-
/** Attempt to dynamically require a plugin module */
|
|
117114
|
-
const requireDependencyOrDie = (parentName, dependencyPath) => {
|
|
117115
|
-
// If the user provided the plugin module already we use that
|
|
117116
|
-
if (this._dependencyResolution.has(dependencyPath)) {
|
|
117117
|
-
return this._dependencyResolution.get(dependencyPath);
|
|
117118
|
-
}
|
|
117119
|
-
const possiblePrefixes = ['puppeteer-extra-plugin-']; // could be extended later
|
|
117120
|
-
const isAlreadyPrefixed = possiblePrefixes.some(prefix => dependencyPath.startsWith(prefix));
|
|
117121
|
-
const packagePaths = [];
|
|
117122
|
-
// If the dependency is not already prefixed we attempt to require all possible combinations to find one that works
|
|
117123
|
-
if (!isAlreadyPrefixed) {
|
|
117124
|
-
packagePaths.push(...possiblePrefixes.map(prefix => prefix + dependencyPath));
|
|
117125
|
-
}
|
|
117126
|
-
// We always attempt to require the path verbatim (as a last resort)
|
|
117127
|
-
packagePaths.push(dependencyPath);
|
|
117128
|
-
const pluginModule = requirePackages(packagePaths);
|
|
117129
|
-
if (pluginModule) {
|
|
117130
|
-
return pluginModule;
|
|
117131
|
-
}
|
|
117132
|
-
const explanation = `
|
|
117133
|
-
The plugin '${parentName}' listed '${dependencyPath}' as dependency,
|
|
117134
|
-
which could not be found. Please install it:
|
|
117135
|
-
|
|
117136
|
-
${packagePaths
|
|
117137
|
-
.map(packagePath => `yarn add ${packagePath.split('/')[0]}`)
|
|
117138
|
-
.join(`\n or:\n`)}
|
|
117139
|
-
|
|
117140
|
-
Note: You don't need to require the plugin yourself,
|
|
117141
|
-
unless you want to modify it's default settings.
|
|
117142
|
-
|
|
117143
|
-
If your bundler has issues with dynamic imports take a look at '.plugins.setDependencyResolution()'.
|
|
117144
|
-
`;
|
|
117145
|
-
console.warn(explanation);
|
|
117146
|
-
throw new Error('Plugin dependency not found');
|
|
117147
|
-
};
|
|
117148
|
-
const existingPluginNames = new Set(this.names);
|
|
117149
|
-
const recursivelyLoadMissingDependencies = ({ name: parentName, dependencies }) => {
|
|
117150
|
-
if (!dependencies) {
|
|
117151
|
-
return;
|
|
117152
|
-
}
|
|
117153
|
-
const processDependency = (dependencyPath, opts) => {
|
|
117154
|
-
const pluginModule = requireDependencyOrDie(parentName, dependencyPath);
|
|
117155
|
-
opts = opts || this._dependencyDefaults.get(dependencyPath) || {};
|
|
117156
|
-
const plugin = pluginModule(opts);
|
|
117157
|
-
if (existingPluginNames.has(plugin.name)) {
|
|
117158
|
-
debug$1(parentName, '=> dependency already exists:', plugin.name);
|
|
117159
|
-
return;
|
|
117160
|
-
}
|
|
117161
|
-
existingPluginNames.add(plugin.name);
|
|
117162
|
-
debug$1(parentName, '=> adding new dependency:', plugin.name, opts);
|
|
117163
|
-
this.add(plugin);
|
|
117164
|
-
return recursivelyLoadMissingDependencies(plugin);
|
|
117165
|
-
};
|
|
117166
|
-
if (dependencies instanceof Set || Array.isArray(dependencies)) {
|
|
117167
|
-
return [...dependencies].forEach(dependencyPath => processDependency(dependencyPath));
|
|
117168
|
-
}
|
|
117169
|
-
if (dependencies instanceof Map) {
|
|
117170
|
-
// Note: `k,v => v,k` (Map + forEach will reverse the order)
|
|
117171
|
-
return dependencies.forEach((v, k) => processDependency(k, v));
|
|
117172
|
-
}
|
|
117173
|
-
};
|
|
117174
|
-
this.list.forEach(recursivelyLoadMissingDependencies);
|
|
117175
|
-
}
|
|
117176
|
-
/**
|
|
117177
|
-
* Lightweight plugin dependency management to require plugins and code mods on demand.
|
|
117178
|
-
* @private
|
|
117179
|
-
*/
|
|
117180
|
-
resolveDependencies() {
|
|
117181
|
-
debug$1('resolveDependencies');
|
|
117182
|
-
this.resolvePluginsStanza();
|
|
117183
|
-
this.resolveDependenciesStanza();
|
|
117184
|
-
}
|
|
117185
|
-
}
|
|
117186
|
-
|
|
117187
|
-
const debug$2 = Debug('playwright-extra');
|
|
117188
|
-
/**
|
|
117189
|
-
* Modular plugin framework to teach `playwright` new tricks.
|
|
117190
|
-
*/
|
|
117191
|
-
class PlaywrightExtraClass {
|
|
117192
|
-
constructor(_launcher) {
|
|
117193
|
-
this._launcher = _launcher;
|
|
117194
|
-
this.plugins = new PluginList();
|
|
117195
|
-
}
|
|
117196
|
-
/**
|
|
117197
|
-
* The **main interface** to register plugins.
|
|
117198
|
-
*
|
|
117199
|
-
* Can be called multiple times to enable multiple plugins.
|
|
117200
|
-
*
|
|
117201
|
-
* Plugins derived from `PuppeteerExtraPlugin` will be used with a compatiblity layer.
|
|
117202
|
-
*
|
|
117203
|
-
* @example
|
|
117204
|
-
* chromium.use(plugin1).use(plugin2)
|
|
117205
|
-
* firefox.use(plugin1).use(plugin2)
|
|
117206
|
-
*
|
|
117207
|
-
* @see [PuppeteerExtraPlugin]
|
|
117208
|
-
*
|
|
117209
|
-
* @return The same `PlaywrightExtra` instance (for optional chaining)
|
|
117210
|
-
*/
|
|
117211
|
-
use(plugin) {
|
|
117212
|
-
const isValid = plugin && 'name' in plugin;
|
|
117213
|
-
if (!isValid) {
|
|
117214
|
-
throw new Error('A plugin must be provided to .use()');
|
|
117215
|
-
}
|
|
117216
|
-
if (this.plugins.add(plugin)) {
|
|
117217
|
-
debug$2('Plugin registered', plugin.name);
|
|
117218
|
-
}
|
|
117219
|
-
return this;
|
|
117220
|
-
}
|
|
117221
|
-
/**
|
|
117222
|
-
* In order to support a default export which will require vanilla playwright automatically,
|
|
117223
|
-
* as well as `addExtra` to patch a provided launcher, we need to so some gymnastics here.
|
|
117224
|
-
*
|
|
117225
|
-
* Otherwise this would throw immediately, even when only using the `addExtra` export with an arbitrary compatible launcher.
|
|
117226
|
-
*
|
|
117227
|
-
* The solution is to make the vanilla launcher optional and only throw once we try to effectively use and can't find it.
|
|
117228
|
-
*
|
|
117229
|
-
* @internal
|
|
117230
|
-
*/
|
|
117231
|
-
get launcher() {
|
|
117232
|
-
if (!this._launcher) {
|
|
117233
|
-
throw playwrightLoader.requireError;
|
|
117234
|
-
}
|
|
117235
|
-
return this._launcher;
|
|
117236
|
-
}
|
|
117237
|
-
async launch(...args) {
|
|
117238
|
-
if (!this.launcher.launch) {
|
|
117239
|
-
throw new Error('Launcher does not support "launch"');
|
|
117240
|
-
}
|
|
117241
|
-
let [options] = args;
|
|
117242
|
-
options = Object.assign({ args: [] }, (options || {})); // Initialize args array
|
|
117243
|
-
debug$2('launch', options);
|
|
117244
|
-
this.plugins.prepare();
|
|
117245
|
-
// Give plugins the chance to modify the options before continuing
|
|
117246
|
-
options =
|
|
117247
|
-
(await this.plugins.dispatchBlocking('beforeLaunch', options)) || options;
|
|
117248
|
-
debug$2('launch with options', options);
|
|
117249
|
-
if ('userDataDir' in options) {
|
|
117250
|
-
debug$2("A plugin defined userDataDir during .launch, which isn't supported by playwright - ignoring");
|
|
117251
|
-
delete options.userDataDir;
|
|
117252
|
-
}
|
|
117253
|
-
const browser = await this.launcher['launch'](options);
|
|
117254
|
-
await this.plugins.dispatchBlocking('onBrowser', browser);
|
|
117255
|
-
await this._bindBrowserEvents(browser);
|
|
117256
|
-
await this.plugins.dispatchBlocking('afterLaunch', browser);
|
|
117257
|
-
return browser;
|
|
117258
|
-
}
|
|
117259
|
-
async launchPersistentContext(...args) {
|
|
117260
|
-
if (!this.launcher.launchPersistentContext) {
|
|
117261
|
-
throw new Error('Launcher does not support "launchPersistentContext"');
|
|
117262
|
-
}
|
|
117263
|
-
let [userDataDir, options] = args;
|
|
117264
|
-
options = Object.assign({ args: [] }, (options || {})); // Initialize args array
|
|
117265
|
-
debug$2('launchPersistentContext', options);
|
|
117266
|
-
this.plugins.prepare();
|
|
117267
|
-
// Give plugins the chance to modify the options before continuing
|
|
117268
|
-
options =
|
|
117269
|
-
(await this.plugins.dispatchBlocking('beforeLaunch', options)) || options;
|
|
117270
|
-
const context = await this.launcher['launchPersistentContext'](userDataDir, options);
|
|
117271
|
-
await this.plugins.dispatchBlocking('afterLaunch', context);
|
|
117272
|
-
this._bindBrowserContextEvents(context);
|
|
117273
|
-
return context;
|
|
117274
|
-
}
|
|
117275
|
-
async connect(wsEndpointOrOptions, wsOptions = {}) {
|
|
117276
|
-
if (!this.launcher.connect) {
|
|
117277
|
-
throw new Error('Launcher does not support "connect"');
|
|
117278
|
-
}
|
|
117279
|
-
this.plugins.prepare();
|
|
117280
|
-
// Playwright currently supports two function signatures for .connect
|
|
117281
|
-
let options = {};
|
|
117282
|
-
let wsEndpointAsString = false;
|
|
117283
|
-
if (typeof wsEndpointOrOptions === 'object') {
|
|
117284
|
-
options = Object.assign(Object.assign({}, wsEndpointOrOptions), wsOptions);
|
|
117285
|
-
}
|
|
117286
|
-
else {
|
|
117287
|
-
wsEndpointAsString = true;
|
|
117288
|
-
options = Object.assign({ wsEndpoint: wsEndpointOrOptions }, wsOptions);
|
|
117289
|
-
}
|
|
117290
|
-
debug$2('connect', options);
|
|
117291
|
-
// Give plugins the chance to modify the options before launch/connect
|
|
117292
|
-
options =
|
|
117293
|
-
(await this.plugins.dispatchBlocking('beforeConnect', options)) || options;
|
|
117294
|
-
// Follow call signature of end user
|
|
117295
|
-
const args = [];
|
|
117296
|
-
const wsEndpoint = options.wsEndpoint;
|
|
117297
|
-
if (wsEndpointAsString) {
|
|
117298
|
-
delete options.wsEndpoint;
|
|
117299
|
-
args.push(wsEndpoint, options);
|
|
117300
|
-
}
|
|
117301
|
-
else {
|
|
117302
|
-
args.push(options);
|
|
117303
|
-
}
|
|
117304
|
-
const browser = (await this.launcher['connect'](...args));
|
|
117305
|
-
await this.plugins.dispatchBlocking('onBrowser', browser);
|
|
117306
|
-
await this._bindBrowserEvents(browser);
|
|
117307
|
-
await this.plugins.dispatchBlocking('afterConnect', browser);
|
|
117308
|
-
return browser;
|
|
117309
|
-
}
|
|
117310
|
-
async connectOverCDP(wsEndpointOrOptions, wsOptions = {}) {
|
|
117311
|
-
if (!this.launcher.connectOverCDP) {
|
|
117312
|
-
throw new Error(`Launcher does not implement 'connectOverCDP'`);
|
|
117313
|
-
}
|
|
117314
|
-
this.plugins.prepare();
|
|
117315
|
-
// Playwright currently supports two function signatures for .connectOverCDP
|
|
117316
|
-
let options = {};
|
|
117317
|
-
let wsEndpointAsString = false;
|
|
117318
|
-
if (typeof wsEndpointOrOptions === 'object') {
|
|
117319
|
-
options = Object.assign(Object.assign({}, wsEndpointOrOptions), wsOptions);
|
|
117320
|
-
}
|
|
117321
|
-
else {
|
|
117322
|
-
wsEndpointAsString = true;
|
|
117323
|
-
options = Object.assign({ endpointURL: wsEndpointOrOptions }, wsOptions);
|
|
117324
|
-
}
|
|
117325
|
-
debug$2('connectOverCDP');
|
|
117326
|
-
// Give plugins the chance to modify the options before launch/connect
|
|
117327
|
-
options =
|
|
117328
|
-
(await this.plugins.dispatchBlocking('beforeConnect', options)) || options;
|
|
117329
|
-
// Follow call signature of end user
|
|
117330
|
-
const args = [];
|
|
117331
|
-
const endpointURL = options.endpointURL;
|
|
117332
|
-
if (wsEndpointAsString) {
|
|
117333
|
-
delete options.endpointURL;
|
|
117334
|
-
args.push(endpointURL, options);
|
|
117335
|
-
}
|
|
117336
|
-
else {
|
|
117337
|
-
args.push(options);
|
|
117338
|
-
}
|
|
117339
|
-
const browser = (await this.launcher['connectOverCDP'](...args));
|
|
117340
|
-
await this.plugins.dispatchBlocking('onBrowser', browser);
|
|
117341
|
-
await this._bindBrowserEvents(browser);
|
|
117342
|
-
await this.plugins.dispatchBlocking('afterConnect', browser);
|
|
117343
|
-
return browser;
|
|
117344
|
-
}
|
|
117345
|
-
async _bindBrowserContextEvents(context, contextOptions) {
|
|
117346
|
-
debug$2('_bindBrowserContextEvents');
|
|
117347
|
-
this.plugins.dispatch('onContextCreated', context, contextOptions);
|
|
117348
|
-
// Make sure things like `addInitScript` show an effect on the very first page as well
|
|
117349
|
-
context.newPage = ((originalMethod, ctx) => {
|
|
117350
|
-
return async () => {
|
|
117351
|
-
const page = await originalMethod.call(ctx);
|
|
117352
|
-
await page.goto('about:blank');
|
|
117353
|
-
return page;
|
|
117354
|
-
};
|
|
117355
|
-
})(context.newPage, context);
|
|
117356
|
-
context.on('close', () => {
|
|
117357
|
-
// When using `launchPersistentContext` context closing is the same as browser closing
|
|
117358
|
-
if (!context.browser()) {
|
|
117359
|
-
this.plugins.dispatch('onDisconnected');
|
|
117360
|
-
}
|
|
117361
|
-
});
|
|
117362
|
-
context.on('page', page => {
|
|
117363
|
-
this.plugins.dispatch('onPageCreated', page);
|
|
117364
|
-
page.on('close', () => {
|
|
117365
|
-
this.plugins.dispatch('onPageClose', page);
|
|
117366
|
-
});
|
|
117367
|
-
});
|
|
117368
|
-
}
|
|
117369
|
-
async _bindBrowserEvents(browser) {
|
|
117370
|
-
debug$2('_bindPlaywrightBrowserEvents');
|
|
117371
|
-
browser.on('disconnected', () => {
|
|
117372
|
-
this.plugins.dispatch('onDisconnected', browser);
|
|
117373
|
-
});
|
|
117374
|
-
// Note: `browser.newPage` will implicitly call `browser.newContext` as well
|
|
117375
|
-
browser.newContext = ((originalMethod, ctx) => {
|
|
117376
|
-
return async (options = {}) => {
|
|
117377
|
-
const contextOptions = (await this.plugins.dispatchBlocking('beforeContext', options, browser)) || options;
|
|
117378
|
-
const context = await originalMethod.call(ctx, contextOptions);
|
|
117379
|
-
this._bindBrowserContextEvents(context, contextOptions);
|
|
117380
|
-
return context;
|
|
117381
|
-
};
|
|
117382
|
-
})(browser.newContext, browser);
|
|
117383
|
-
}
|
|
117384
|
-
}
|
|
117385
|
-
/**
|
|
117386
|
-
* PlaywrightExtra class with additional launcher methods.
|
|
117387
|
-
*
|
|
117388
|
-
* Augments the class with an instance proxy to pass on methods that are not augmented to the original target.
|
|
117389
|
-
*
|
|
117390
|
-
*/
|
|
117391
|
-
const PlaywrightExtra = new Proxy(PlaywrightExtraClass, {
|
|
117392
|
-
construct(classTarget, args) {
|
|
117393
|
-
debug$2(`create instance of ${classTarget.name}`);
|
|
117394
|
-
const result = Reflect.construct(classTarget, args);
|
|
117395
|
-
return new Proxy(result, {
|
|
117396
|
-
get(target, prop) {
|
|
117397
|
-
if (prop in target) {
|
|
117398
|
-
return Reflect.get(target, prop);
|
|
117399
|
-
}
|
|
117400
|
-
debug$2('proxying property to original launcher: ', prop);
|
|
117401
|
-
return Reflect.get(target.launcher, prop);
|
|
117402
|
-
}
|
|
117403
|
-
});
|
|
117404
|
-
}
|
|
117405
|
-
});
|
|
117406
|
-
|
|
117407
|
-
/**
|
|
117408
|
-
* Augment the provided Playwright browser launcher with plugin functionality.
|
|
117409
|
-
*
|
|
117410
|
-
* Using `addExtra` will always create a fresh PlaywrightExtra instance.
|
|
117411
|
-
*
|
|
117412
|
-
* @example
|
|
117413
|
-
* import playwright from 'playwright'
|
|
117414
|
-
* import { addExtra } from 'playwright-extra'
|
|
117415
|
-
*
|
|
117416
|
-
* const chromium = addExtra(playwright.chromium)
|
|
117417
|
-
* chromium.use(plugin)
|
|
117418
|
-
*
|
|
117419
|
-
* @param launcher - Playwright (or compatible) browser launcher
|
|
117420
|
-
*/
|
|
117421
|
-
const addExtra = (launcher) => new PlaywrightExtra(launcher);
|
|
117422
|
-
/**
|
|
117423
|
-
* This object can be used to launch or connect to Chromium with plugin functionality.
|
|
117424
|
-
*
|
|
117425
|
-
* This default export will behave exactly the same as the regular playwright
|
|
117426
|
-
* (just with extra plugin functionality) and can be used as a drop-in replacement.
|
|
117427
|
-
*
|
|
117428
|
-
* Behind the scenes it will try to require either the `playwright-core`
|
|
117429
|
-
* or `playwright` module from the installed dependencies.
|
|
117430
|
-
*
|
|
117431
|
-
* @note
|
|
117432
|
-
* Due to Node.js import caching this will result in a single
|
|
117433
|
-
* PlaywrightExtra instance, even when used in different files. If you need multiple
|
|
117434
|
-
* instances with different plugins please use `addExtra`.
|
|
117435
|
-
*
|
|
117436
|
-
* @example
|
|
117437
|
-
* // javascript import
|
|
117438
|
-
* const { chromium } = require('playwright-extra')
|
|
117439
|
-
*
|
|
117440
|
-
* // typescript/es6 module import
|
|
117441
|
-
* import { chromium } from 'playwright-extra'
|
|
117442
|
-
*
|
|
117443
|
-
* // Add plugins
|
|
117444
|
-
* chromium.use(...)
|
|
117445
|
-
*/
|
|
117446
|
-
const chromium = addExtra((playwrightLoader.loadModule() || {}).chromium);
|
|
117447
|
-
/**
|
|
117448
|
-
* This object can be used to launch or connect to Firefox with plugin functionality
|
|
117449
|
-
* @note This export will always return the same instance, if you wish to use multiple instances with different plugins use `addExtra`
|
|
117450
|
-
*/
|
|
117451
|
-
addExtra((playwrightLoader.loadModule() || {}).firefox);
|
|
117452
|
-
/**
|
|
117453
|
-
* This object can be used to launch or connect to Webkit with plugin functionality
|
|
117454
|
-
* @note This export will always return the same instance, if you wish to use multiple instances with different plugins use `addExtra`
|
|
117455
|
-
*/
|
|
117456
|
-
addExtra((playwrightLoader.loadModule() || {}).webkit);
|
|
117457
|
-
// Other playwright module exports we simply re-export with lazy loading
|
|
117458
|
-
playwrightLoader.lazyloadExportOrDie('_android');
|
|
117459
|
-
playwrightLoader.lazyloadExportOrDie('_electron');
|
|
117460
|
-
playwrightLoader.lazyloadExportOrDie('request');
|
|
117461
|
-
playwrightLoader.lazyloadExportOrDie('selectors');
|
|
117462
|
-
playwrightLoader.lazyloadExportOrDie('devices');
|
|
117463
|
-
playwrightLoader.lazyloadExportOrDie('errors');
|
|
117464
|
-
|
|
117465
116576
|
var stealth = test$1.extend({
|
|
117466
|
-
browser: async ({
|
|
117467
|
-
|
|
117468
|
-
|
|
117469
|
-
const stealthBrowser = await
|
|
116577
|
+
browser: async ({}, use) => {
|
|
116578
|
+
const chromiumBrowser = addExtra(chromium);
|
|
116579
|
+
chromiumBrowser.use(stealth$1());
|
|
116580
|
+
const stealthBrowser = await chromiumBrowser.launch();
|
|
117470
116581
|
await use(stealthBrowser);
|
|
117471
116582
|
await stealthBrowser.close();
|
|
117472
116583
|
},
|
|
@@ -117566,7 +116677,7 @@ const i18nFixture = {
|
|
|
117566
116677
|
i18n: [
|
|
117567
116678
|
async ({}, use) => {
|
|
117568
116679
|
const translation = readTranslations();
|
|
117569
|
-
const page = await (await chromium
|
|
116680
|
+
const page = await (await chromium.launch()).newPage();
|
|
117570
116681
|
const taxonomies = await mergeTaxonomies(translation, page);
|
|
117571
116682
|
const options = {
|
|
117572
116683
|
debug: false,
|
|
@@ -119675,31 +118786,6 @@ class HelpAndProfilePage {
|
|
|
119675
118786
|
})).toHaveScreenshot(expectedScreenshot, { maxDiffPixelRatio: 0.1 });
|
|
119676
118787
|
});
|
|
119677
118788
|
};
|
|
119678
|
-
/**
|
|
119679
|
-
* @deprecated This method is deprecated. Use updateBasicInfo instead.
|
|
119680
|
-
*/
|
|
119681
|
-
updateProfile = async ({ firstName, lastName }) => {
|
|
119682
|
-
await this.openHelpCenter();
|
|
119683
|
-
await this.page
|
|
119684
|
-
.getByTestId(PROFILE_SECTION_SELECTORS.myProfileButton)
|
|
119685
|
-
.click();
|
|
119686
|
-
await this.page
|
|
119687
|
-
.getByTestId(COMMON_SELECTORS.pane)
|
|
119688
|
-
.getByTestId(COMMON_SELECTORS.dropdownIcon)
|
|
119689
|
-
.click();
|
|
119690
|
-
await this.page.getByTestId(PROFILE_SECTION_SELECTORS.editBtn).click();
|
|
119691
|
-
firstName &&
|
|
119692
|
-
(await this.page
|
|
119693
|
-
.getByTestId(PROFILE_SECTION_SELECTORS.firstNameTextField)
|
|
119694
|
-
.fill(firstName));
|
|
119695
|
-
lastName &&
|
|
119696
|
-
(await this.page
|
|
119697
|
-
.getByTestId(PROFILE_SECTION_SELECTORS.lastNameTextField)
|
|
119698
|
-
.fill(lastName));
|
|
119699
|
-
await this.page.getByTestId(PROFILE_SECTION_SELECTORS.submitButton).click();
|
|
119700
|
-
await this.neetoPlaywrightUtilities.waitForPageLoad();
|
|
119701
|
-
await expect(this.page.getByTestId(COMMON_SELECTORS.paneModalCrossIcon)).toBeHidden();
|
|
119702
|
-
};
|
|
119703
118789
|
}
|
|
119704
118790
|
|
|
119705
118791
|
class MicrosoftPage extends IntegrationBase {
|
|
@@ -120030,32 +119116,6 @@ class SlackPage extends IntegrationBase {
|
|
|
120030
119116
|
await nextButton.click();
|
|
120031
119117
|
await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.inviteToWorkspaceSkipButton).click();
|
|
120032
119118
|
};
|
|
120033
|
-
/**
|
|
120034
|
-
* @deprecated Use {@link SlackPage.archiveChannelViaAPI} instead. This flow
|
|
120035
|
-
* drives the Slack web UI to permanently delete a channel and is brittle;
|
|
120036
|
-
* `archiveChannelViaAPI` archives via the Slack Web API (requires
|
|
120037
|
-
* `SLACK_BOT_TOKEN`).
|
|
120038
|
-
*/
|
|
120039
|
-
deleteSlackChannel = async (channel) => {
|
|
120040
|
-
const channelItem = this.slackWebappPage.locator(SLACK_SELECTORS.channelItems, { hasText: channel });
|
|
120041
|
-
await channelItem.click({ button: "right" });
|
|
120042
|
-
await this.slackWebappPageDataQa([
|
|
120043
|
-
SLACK_DATA_QA_SELECTORS.menuItems,
|
|
120044
|
-
SLACK_DATA_QA_SELECTORS.channelDetailsModal,
|
|
120045
|
-
]).click();
|
|
120046
|
-
await expect(this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.channelDetailsModal)).toBeVisible();
|
|
120047
|
-
await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.channelDetailsSettingsTab).click();
|
|
120048
|
-
await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.skModalContent)
|
|
120049
|
-
.getByRole("button", { name: SLACK_WEB_TEXTS.deleteThisChannel })
|
|
120050
|
-
.click();
|
|
120051
|
-
await this.slackWebappPage
|
|
120052
|
-
.getByLabel(SLACK_WEB_TEXTS.permanentlyDeleteTheChannel)
|
|
120053
|
-
.check();
|
|
120054
|
-
await this.slackWebappPage
|
|
120055
|
-
.getByRole("button", { name: SLACK_WEB_TEXTS.deleteChannel })
|
|
120056
|
-
.click();
|
|
120057
|
-
await expect(channelItem).toBeHidden();
|
|
120058
|
-
};
|
|
120059
119119
|
archiveChannelViaAPI = async (name) => {
|
|
120060
119120
|
const response = await this.slackApi.listChannels();
|
|
120061
119121
|
const { channels } = (await response?.json());
|
|
@@ -120367,7 +119427,7 @@ class ZapierPage extends IntegrationBase {
|
|
|
120367
119427
|
message: TOASTR_MESSAGES.zapierApiKeyGenerated,
|
|
120368
119428
|
});
|
|
120369
119429
|
await this.page.getByTestId(COMMON_SELECTORS.copyToClipboardButton).click();
|
|
120370
|
-
const apiKey = await this.page
|
|
119430
|
+
const apiKey = await getClipboardContent(this.page);
|
|
120371
119431
|
await this.verifyIntegrationStatus();
|
|
120372
119432
|
return apiKey;
|
|
120373
119433
|
};
|
|
@@ -120504,6 +119564,7 @@ const LIST_MODIFIER_TAGS = {
|
|
|
120504
119564
|
orderedList: "ol",
|
|
120505
119565
|
};
|
|
120506
119566
|
|
|
119567
|
+
const __dirname$4 = getDirname(import.meta.url);
|
|
120507
119568
|
class SlashCommandEditorPage {
|
|
120508
119569
|
page;
|
|
120509
119570
|
neetoPlaywrightUtilities;
|
|
@@ -120623,7 +119684,7 @@ class SlashCommandEditorPage {
|
|
|
120623
119684
|
.getByTestId(NEETO_IMAGE_UPLOADER_SELECTORS.browseText)
|
|
120624
119685
|
.click();
|
|
120625
119686
|
const fileUploader = await fileUploaderPromise;
|
|
120626
|
-
const imagePath = path.join(__dirname, filePath);
|
|
119687
|
+
const imagePath = path.join(__dirname$4, filePath);
|
|
120627
119688
|
await fileUploader.setFiles(imagePath);
|
|
120628
119689
|
await expect(this.imageWrapper).toBeVisible({ timeout: 15_000 });
|
|
120629
119690
|
if (shouldRemoveImage) {
|
|
@@ -120698,6 +119759,7 @@ class SlashCommandEditorPage {
|
|
|
120698
119759
|
};
|
|
120699
119760
|
}
|
|
120700
119761
|
|
|
119762
|
+
const __dirname$3 = getDirname(import.meta.url);
|
|
120701
119763
|
class EditorPage {
|
|
120702
119764
|
page;
|
|
120703
119765
|
neetoPlaywrightUtilities;
|
|
@@ -120928,7 +119990,7 @@ class EditorPage {
|
|
|
120928
119990
|
isButtonInMoreMenu && (await this.moreMenuSelector.click());
|
|
120929
119991
|
await this.editorAttachmentsButton.click();
|
|
120930
119992
|
const fileUploader = await fileUploaderPromise;
|
|
120931
|
-
const imagePath = path.join(__dirname, filePath);
|
|
119993
|
+
const imagePath = path.join(__dirname$3, filePath);
|
|
120932
119994
|
await fileUploader.setFiles(imagePath);
|
|
120933
119995
|
await expect(this.attachmentPreview).toBeVisible();
|
|
120934
119996
|
if (shouldRemoveAttachment) {
|
|
@@ -120954,7 +120016,7 @@ class EditorPage {
|
|
|
120954
120016
|
.getByTestId(NEETO_IMAGE_UPLOADER_SELECTORS.browseText)
|
|
120955
120017
|
.click();
|
|
120956
120018
|
const fileUploader = await fileUploaderPromise;
|
|
120957
|
-
const imagePath = path.join(__dirname, filePath);
|
|
120019
|
+
const imagePath = path.join(__dirname$3, filePath);
|
|
120958
120020
|
await fileUploader.setFiles(imagePath);
|
|
120959
120021
|
await expect(this.imageWrapper).toBeVisible({ timeout: 15_000 });
|
|
120960
120022
|
if (shouldRemoveImage) {
|
|
@@ -121061,7 +120123,7 @@ class EditorPage {
|
|
|
121061
120123
|
.getByTestId(NEETO_EDITOR_SELECTORS.imageUploadButton)
|
|
121062
120124
|
.click();
|
|
121063
120125
|
const fileUploader = await fileUploaderPromise;
|
|
121064
|
-
const imagePath = path.join(__dirname, filePath);
|
|
120126
|
+
const imagePath = path.join(__dirname$3, filePath);
|
|
121065
120127
|
await fileUploader.setFiles(imagePath);
|
|
121066
120128
|
await expect(this.page.getByRole("figure")).toBeVisible({
|
|
121067
120129
|
timeout: 20_000,
|
|
@@ -122645,12 +121707,8 @@ const PHONE_NUMBER_FORMATS = [
|
|
|
122645
121707
|
const initializeCredentials = (product) => {
|
|
122646
121708
|
if (process.env.SKIP_SETUP === "true" && getGlobalUserState()) {
|
|
122647
121709
|
const { email } = getGlobalUserState();
|
|
122648
|
-
|
|
122649
|
-
|
|
122650
|
-
}
|
|
122651
|
-
else {
|
|
122652
|
-
email.endsWith("bigbinary.com") && removeCredentialFile();
|
|
122653
|
-
}
|
|
121710
|
+
const domain = IS_STAGING_ENV ? "example.com" : "bigbinary.com";
|
|
121711
|
+
email.endsWith(domain) && removeCredentialFile();
|
|
122654
121712
|
readFileSyncIfExists();
|
|
122655
121713
|
}
|
|
122656
121714
|
isStagingOrganizationExpired(getGlobalUserState()?.subdomainName) &&
|
|
@@ -125810,15 +124868,13 @@ async function warmup({ urls = DEFAULT_WARMUP_URLS, timeout = 60_000, } = {}) {
|
|
|
125810
124868
|
throw new Error("RAILS_SERVER_PORT is not defined in environment variables.");
|
|
125811
124869
|
}
|
|
125812
124870
|
const baseURL = `http://${SUBDOMAIN}.lvh.me:${RAILS_SERVER_PORT}`;
|
|
125813
|
-
const browser = await chromium
|
|
124871
|
+
const browser = await chromium.launch();
|
|
125814
124872
|
const page = await browser.newPage();
|
|
125815
124873
|
try {
|
|
125816
124874
|
for (const url of urls) {
|
|
125817
124875
|
const fullUrl = url.startsWith("http") ? url : `${baseURL}${url}`;
|
|
125818
|
-
|
|
125819
|
-
|
|
125820
|
-
timeout,
|
|
125821
|
-
});
|
|
124876
|
+
// eslint-disable-next-line playwright/no-networkidle
|
|
124877
|
+
await page.goto(fullUrl, { waitUntil: "networkidle", timeout });
|
|
125822
124878
|
}
|
|
125823
124879
|
}
|
|
125824
124880
|
finally {
|
|
@@ -125833,7 +124889,8 @@ const CONFIG$1 = {
|
|
|
125833
124889
|
MAX_WAIT_MS: 120_000,
|
|
125834
124890
|
EMAIL_INIT: "/tmp/neeto-auth-web/config/initializers/playwright_email_capture.rb",
|
|
125835
124891
|
};
|
|
125836
|
-
const
|
|
124892
|
+
const __dirname$2 = getDirname(import.meta.url);
|
|
124893
|
+
const SCRIPTS_DIR$1 = path.join(__dirname$2, "scripts", "neeto-auth");
|
|
125837
124894
|
const escapeRubyString = (value) => value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
125838
124895
|
const buildEmailCaptureInitializer = (targetApp) => {
|
|
125839
124896
|
const template = fs.readFileSync(path.join(SCRIPTS_DIR$1, "playwright_email_capture.rb.template"), "utf-8");
|
|
@@ -125993,7 +125050,8 @@ const CONFIG = {
|
|
|
125993
125050
|
};
|
|
125994
125051
|
const DEFAULT_STATE = { pid: null, refCount: 0 };
|
|
125995
125052
|
const WIDGET_BASE_URL = `http://localhost:${CONFIG.PORT}`;
|
|
125996
|
-
const
|
|
125053
|
+
const __dirname$1 = getDirname(import.meta.url);
|
|
125054
|
+
const SCRIPTS_DIR = path.join(__dirname$1, "scripts", "neeto-chat-widget");
|
|
125997
125055
|
const log = (msg) => console.log(`[NeetoChatWidget] ${msg}`);
|
|
125998
125056
|
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
|
125999
125057
|
const httpCheck = (timeout = 3000) => new Promise(resolve => {
|
|
@@ -126310,17 +125368,17 @@ class EmailDeliveryUtils {
|
|
|
126310
125368
|
};
|
|
126311
125369
|
}
|
|
126312
125370
|
|
|
126313
|
-
var main
|
|
125371
|
+
var main = {exports: {}};
|
|
126314
125372
|
|
|
126315
125373
|
var version = "17.3.1";
|
|
126316
125374
|
var require$$4 = {
|
|
126317
125375
|
version: version};
|
|
126318
125376
|
|
|
126319
|
-
var hasRequiredMain
|
|
125377
|
+
var hasRequiredMain;
|
|
126320
125378
|
|
|
126321
|
-
function requireMain
|
|
126322
|
-
if (hasRequiredMain
|
|
126323
|
-
hasRequiredMain
|
|
125379
|
+
function requireMain () {
|
|
125380
|
+
if (hasRequiredMain) return main.exports;
|
|
125381
|
+
hasRequiredMain = 1;
|
|
126324
125382
|
const fs = fs__default;
|
|
126325
125383
|
const path = path__default;
|
|
126326
125384
|
const os$1 = os;
|
|
@@ -126743,130 +125801,20 @@ function requireMain$1 () {
|
|
|
126743
125801
|
populate
|
|
126744
125802
|
};
|
|
126745
125803
|
|
|
126746
|
-
main
|
|
126747
|
-
main
|
|
126748
|
-
main
|
|
126749
|
-
main
|
|
126750
|
-
main
|
|
126751
|
-
main
|
|
126752
|
-
main
|
|
126753
|
-
|
|
126754
|
-
main$1.exports = DotenvModule;
|
|
126755
|
-
return main$1.exports;
|
|
126756
|
-
}
|
|
126757
|
-
|
|
126758
|
-
var mainExports$1 = requireMain$1();
|
|
126759
|
-
var dotenv = /*@__PURE__*/getDefaultExportFromCjs(mainExports$1);
|
|
126760
|
-
|
|
126761
|
-
var main = {};
|
|
126762
|
-
|
|
126763
|
-
var hasRequiredMain;
|
|
126764
|
-
|
|
126765
|
-
function requireMain () {
|
|
126766
|
-
if (hasRequiredMain) return main;
|
|
126767
|
-
hasRequiredMain = 1;
|
|
126768
|
-
|
|
126769
|
-
function _resolveEscapeSequences (value) {
|
|
126770
|
-
return value.replace(/\\\$/g, '$')
|
|
126771
|
-
}
|
|
126772
|
-
|
|
126773
|
-
function expandValue (value, processEnv, runningParsed) {
|
|
126774
|
-
const env = { ...runningParsed, ...processEnv }; // process.env wins
|
|
126775
|
-
|
|
126776
|
-
const regex = /(?<!\\)\${([^{}]+)}|(?<!\\)\$([A-Za-z_][A-Za-z0-9_]*)/g;
|
|
126777
|
-
|
|
126778
|
-
let result = value;
|
|
126779
|
-
let match;
|
|
126780
|
-
const seen = new Set(); // self-referential checker
|
|
126781
|
-
|
|
126782
|
-
while ((match = regex.exec(result)) !== null) {
|
|
126783
|
-
seen.add(result);
|
|
126784
|
-
|
|
126785
|
-
const [template, bracedExpression, unbracedExpression] = match;
|
|
126786
|
-
const expression = bracedExpression || unbracedExpression;
|
|
126787
|
-
|
|
126788
|
-
// match the operators `:+`, `+`, `:-`, and `-`
|
|
126789
|
-
const opRegex = /(:\+|\+|:-|-)/;
|
|
126790
|
-
// find first match
|
|
126791
|
-
const opMatch = expression.match(opRegex);
|
|
126792
|
-
const splitter = opMatch ? opMatch[0] : null;
|
|
126793
|
-
|
|
126794
|
-
const r = expression.split(splitter);
|
|
126795
|
-
|
|
126796
|
-
let defaultValue;
|
|
126797
|
-
let value;
|
|
126798
|
-
|
|
126799
|
-
const key = r.shift();
|
|
126800
|
-
|
|
126801
|
-
if ([':+', '+'].includes(splitter)) {
|
|
126802
|
-
defaultValue = env[key] ? r.join(splitter) : '';
|
|
126803
|
-
value = null;
|
|
126804
|
-
} else {
|
|
126805
|
-
defaultValue = r.join(splitter);
|
|
126806
|
-
value = env[key];
|
|
126807
|
-
}
|
|
126808
|
-
|
|
126809
|
-
if (value) {
|
|
126810
|
-
// self-referential check
|
|
126811
|
-
if (seen.has(value)) {
|
|
126812
|
-
result = result.replace(template, defaultValue);
|
|
126813
|
-
} else {
|
|
126814
|
-
result = result.replace(template, value);
|
|
126815
|
-
}
|
|
126816
|
-
} else {
|
|
126817
|
-
result = result.replace(template, defaultValue);
|
|
126818
|
-
}
|
|
126819
|
-
|
|
126820
|
-
// if the result equaled what was in process.env and runningParsed then stop expanding
|
|
126821
|
-
if (result === runningParsed[key]) {
|
|
126822
|
-
break
|
|
126823
|
-
}
|
|
126824
|
-
|
|
126825
|
-
regex.lastIndex = 0; // reset regex search position to re-evaluate after each replacement
|
|
126826
|
-
}
|
|
126827
|
-
|
|
126828
|
-
return result
|
|
126829
|
-
}
|
|
126830
|
-
|
|
126831
|
-
function expand (options) {
|
|
126832
|
-
// for use with progressive expansion
|
|
126833
|
-
const runningParsed = {};
|
|
126834
|
-
|
|
126835
|
-
let processEnv = process.env;
|
|
126836
|
-
if (options && options.processEnv != null) {
|
|
126837
|
-
processEnv = options.processEnv;
|
|
126838
|
-
}
|
|
126839
|
-
|
|
126840
|
-
// dotenv.config() ran before this so the assumption is process.env has already been set
|
|
126841
|
-
for (const key in options.parsed) {
|
|
126842
|
-
let value = options.parsed[key];
|
|
126843
|
-
|
|
126844
|
-
// short-circuit scenario: process.env was already set prior to the file value
|
|
126845
|
-
if (processEnv[key] && processEnv[key] !== value) {
|
|
126846
|
-
value = processEnv[key];
|
|
126847
|
-
} else {
|
|
126848
|
-
value = expandValue(value, processEnv, runningParsed);
|
|
126849
|
-
}
|
|
126850
|
-
|
|
126851
|
-
options.parsed[key] = _resolveEscapeSequences(value);
|
|
126852
|
-
|
|
126853
|
-
// for use with progressive expansion
|
|
126854
|
-
runningParsed[key] = _resolveEscapeSequences(value);
|
|
126855
|
-
}
|
|
126856
|
-
|
|
126857
|
-
for (const processKey in options.parsed) {
|
|
126858
|
-
processEnv[processKey] = options.parsed[processKey];
|
|
126859
|
-
}
|
|
126860
|
-
|
|
126861
|
-
return options
|
|
126862
|
-
}
|
|
125804
|
+
main.exports.configDotenv = DotenvModule.configDotenv;
|
|
125805
|
+
main.exports._configVault = DotenvModule._configVault;
|
|
125806
|
+
main.exports._parseVault = DotenvModule._parseVault;
|
|
125807
|
+
main.exports.config = DotenvModule.config;
|
|
125808
|
+
main.exports.decrypt = DotenvModule.decrypt;
|
|
125809
|
+
main.exports.parse = DotenvModule.parse;
|
|
125810
|
+
main.exports.populate = DotenvModule.populate;
|
|
126863
125811
|
|
|
126864
|
-
main.
|
|
126865
|
-
return main;
|
|
125812
|
+
main.exports = DotenvModule;
|
|
125813
|
+
return main.exports;
|
|
126866
125814
|
}
|
|
126867
125815
|
|
|
126868
125816
|
var mainExports = requireMain();
|
|
126869
|
-
var
|
|
125817
|
+
var dotenv = /*@__PURE__*/getDefaultExportFromCjs(mainExports);
|
|
126870
125818
|
|
|
126871
125819
|
const E2E_TEST_DIR = "e2e/tests";
|
|
126872
125820
|
const LOG_PREFIX = "[playwright.config]";
|
|
@@ -126927,11 +125875,11 @@ const parseSpecPatterns = () => {
|
|
|
126927
125875
|
};
|
|
126928
125876
|
|
|
126929
125877
|
// @ts-check
|
|
126930
|
-
const loadEnv = (path) => dotenvExpand.expand(dotenv.config({ path, quiet: true }));
|
|
126931
125878
|
const envBasePath = "./e2e/config/.env";
|
|
126932
125879
|
const envLocalPath = `${envBasePath}.local`;
|
|
126933
125880
|
const reporterPackageName = "@bigbinary/neeto-playwright-reporter";
|
|
126934
125881
|
process.env.TEST_ENV = process.env.TEST_ENV ?? ENVIRONMENT.development;
|
|
125882
|
+
const loadEnv = (path) => dotenv.config({ path, quiet: true });
|
|
126935
125883
|
loadEnv(`${envBasePath}.${process.env.TEST_ENV}`);
|
|
126936
125884
|
fs.existsSync(envLocalPath) && loadEnv(envLocalPath);
|
|
126937
125885
|
const playdashStagingConfig = {
|
|
@@ -127135,5 +126083,4 @@ const definePlaywrightConfig = (overrides) => {
|
|
|
127135
126083
|
});
|
|
127136
126084
|
};
|
|
127137
126085
|
|
|
127138
|
-
export { ACTIONS, ADMIN_PANEL_SELECTORS, ALL_RESOURCES, ANALYTICS_RESOURCES, API_KEYS_SELECTORS, API_ROUTES, APP_RESOURCES, AUDIT_LOGS_SELECTORS, ApiKeysApi, ApiKeysPage, AuditLogsPage, BASE_URL, CALENDAR_LABELS, CERTIFICATE_LIMIT_EXCEEDED_MESSAGE, CERTIFICATE_LIMIT_EXCEEDED_REGEXP, CHANGELOG_WIDGET_SELECTORS, CHAT_WIDGET_SELECTORS, CHAT_WIDGET_TEXTS, COLOR, COMMON_SELECTORS, COMMON_TEXTS, COMMUNITY_TEXTS, CREDENTIALS, CURRENT_TIME_RANGES, CUSTOM_DOMAIN_SELECTORS, CUSTOM_DOMAIN_SUFFIX, ColorPickerUtils, CustomCommands, CustomDomainApi, CustomDomainPage, DATE_FORMATS, DATE_PICKER_SELECTORS, DATE_RANGES, DATE_TEXTS, DEFAULT_WEBHOOKS_RESPONSE_TEXT, DESCRIPTION_EDITOR_TEXTS, EMBED_SELECTORS, EMOJI_LABEL, EMPTY_STORAGE_STATE, ENGAGE_TEXTS, ENVIRONMENT, EXAMPLE_URL, EXPANDED_FONT_SIZE, EXPORT_FILE_TYPES, EditorPage, EmailDeliveryUtils, EmbedBase, FILE_FORMATS, FONTS_RESOURCES, FONT_SIZE_SELECTORS, FROM_EMAIL_ENV_KEYS, GLOBAL_TRANSLATIONS_PATTERN, GOOGLE_ANALYTICS_SELECTORS, GOOGLE_CALENDAR_DATE_FORMAT, GOOGLE_LOGIN_SELECTORS, GOOGLE_LOGIN_TEXTS, GOOGLE_SHEETS_SELECTORS, GooglePage, HELP_CENTER_ROUTES, HELP_CENTER_SELECTORS, HelpAndProfilePage, INTEGRATIONS_TEXTS, INTEGRATION_SELECTORS, IPRestrictionsPage, IP_RESTRICTIONS_SELECTORS, IS_CI, IS_DEV_ENV, IS_STAGING_ENV, ImageUploader, IntegrationBase, IpRestrictionsApi, KEYBOARD_SHORTCUTS_SELECTORS, KEYBOARD_SHORTCUT_TEST_CASES, LIST_MODIFIER_SELECTORS, LIST_MODIFIER_TAGS, LOGIN_SELECTORS, MEMBER_FORM_SELECTORS, MEMBER_SELECTORS, MEMBER_TEXTS, MERGE_TAGS_SELECTORS, MICROSOFT_LOGIN_SELECTORS, MICROSOFT_LOGIN_TEXTS, MailerUtils, Member, MemberApis, MicrosoftPage, NEETO_AUTH_BASE_URL, NEETO_EDITOR_SELECTORS, NEETO_FILTERS_SELECTORS, NEETO_IMAGE_UPLOADER_SELECTORS, NEETO_ROUTES, NEETO_SEO_SELECTORS, NEETO_TEXT_MODIFIER_SELECTORS, NeetoAuthServer, NeetoChatWidget, NeetoEmailDeliveryApi, NeetoTowerApi, ONBOARDING_SELECTORS, ORGANIZATION_TEXTS, OTP_EMAIL_PATTERN, OrganizationPage, PAST_TIME_RANGES, PHONE_NUMBER_FORMATS, PLURAL, PRODUCT_ROLES_ROUTE_MAP, PROFILE_LINKS, PROFILE_SECTION_SELECTORS, PROJECT_NAMES, PROJECT_TRANSLATIONS_PATH, ROLES_SELECTORS, ROUTES, RailsEmailApiClient, RailsEmailUtils, RoleApis, RolesPage, SIGNUP_SELECTORS, SINGULAR, SLACK_DATA_QA_SELECTORS, SLACK_DEFAULT_CHANNEL, SLACK_SELECTORS, SLACK_WEB_TEXTS, STATUS_TEXTS, STORAGE_STATE, SecurityApi, SidebarSection, SlackApi, SlackPage, TABLE_SELECTORS, TAB_SELECTORS, TAGS_SELECTORS, TEAM_MEMBER_TEXTS, TEXT_MODIFIER_ROLES, TEXT_MODIFIER_SELECTORS, TEXT_MODIFIER_TAGS, THANK_YOU_SELECTORS, THEMES_SELECTORS, THEMES_TEXTS, THIRD_PARTY_RESOURCES, THIRD_PARTY_ROUTES, TIME_RANGES, TOASTR_MESSAGES, TWILIO_SELECTORS, TagsApi, TagsPage, TeamMembers, ThankYouApi, ThankYouPage, TwilioApi, USER_AGENTS, WEBHOOK_SELECTORS, WebhookSiteApi, WebhooksPage, ZAPIER_LIMIT_EXHAUSTED_MESSAGE, ZAPIER_SELECTORS, ZAPIER_TEST_EMAIL, ZAPIER_WEB_TEXTS, ZapierPage, baseURLGenerator, basicHTMLContent, clearCredentials, commands, cpuThrottlingUsingCDP, createOrganizationViaRake, currencyUtils, dataQa, decodeQRCodeFromFile, definePlaywrightConfig, executeWithThrottledResources, extractSubdomainFromError, fillCredentialsAndSubmit, filterUtils, generatePhoneNumber, generatePhoneNumberDetails, generateRandomBypassEmail, generateRandomFile, generateStagingData, getByDataQA, getClipboardContent, getFormattedPhoneNumber, getFullUrl, getGlobalUserProps, getGlobalUserState, getImagePathAndName, getIsoCodeFromPhoneCode, getListCount, globalShortcuts, grantClipboardPermissions, hexToRGB, hexToRGBA, i18nFixture, imageRegex, initializeCredentials, initializeTestData, initializeTotp, isGithubIssueOpen, isStagingOrganizationExpired, joinHyphenCase, joinString, login, loginWithoutSSO, networkConditions, networkThrottlingUsingCDP, readFileSyncIfExists, removeCredentialFile, serializeFileForBrowser, shouldSkipCustomDomainSetup, shouldSkipSetupAndTeardown, simulateClickWithDelay, simulateTypingWithDelay, skipTest, squish, stealth as stealthTest, tableUtils, toCamelCase, updateCredentials, warmup, withCookieCache, writeDataToFile };
|
|
127139
|
-
//# sourceMappingURL=index.js.map
|
|
126086
|
+
export { ACTIONS, ADMIN_PANEL_SELECTORS, ALL_RESOURCES, ANALYTICS_RESOURCES, API_KEYS_SELECTORS, API_ROUTES, APP_RESOURCES, AUDIT_LOGS_SELECTORS, ApiKeysApi, ApiKeysPage, AuditLogsPage, BASE_URL, CALENDAR_LABELS, CERTIFICATE_LIMIT_EXCEEDED_MESSAGE, CERTIFICATE_LIMIT_EXCEEDED_REGEXP, CHANGELOG_WIDGET_SELECTORS, CHAT_WIDGET_SELECTORS, CHAT_WIDGET_TEXTS, COLOR, COMMON_SELECTORS, COMMON_TEXTS, COMMUNITY_TEXTS, CREDENTIALS, CURRENT_TIME_RANGES, CUSTOM_DOMAIN_SELECTORS, CUSTOM_DOMAIN_SUFFIX, ColorPickerUtils, CustomCommands, CustomDomainApi, CustomDomainPage, DATE_FORMATS, DATE_PICKER_SELECTORS, DATE_RANGES, DATE_TEXTS, DEFAULT_WEBHOOKS_RESPONSE_TEXT, DESCRIPTION_EDITOR_TEXTS, EMBED_SELECTORS, EMOJI_LABEL, EMPTY_STORAGE_STATE, ENGAGE_TEXTS, ENVIRONMENT, EXAMPLE_URL, EXPANDED_FONT_SIZE, EXPORT_FILE_TYPES, EditorPage, EmailDeliveryUtils, EmbedBase, FILE_FORMATS, FONTS_RESOURCES, FONT_SIZE_SELECTORS, FROM_EMAIL_ENV_KEYS, GLOBAL_TRANSLATIONS_PATTERN, GOOGLE_ANALYTICS_SELECTORS, GOOGLE_CALENDAR_DATE_FORMAT, GOOGLE_LOGIN_SELECTORS, GOOGLE_LOGIN_TEXTS, GOOGLE_SHEETS_SELECTORS, GooglePage, HELP_CENTER_ROUTES, HELP_CENTER_SELECTORS, HelpAndProfilePage, INTEGRATIONS_TEXTS, INTEGRATION_SELECTORS, IPRestrictionsPage, IP_RESTRICTIONS_SELECTORS, IS_CI, IS_DEV_ENV, IS_STAGING_ENV, ImageUploader, IntegrationBase, IpRestrictionsApi, KEYBOARD_SHORTCUTS_SELECTORS, KEYBOARD_SHORTCUT_TEST_CASES, LIST_MODIFIER_SELECTORS, LIST_MODIFIER_TAGS, LOGIN_SELECTORS, MEMBER_FORM_SELECTORS, MEMBER_SELECTORS, MEMBER_TEXTS, MERGE_TAGS_SELECTORS, MICROSOFT_LOGIN_SELECTORS, MICROSOFT_LOGIN_TEXTS, MailerUtils, Member, MemberApis, MicrosoftPage, NEETO_AUTH_BASE_URL, NEETO_EDITOR_SELECTORS, NEETO_FILTERS_SELECTORS, NEETO_IMAGE_UPLOADER_SELECTORS, NEETO_ROUTES, NEETO_SEO_SELECTORS, NEETO_TEXT_MODIFIER_SELECTORS, NeetoAuthServer, NeetoChatWidget, NeetoEmailDeliveryApi, NeetoTowerApi, ONBOARDING_SELECTORS, ORGANIZATION_TEXTS, OTP_EMAIL_PATTERN, OrganizationPage, PAST_TIME_RANGES, PHONE_NUMBER_FORMATS, PLURAL, PRODUCT_ROLES_ROUTE_MAP, PROFILE_LINKS, PROFILE_SECTION_SELECTORS, PROJECT_NAMES, PROJECT_TRANSLATIONS_PATH, ROLES_SELECTORS, ROUTES, RailsEmailApiClient, RailsEmailUtils, RoleApis, RolesPage, SIGNUP_SELECTORS, SINGULAR, SLACK_DATA_QA_SELECTORS, SLACK_DEFAULT_CHANNEL, SLACK_SELECTORS, SLACK_WEB_TEXTS, STATUS_TEXTS, STORAGE_STATE, SecurityApi, SidebarSection, SlackApi, SlackPage, TABLE_SELECTORS, TAB_SELECTORS, TAGS_SELECTORS, TEAM_MEMBER_TEXTS, TEXT_MODIFIER_ROLES, TEXT_MODIFIER_SELECTORS, TEXT_MODIFIER_TAGS, THANK_YOU_SELECTORS, THEMES_SELECTORS, THEMES_TEXTS, THIRD_PARTY_RESOURCES, THIRD_PARTY_ROUTES, TIME_RANGES, TOASTR_MESSAGES, TWILIO_SELECTORS, TagsApi, TagsPage, TeamMembers, ThankYouApi, ThankYouPage, TwilioApi, USER_AGENTS, WEBHOOK_SELECTORS, WebhookSiteApi, WebhooksPage, ZAPIER_LIMIT_EXHAUSTED_MESSAGE, ZAPIER_SELECTORS, ZAPIER_TEST_EMAIL, ZAPIER_WEB_TEXTS, ZapierPage, baseURLGenerator, basicHTMLContent, clearCredentials, commands, cpuThrottlingUsingCDP, createOrganizationViaRake, currencyUtils, dataQa, decodeQRCodeFromFile, definePlaywrightConfig, executeWithThrottledResources, extractSubdomainFromError, fillCredentialsAndSubmit, filterUtils, generatePhoneNumber, generatePhoneNumberDetails, generateRandomBypassEmail, generateRandomFile, generateStagingData, getByDataQA, getClipboardContent, getDirname, getFormattedPhoneNumber, getFullUrl, getGlobalUserProps, getGlobalUserState, getImagePathAndName, getIsoCodeFromPhoneCode, getListCount, globalShortcuts, grantClipboardPermissions, hexToRGB, hexToRGBA, i18nFixture, imageRegex, initializeCredentials, initializeTestData, initializeTotp, isGithubIssueOpen, isStagingOrganizationExpired, joinHyphenCase, joinString, login, loginWithoutSSO, networkConditions, networkThrottlingUsingCDP, readFileSyncIfExists, removeCredentialFile, serializeFileForBrowser, shouldSkipCustomDomainSetup, shouldSkipSetupAndTeardown, simulateClickWithDelay, simulateTypingWithDelay, skipTest, squish, stealth as stealthTest, tableUtils, toCamelCase, updateCredentials, warmup, withCookieCache, writeDataToFile };
|