screenshot/test_1
This commit is contained in:
69
node_modules/playwright-core/lib/androidServerImpl.js
generated
vendored
Normal file
69
node_modules/playwright-core/lib/androidServerImpl.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.AndroidServerLauncherImpl = void 0;
|
||||
var _playwrightServer = require("./remote/playwrightServer");
|
||||
var _playwright = require("./server/playwright");
|
||||
var _crypto = require("./server/utils/crypto");
|
||||
var _utilsBundle = require("./utilsBundle");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class AndroidServerLauncherImpl {
|
||||
async launchServer(options = {}) {
|
||||
const playwright = (0, _playwright.createPlaywright)({
|
||||
sdkLanguage: 'javascript',
|
||||
isServer: true
|
||||
});
|
||||
// 1. Pre-connect to the device
|
||||
let devices = await playwright.android.devices({
|
||||
host: options.adbHost,
|
||||
port: options.adbPort,
|
||||
omitDriverInstall: options.omitDriverInstall
|
||||
});
|
||||
if (devices.length === 0) throw new Error('No devices found');
|
||||
if (options.deviceSerialNumber) {
|
||||
devices = devices.filter(d => d.serial === options.deviceSerialNumber);
|
||||
if (devices.length === 0) throw new Error(`No device with serial number '${options.deviceSerialNumber}' was found`);
|
||||
}
|
||||
if (devices.length > 1) throw new Error(`More than one device found. Please specify deviceSerialNumber`);
|
||||
const device = devices[0];
|
||||
const path = options.wsPath ? options.wsPath.startsWith('/') ? options.wsPath : `/${options.wsPath}` : `/${(0, _crypto.createGuid)()}`;
|
||||
|
||||
// 2. Start the server
|
||||
const server = new _playwrightServer.PlaywrightServer({
|
||||
mode: 'launchServer',
|
||||
path,
|
||||
maxConnections: 1,
|
||||
preLaunchedAndroidDevice: device
|
||||
});
|
||||
const wsEndpoint = await server.listen(options.port, options.host);
|
||||
|
||||
// 3. Return the BrowserServer interface
|
||||
const browserServer = new _utilsBundle.ws.EventEmitter();
|
||||
browserServer.wsEndpoint = () => wsEndpoint;
|
||||
browserServer.close = () => device.close();
|
||||
browserServer.kill = () => device.close();
|
||||
device.on('close', () => {
|
||||
server.close();
|
||||
browserServer.emit('close');
|
||||
});
|
||||
return browserServer;
|
||||
}
|
||||
}
|
||||
exports.AndroidServerLauncherImpl = AndroidServerLauncherImpl;
|
||||
101
node_modules/playwright-core/lib/browserServerImpl.js
generated
vendored
Normal file
101
node_modules/playwright-core/lib/browserServerImpl.js
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.BrowserServerLauncherImpl = void 0;
|
||||
var _socksProxy = require("./server/utils/socksProxy");
|
||||
var _playwrightServer = require("./remote/playwrightServer");
|
||||
var _helper = require("./server/helper");
|
||||
var _instrumentation = require("./server/instrumentation");
|
||||
var _playwright = require("./server/playwright");
|
||||
var _crypto = require("./server/utils/crypto");
|
||||
var _stackTrace = require("./utils/isomorphic/stackTrace");
|
||||
var _utilsBundle = require("./utilsBundle");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class BrowserServerLauncherImpl {
|
||||
constructor(browserName) {
|
||||
this._browserName = void 0;
|
||||
this._browserName = browserName;
|
||||
}
|
||||
async launchServer(options = {}) {
|
||||
const playwright = (0, _playwright.createPlaywright)({
|
||||
sdkLanguage: 'javascript',
|
||||
isServer: true
|
||||
});
|
||||
// TODO: enable socks proxy once ipv6 is supported.
|
||||
const socksProxy = false ? new _socksProxy.SocksProxy() : undefined;
|
||||
playwright.options.socksProxyPort = await (socksProxy === null || socksProxy === void 0 ? void 0 : socksProxy.listen(0));
|
||||
|
||||
// 1. Pre-launch the browser
|
||||
const metadata = (0, _instrumentation.serverSideCallMetadata)();
|
||||
const browser = await playwright[this._browserName].launch(metadata, {
|
||||
...options,
|
||||
ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined,
|
||||
ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs),
|
||||
env: options.env ? envObjectToArray(options.env) : undefined
|
||||
}, toProtocolLogger(options.logger)).catch(e => {
|
||||
const log = _helper.helper.formatBrowserLogs(metadata.log);
|
||||
(0, _stackTrace.rewriteErrorMessage)(e, `${e.message} Failed to launch browser.${log}`);
|
||||
throw e;
|
||||
});
|
||||
const path = options.wsPath ? options.wsPath.startsWith('/') ? options.wsPath : `/${options.wsPath}` : `/${(0, _crypto.createGuid)()}`;
|
||||
|
||||
// 2. Start the server
|
||||
const server = new _playwrightServer.PlaywrightServer({
|
||||
mode: 'launchServer',
|
||||
path,
|
||||
maxConnections: Infinity,
|
||||
preLaunchedBrowser: browser,
|
||||
preLaunchedSocksProxy: socksProxy
|
||||
});
|
||||
const wsEndpoint = await server.listen(options.port, options.host);
|
||||
|
||||
// 3. Return the BrowserServer interface
|
||||
const browserServer = new _utilsBundle.ws.EventEmitter();
|
||||
browserServer.process = () => browser.options.browserProcess.process;
|
||||
browserServer.wsEndpoint = () => wsEndpoint;
|
||||
browserServer.close = () => browser.options.browserProcess.close();
|
||||
browserServer[Symbol.asyncDispose] = browserServer.close;
|
||||
browserServer.kill = () => browser.options.browserProcess.kill();
|
||||
browserServer._disconnectForTest = () => server.close();
|
||||
browserServer._userDataDirForTest = browser._userDataDirForTest;
|
||||
browser.options.browserProcess.onclose = (exitCode, signal) => {
|
||||
socksProxy === null || socksProxy === void 0 || socksProxy.close().catch(() => {});
|
||||
server.close();
|
||||
browserServer.emit('close', exitCode, signal);
|
||||
};
|
||||
return browserServer;
|
||||
}
|
||||
}
|
||||
exports.BrowserServerLauncherImpl = BrowserServerLauncherImpl;
|
||||
function toProtocolLogger(logger) {
|
||||
return logger ? (direction, message) => {
|
||||
if (logger.isEnabled('protocol', 'verbose')) logger.log('protocol', 'verbose', (direction === 'send' ? 'SEND ► ' : '◀ RECV ') + JSON.stringify(message), [], {});
|
||||
} : undefined;
|
||||
}
|
||||
function envObjectToArray(env) {
|
||||
const result = [];
|
||||
for (const name in env) {
|
||||
if (!Object.is(env[name], undefined)) result.push({
|
||||
name,
|
||||
value: String(env[name])
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
95
node_modules/playwright-core/lib/cli/driver.js
generated
vendored
Normal file
95
node_modules/playwright-core/lib/cli/driver.js
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.launchBrowserServer = launchBrowserServer;
|
||||
exports.printApiJson = printApiJson;
|
||||
exports.runDriver = runDriver;
|
||||
exports.runServer = runServer;
|
||||
var _fs = _interopRequireDefault(require("fs"));
|
||||
var playwright = _interopRequireWildcard(require("../.."));
|
||||
var _pipeTransport = require("../server/utils/pipeTransport");
|
||||
var _playwrightServer = require("../remote/playwrightServer");
|
||||
var _server = require("../server");
|
||||
var _processLauncher = require("../server/utils/processLauncher");
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable no-console */
|
||||
|
||||
function printApiJson() {
|
||||
// Note: this file is generated by build-playwright-driver.sh
|
||||
console.log(JSON.stringify(require('../../api.json')));
|
||||
}
|
||||
function runDriver() {
|
||||
const dispatcherConnection = new _server.DispatcherConnection();
|
||||
new _server.RootDispatcher(dispatcherConnection, async (rootScope, {
|
||||
sdkLanguage
|
||||
}) => {
|
||||
const playwright = (0, _server.createPlaywright)({
|
||||
sdkLanguage
|
||||
});
|
||||
return new _server.PlaywrightDispatcher(rootScope, playwright);
|
||||
});
|
||||
const transport = new _pipeTransport.PipeTransport(process.stdout, process.stdin);
|
||||
transport.onmessage = message => dispatcherConnection.dispatch(JSON.parse(message));
|
||||
// Certain Language Binding JSON parsers (e.g. .NET) do not like strings with lone surrogates.
|
||||
const isJavaScriptLanguageBinding = !process.env.PW_LANG_NAME || process.env.PW_LANG_NAME === 'javascript';
|
||||
const replacer = !isJavaScriptLanguageBinding && String.prototype.toWellFormed ? (key, value) => {
|
||||
if (typeof value === 'string') return value.toWellFormed();
|
||||
return value;
|
||||
} : undefined;
|
||||
dispatcherConnection.onmessage = message => transport.send(JSON.stringify(message, replacer));
|
||||
transport.onclose = () => {
|
||||
// Drop any messages during shutdown on the floor.
|
||||
dispatcherConnection.onmessage = () => {};
|
||||
(0, _processLauncher.gracefullyProcessExitDoNotHang)(0);
|
||||
};
|
||||
// Ignore the SIGINT signal in the driver process so the parent can gracefully close the connection.
|
||||
// We still will destruct everything (close browsers and exit) when the transport pipe closes.
|
||||
process.on('SIGINT', () => {
|
||||
// Keep the process running.
|
||||
});
|
||||
}
|
||||
async function runServer(options) {
|
||||
const {
|
||||
port,
|
||||
host,
|
||||
path = '/',
|
||||
maxConnections = Infinity,
|
||||
extension
|
||||
} = options;
|
||||
const server = new _playwrightServer.PlaywrightServer({
|
||||
mode: extension ? 'extension' : 'default',
|
||||
path,
|
||||
maxConnections
|
||||
});
|
||||
const wsEndpoint = await server.listen(port, host);
|
||||
process.on('exit', () => server.close().catch(console.error));
|
||||
console.log('Listening on ' + wsEndpoint);
|
||||
process.stdin.on('close', () => (0, _processLauncher.gracefullyProcessExitDoNotHang)(0));
|
||||
}
|
||||
async function launchBrowserServer(browserName, configFile) {
|
||||
let options = {};
|
||||
if (configFile) options = JSON.parse(_fs.default.readFileSync(configFile).toString());
|
||||
const browserType = playwright[browserName];
|
||||
const server = await browserType.launchServer(options);
|
||||
console.log(server.wsEndpoint());
|
||||
}
|
||||
583
node_modules/playwright-core/lib/cli/program.js
generated
vendored
Normal file
583
node_modules/playwright-core/lib/cli/program.js
generated
vendored
Normal file
@@ -0,0 +1,583 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "program", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _utilsBundle.program;
|
||||
}
|
||||
});
|
||||
var _fs = _interopRequireDefault(require("fs"));
|
||||
var _os = _interopRequireDefault(require("os"));
|
||||
var _path = _interopRequireDefault(require("path"));
|
||||
var playwright = _interopRequireWildcard(require("../.."));
|
||||
var _driver = require("./driver");
|
||||
var _server = require("../server");
|
||||
var _utils = require("../utils");
|
||||
var _traceViewer = require("../server/trace/viewer/traceViewer");
|
||||
var _ascii = require("../server/utils/ascii");
|
||||
var _utilsBundle = require("../utilsBundle");
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable no-console */
|
||||
|
||||
const packageJSON = require('../../package.json');
|
||||
_utilsBundle.program.version('Version ' + (process.env.PW_CLI_DISPLAY_VERSION || packageJSON.version)).name(buildBasePlaywrightCLICommand(process.env.PW_LANG_NAME));
|
||||
_utilsBundle.program.command('mark-docker-image [dockerImageNameTemplate]', {
|
||||
hidden: true
|
||||
}).description('mark docker image').allowUnknownOption(true).action(function (dockerImageNameTemplate) {
|
||||
(0, _utils.assert)(dockerImageNameTemplate, 'dockerImageNameTemplate is required');
|
||||
(0, _server.writeDockerVersion)(dockerImageNameTemplate).catch(logErrorAndExit);
|
||||
});
|
||||
commandWithOpenOptions('open [url]', 'open page in browser specified via -b, --browser', []).action(function (url, options) {
|
||||
open(options, url, codegenId()).catch(logErrorAndExit);
|
||||
}).addHelpText('afterAll', `
|
||||
Examples:
|
||||
|
||||
$ open
|
||||
$ open -b webkit https://example.com`);
|
||||
commandWithOpenOptions('codegen [url]', 'open page and generate code for user actions', [['-o, --output <file name>', 'saves the generated script to a file'], ['--target <language>', `language to generate, one of javascript, playwright-test, python, python-async, python-pytest, csharp, csharp-mstest, csharp-nunit, java, java-junit`, codegenId()], ['--test-id-attribute <attributeName>', 'use the specified attribute to generate data test ID selectors']]).action(function (url, options) {
|
||||
codegen(options, url).catch(logErrorAndExit);
|
||||
}).addHelpText('afterAll', `
|
||||
Examples:
|
||||
|
||||
$ codegen
|
||||
$ codegen --target=python
|
||||
$ codegen -b webkit https://example.com`);
|
||||
function suggestedBrowsersToInstall() {
|
||||
return _server.registry.executables().filter(e => e.installType !== 'none' && e.type !== 'tool').map(e => e.name).join(', ');
|
||||
}
|
||||
function defaultBrowsersToInstall(options) {
|
||||
let executables = _server.registry.defaultExecutables();
|
||||
if (options.noShell) executables = executables.filter(e => e.name !== 'chromium-headless-shell');
|
||||
if (options.onlyShell) executables = executables.filter(e => e.name !== 'chromium');
|
||||
return executables;
|
||||
}
|
||||
function checkBrowsersToInstall(args, options) {
|
||||
if (options.noShell && options.onlyShell) throw new Error(`Only one of --no-shell and --only-shell can be specified`);
|
||||
const faultyArguments = [];
|
||||
const executables = [];
|
||||
const handleArgument = arg => {
|
||||
const executable = _server.registry.findExecutable(arg);
|
||||
if (!executable || executable.installType === 'none') faultyArguments.push(arg);else executables.push(executable);
|
||||
if ((executable === null || executable === void 0 ? void 0 : executable.browserName) === 'chromium') executables.push(_server.registry.findExecutable('ffmpeg'));
|
||||
};
|
||||
for (const arg of args) {
|
||||
if (arg === 'chromium') {
|
||||
if (!options.onlyShell) handleArgument('chromium');
|
||||
if (!options.noShell) handleArgument('chromium-headless-shell');
|
||||
} else {
|
||||
handleArgument(arg);
|
||||
}
|
||||
}
|
||||
if (process.platform === 'win32') executables.push(_server.registry.findExecutable('winldd'));
|
||||
if (faultyArguments.length) throw new Error(`Invalid installation targets: ${faultyArguments.map(name => `'${name}'`).join(', ')}. Expecting one of: ${suggestedBrowsersToInstall()}`);
|
||||
return executables;
|
||||
}
|
||||
_utilsBundle.program.command('install [browser...]').description('ensure browsers necessary for this version of Playwright are installed').option('--with-deps', 'install system dependencies for browsers').option('--dry-run', 'do not execute installation, only print information').option('--force', 'force reinstall of stable browser channels').option('--only-shell', 'only install headless shell when installing chromium').option('--no-shell', 'do not install chromium headless shell').action(async function (args, options) {
|
||||
// For '--no-shell' option, commander sets `shell: false` instead.
|
||||
if (options.shell === false) options.noShell = true;
|
||||
if ((0, _utils.isLikelyNpxGlobal)()) {
|
||||
console.error((0, _ascii.wrapInASCIIBox)([`WARNING: It looks like you are running 'npx playwright install' without first`, `installing your project's dependencies.`, ``, `To avoid unexpected behavior, please install your dependencies first, and`, `then run Playwright's install command:`, ``, ` npm install`, ` npx playwright install`, ``, `If your project does not yet depend on Playwright, first install the`, `applicable npm package (most commonly @playwright/test), and`, `then run Playwright's install command to download the browsers:`, ``, ` npm install @playwright/test`, ` npx playwright install`, ``].join('\n'), 1));
|
||||
}
|
||||
try {
|
||||
const hasNoArguments = !args.length;
|
||||
const executables = hasNoArguments ? defaultBrowsersToInstall(options) : checkBrowsersToInstall(args, options);
|
||||
if (options.withDeps) await _server.registry.installDeps(executables, !!options.dryRun);
|
||||
if (options.dryRun) {
|
||||
for (const executable of executables) {
|
||||
var _executable$directory, _executable$downloadU;
|
||||
const version = executable.browserVersion ? `version ` + executable.browserVersion : '';
|
||||
console.log(`browser: ${executable.name}${version ? ' ' + version : ''}`);
|
||||
console.log(` Install location: ${(_executable$directory = executable.directory) !== null && _executable$directory !== void 0 ? _executable$directory : '<system>'}`);
|
||||
if ((_executable$downloadU = executable.downloadURLs) !== null && _executable$downloadU !== void 0 && _executable$downloadU.length) {
|
||||
const [url, ...fallbacks] = executable.downloadURLs;
|
||||
console.log(` Download url: ${url}`);
|
||||
for (let i = 0; i < fallbacks.length; ++i) console.log(` Download fallback ${i + 1}: ${fallbacks[i]}`);
|
||||
}
|
||||
console.log(``);
|
||||
}
|
||||
} else {
|
||||
const forceReinstall = hasNoArguments ? false : !!options.force;
|
||||
await _server.registry.install(executables, forceReinstall);
|
||||
await _server.registry.validateHostRequirementsForExecutablesIfNeeded(executables, process.env.PW_LANG_NAME || 'javascript').catch(e => {
|
||||
e.name = 'Playwright Host validation warning';
|
||||
console.error(e);
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(`Failed to install browsers\n${e}`);
|
||||
(0, _utils.gracefullyProcessExitDoNotHang)(1);
|
||||
}
|
||||
}).addHelpText('afterAll', `
|
||||
|
||||
Examples:
|
||||
- $ install
|
||||
Install default browsers.
|
||||
|
||||
- $ install chrome firefox
|
||||
Install custom browsers, supports ${suggestedBrowsersToInstall()}.`);
|
||||
_utilsBundle.program.command('uninstall').description('Removes browsers used by this installation of Playwright from the system (chromium, firefox, webkit, ffmpeg). This does not include branded channels.').option('--all', 'Removes all browsers used by any Playwright installation from the system.').action(async options => {
|
||||
delete process.env.PLAYWRIGHT_SKIP_BROWSER_GC;
|
||||
await _server.registry.uninstall(!!options.all).then(({
|
||||
numberOfBrowsersLeft
|
||||
}) => {
|
||||
if (!options.all && numberOfBrowsersLeft > 0) {
|
||||
console.log('Successfully uninstalled Playwright browsers for the current Playwright installation.');
|
||||
console.log(`There are still ${numberOfBrowsersLeft} browsers left, used by other Playwright installations.\nTo uninstall Playwright browsers for all installations, re-run with --all flag.`);
|
||||
}
|
||||
}).catch(logErrorAndExit);
|
||||
});
|
||||
_utilsBundle.program.command('install-deps [browser...]').description('install dependencies necessary to run browsers (will ask for sudo permissions)').option('--dry-run', 'Do not execute installation commands, only print them').action(async function (args, options) {
|
||||
try {
|
||||
if (!args.length) await _server.registry.installDeps(defaultBrowsersToInstall({}), !!options.dryRun);else await _server.registry.installDeps(checkBrowsersToInstall(args, {}), !!options.dryRun);
|
||||
} catch (e) {
|
||||
console.log(`Failed to install browser dependencies\n${e}`);
|
||||
(0, _utils.gracefullyProcessExitDoNotHang)(1);
|
||||
}
|
||||
}).addHelpText('afterAll', `
|
||||
Examples:
|
||||
- $ install-deps
|
||||
Install dependencies for default browsers.
|
||||
|
||||
- $ install-deps chrome firefox
|
||||
Install dependencies for specific browsers, supports ${suggestedBrowsersToInstall()}.`);
|
||||
const browsers = [{
|
||||
alias: 'cr',
|
||||
name: 'Chromium',
|
||||
type: 'chromium'
|
||||
}, {
|
||||
alias: 'ff',
|
||||
name: 'Firefox',
|
||||
type: 'firefox'
|
||||
}, {
|
||||
alias: 'wk',
|
||||
name: 'WebKit',
|
||||
type: 'webkit'
|
||||
}];
|
||||
for (const {
|
||||
alias,
|
||||
name,
|
||||
type
|
||||
} of browsers) {
|
||||
commandWithOpenOptions(`${alias} [url]`, `open page in ${name}`, []).action(function (url, options) {
|
||||
open({
|
||||
...options,
|
||||
browser: type
|
||||
}, url, options.target).catch(logErrorAndExit);
|
||||
}).addHelpText('afterAll', `
|
||||
Examples:
|
||||
|
||||
$ ${alias} https://example.com`);
|
||||
}
|
||||
commandWithOpenOptions('screenshot <url> <filename>', 'capture a page screenshot', [['--wait-for-selector <selector>', 'wait for selector before taking a screenshot'], ['--wait-for-timeout <timeout>', 'wait for timeout in milliseconds before taking a screenshot'], ['--full-page', 'whether to take a full page screenshot (entire scrollable area)']]).action(function (url, filename, command) {
|
||||
screenshot(command, command, url, filename).catch(logErrorAndExit);
|
||||
}).addHelpText('afterAll', `
|
||||
Examples:
|
||||
|
||||
$ screenshot -b webkit https://example.com example.png`);
|
||||
commandWithOpenOptions('pdf <url> <filename>', 'save page as pdf', [['--wait-for-selector <selector>', 'wait for given selector before saving as pdf'], ['--wait-for-timeout <timeout>', 'wait for given timeout in milliseconds before saving as pdf']]).action(function (url, filename, options) {
|
||||
pdf(options, options, url, filename).catch(logErrorAndExit);
|
||||
}).addHelpText('afterAll', `
|
||||
Examples:
|
||||
|
||||
$ pdf https://example.com example.pdf`);
|
||||
_utilsBundle.program.command('run-driver', {
|
||||
hidden: true
|
||||
}).action(function (options) {
|
||||
(0, _driver.runDriver)();
|
||||
});
|
||||
_utilsBundle.program.command('run-server').option('--port <port>', 'Server port').option('--host <host>', 'Server host').option('--path <path>', 'Endpoint Path', '/').option('--max-clients <maxClients>', 'Maximum clients').option('--mode <mode>', 'Server mode, either "default" or "extension"').action(function (options) {
|
||||
(0, _driver.runServer)({
|
||||
port: options.port ? +options.port : undefined,
|
||||
host: options.host,
|
||||
path: options.path,
|
||||
maxConnections: options.maxClients ? +options.maxClients : Infinity,
|
||||
extension: options.mode === 'extension' || !!process.env.PW_EXTENSION_MODE
|
||||
}).catch(logErrorAndExit);
|
||||
});
|
||||
_utilsBundle.program.command('print-api-json', {
|
||||
hidden: true
|
||||
}).action(function (options) {
|
||||
(0, _driver.printApiJson)();
|
||||
});
|
||||
_utilsBundle.program.command('launch-server', {
|
||||
hidden: true
|
||||
}).requiredOption('--browser <browserName>', 'Browser name, one of "chromium", "firefox" or "webkit"').option('--config <path-to-config-file>', 'JSON file with launchServer options').action(function (options) {
|
||||
(0, _driver.launchBrowserServer)(options.browser, options.config);
|
||||
});
|
||||
_utilsBundle.program.command('show-trace [trace...]').option('-b, --browser <browserType>', 'browser to use, one of cr, chromium, ff, firefox, wk, webkit', 'chromium').option('-h, --host <host>', 'Host to serve trace on; specifying this option opens trace in a browser tab').option('-p, --port <port>', 'Port to serve trace on, 0 for any free port; specifying this option opens trace in a browser tab').option('--stdin', 'Accept trace URLs over stdin to update the viewer').description('show trace viewer').action(function (traces, options) {
|
||||
if (options.browser === 'cr') options.browser = 'chromium';
|
||||
if (options.browser === 'ff') options.browser = 'firefox';
|
||||
if (options.browser === 'wk') options.browser = 'webkit';
|
||||
const openOptions = {
|
||||
host: options.host,
|
||||
port: +options.port,
|
||||
isServer: !!options.stdin
|
||||
};
|
||||
if (options.port !== undefined || options.host !== undefined) (0, _traceViewer.runTraceInBrowser)(traces, openOptions).catch(logErrorAndExit);else (0, _traceViewer.runTraceViewerApp)(traces, options.browser, openOptions, true).catch(logErrorAndExit);
|
||||
}).addHelpText('afterAll', `
|
||||
Examples:
|
||||
|
||||
$ show-trace https://example.com/trace.zip`);
|
||||
async function launchContext(options, extraOptions) {
|
||||
validateOptions(options);
|
||||
const browserType = lookupBrowserType(options);
|
||||
const launchOptions = extraOptions;
|
||||
if (options.channel) launchOptions.channel = options.channel;
|
||||
launchOptions.handleSIGINT = false;
|
||||
const contextOptions =
|
||||
// Copy the device descriptor since we have to compare and modify the options.
|
||||
options.device ? {
|
||||
...playwright.devices[options.device]
|
||||
} : {};
|
||||
|
||||
// In headful mode, use host device scale factor for things to look nice.
|
||||
// In headless, keep things the way it works in Playwright by default.
|
||||
// Assume high-dpi on MacOS. TODO: this is not perfect.
|
||||
if (!extraOptions.headless) contextOptions.deviceScaleFactor = _os.default.platform() === 'darwin' ? 2 : 1;
|
||||
|
||||
// Work around the WebKit GTK scrolling issue.
|
||||
if (browserType.name() === 'webkit' && process.platform === 'linux') {
|
||||
delete contextOptions.hasTouch;
|
||||
delete contextOptions.isMobile;
|
||||
}
|
||||
if (contextOptions.isMobile && browserType.name() === 'firefox') contextOptions.isMobile = undefined;
|
||||
if (options.blockServiceWorkers) contextOptions.serviceWorkers = 'block';
|
||||
|
||||
// Proxy
|
||||
|
||||
if (options.proxyServer) {
|
||||
launchOptions.proxy = {
|
||||
server: options.proxyServer
|
||||
};
|
||||
if (options.proxyBypass) launchOptions.proxy.bypass = options.proxyBypass;
|
||||
}
|
||||
const browser = await browserType.launch(launchOptions);
|
||||
if (process.env.PWTEST_CLI_IS_UNDER_TEST) {
|
||||
process._didSetSourcesForTest = text => {
|
||||
process.stdout.write('\n-------------8<-------------\n');
|
||||
process.stdout.write(text);
|
||||
process.stdout.write('\n-------------8<-------------\n');
|
||||
const autoExitCondition = process.env.PWTEST_CLI_AUTO_EXIT_WHEN;
|
||||
if (autoExitCondition && text.includes(autoExitCondition)) closeBrowser();
|
||||
};
|
||||
// Make sure we exit abnormally when browser crashes.
|
||||
const logs = [];
|
||||
require('playwright-core/lib/utilsBundle').debug.log = (...args) => {
|
||||
const line = require('util').format(...args) + '\n';
|
||||
logs.push(line);
|
||||
process.stderr.write(line);
|
||||
};
|
||||
browser.on('disconnected', () => {
|
||||
const hasCrashLine = logs.some(line => line.includes('process did exit:') && !line.includes('process did exit: exitCode=0, signal=null'));
|
||||
if (hasCrashLine) {
|
||||
process.stderr.write('Detected browser crash.\n');
|
||||
(0, _utils.gracefullyProcessExitDoNotHang)(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Viewport size
|
||||
if (options.viewportSize) {
|
||||
try {
|
||||
const [width, height] = options.viewportSize.split(',').map(n => +n);
|
||||
if (isNaN(width) || isNaN(height)) throw new Error('bad values');
|
||||
contextOptions.viewport = {
|
||||
width,
|
||||
height
|
||||
};
|
||||
} catch (e) {
|
||||
throw new Error('Invalid viewport size format: use "width,height", for example --viewport-size="800,600"');
|
||||
}
|
||||
}
|
||||
|
||||
// Geolocation
|
||||
|
||||
if (options.geolocation) {
|
||||
try {
|
||||
const [latitude, longitude] = options.geolocation.split(',').map(n => parseFloat(n.trim()));
|
||||
contextOptions.geolocation = {
|
||||
latitude,
|
||||
longitude
|
||||
};
|
||||
} catch (e) {
|
||||
throw new Error('Invalid geolocation format, should be "lat,long". For example --geolocation="37.819722,-122.478611"');
|
||||
}
|
||||
contextOptions.permissions = ['geolocation'];
|
||||
}
|
||||
|
||||
// User agent
|
||||
|
||||
if (options.userAgent) contextOptions.userAgent = options.userAgent;
|
||||
|
||||
// Lang
|
||||
|
||||
if (options.lang) contextOptions.locale = options.lang;
|
||||
|
||||
// Color scheme
|
||||
|
||||
if (options.colorScheme) contextOptions.colorScheme = options.colorScheme;
|
||||
|
||||
// Timezone
|
||||
|
||||
if (options.timezone) contextOptions.timezoneId = options.timezone;
|
||||
|
||||
// Storage
|
||||
|
||||
if (options.loadStorage) contextOptions.storageState = options.loadStorage;
|
||||
if (options.ignoreHttpsErrors) contextOptions.ignoreHTTPSErrors = true;
|
||||
|
||||
// HAR
|
||||
|
||||
if (options.saveHar) {
|
||||
contextOptions.recordHar = {
|
||||
path: _path.default.resolve(process.cwd(), options.saveHar),
|
||||
mode: 'minimal'
|
||||
};
|
||||
if (options.saveHarGlob) contextOptions.recordHar.urlFilter = options.saveHarGlob;
|
||||
contextOptions.serviceWorkers = 'block';
|
||||
}
|
||||
|
||||
// Close app when the last window closes.
|
||||
|
||||
const context = await browser.newContext(contextOptions);
|
||||
let closingBrowser = false;
|
||||
async function closeBrowser() {
|
||||
// We can come here multiple times. For example, saving storage creates
|
||||
// a temporary page and we call closeBrowser again when that page closes.
|
||||
if (closingBrowser) return;
|
||||
closingBrowser = true;
|
||||
if (options.saveStorage) await context.storageState({
|
||||
path: options.saveStorage
|
||||
}).catch(e => null);
|
||||
if (options.saveHar) await context.close();
|
||||
await browser.close();
|
||||
}
|
||||
context.on('page', page => {
|
||||
page.on('dialog', () => {}); // Prevent dialogs from being automatically dismissed.
|
||||
page.on('close', () => {
|
||||
const hasPage = browser.contexts().some(context => context.pages().length > 0);
|
||||
if (hasPage) return;
|
||||
// Avoid the error when the last page is closed because the browser has been closed.
|
||||
closeBrowser().catch(() => {});
|
||||
});
|
||||
});
|
||||
process.on('SIGINT', async () => {
|
||||
await closeBrowser();
|
||||
(0, _utils.gracefullyProcessExitDoNotHang)(130);
|
||||
});
|
||||
const timeout = options.timeout ? parseInt(options.timeout, 10) : 0;
|
||||
context.setDefaultTimeout(timeout);
|
||||
context.setDefaultNavigationTimeout(timeout);
|
||||
|
||||
// Omit options that we add automatically for presentation purpose.
|
||||
delete launchOptions.headless;
|
||||
delete launchOptions.executablePath;
|
||||
delete launchOptions.handleSIGINT;
|
||||
delete contextOptions.deviceScaleFactor;
|
||||
return {
|
||||
browser,
|
||||
browserName: browserType.name(),
|
||||
context,
|
||||
contextOptions,
|
||||
launchOptions
|
||||
};
|
||||
}
|
||||
async function openPage(context, url) {
|
||||
const page = await context.newPage();
|
||||
if (url) {
|
||||
if (_fs.default.existsSync(url)) url = 'file://' + _path.default.resolve(url);else if (!url.startsWith('http') && !url.startsWith('file://') && !url.startsWith('about:') && !url.startsWith('data:')) url = 'http://' + url;
|
||||
await page.goto(url).catch(error => {
|
||||
if (process.env.PWTEST_CLI_AUTO_EXIT_WHEN) {
|
||||
// Tests with PWTEST_CLI_AUTO_EXIT_WHEN might close page too fast, resulting
|
||||
// in a stray navigation aborted error. We should ignore it.
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
return page;
|
||||
}
|
||||
async function open(options, url, language) {
|
||||
const {
|
||||
context,
|
||||
launchOptions,
|
||||
contextOptions
|
||||
} = await launchContext(options, {
|
||||
headless: !!process.env.PWTEST_CLI_HEADLESS,
|
||||
executablePath: process.env.PWTEST_CLI_EXECUTABLE_PATH
|
||||
});
|
||||
await context._enableRecorder({
|
||||
language,
|
||||
launchOptions,
|
||||
contextOptions,
|
||||
device: options.device,
|
||||
saveStorage: options.saveStorage,
|
||||
handleSIGINT: false
|
||||
});
|
||||
await openPage(context, url);
|
||||
}
|
||||
async function codegen(options, url) {
|
||||
const {
|
||||
target: language,
|
||||
output: outputFile,
|
||||
testIdAttribute: testIdAttributeName
|
||||
} = options;
|
||||
const tracesDir = _path.default.join(_os.default.tmpdir(), `playwright-recorder-trace-${Date.now()}`);
|
||||
const {
|
||||
context,
|
||||
launchOptions,
|
||||
contextOptions
|
||||
} = await launchContext(options, {
|
||||
headless: !!process.env.PWTEST_CLI_HEADLESS,
|
||||
executablePath: process.env.PWTEST_CLI_EXECUTABLE_PATH,
|
||||
tracesDir
|
||||
});
|
||||
_utilsBundle.dotenv.config({
|
||||
path: 'playwright.env'
|
||||
});
|
||||
await context._enableRecorder({
|
||||
language,
|
||||
launchOptions,
|
||||
contextOptions,
|
||||
device: options.device,
|
||||
saveStorage: options.saveStorage,
|
||||
mode: 'recording',
|
||||
testIdAttributeName,
|
||||
outputFile: outputFile ? _path.default.resolve(outputFile) : undefined,
|
||||
handleSIGINT: false
|
||||
});
|
||||
await openPage(context, url);
|
||||
}
|
||||
async function waitForPage(page, captureOptions) {
|
||||
if (captureOptions.waitForSelector) {
|
||||
console.log(`Waiting for selector ${captureOptions.waitForSelector}...`);
|
||||
await page.waitForSelector(captureOptions.waitForSelector);
|
||||
}
|
||||
if (captureOptions.waitForTimeout) {
|
||||
console.log(`Waiting for timeout ${captureOptions.waitForTimeout}...`);
|
||||
await page.waitForTimeout(parseInt(captureOptions.waitForTimeout, 10));
|
||||
}
|
||||
}
|
||||
async function screenshot(options, captureOptions, url, path) {
|
||||
const {
|
||||
context
|
||||
} = await launchContext(options, {
|
||||
headless: true
|
||||
});
|
||||
console.log('Navigating to ' + url);
|
||||
const page = await openPage(context, url);
|
||||
await waitForPage(page, captureOptions);
|
||||
console.log('Capturing screenshot into ' + path);
|
||||
await page.screenshot({
|
||||
path,
|
||||
fullPage: !!captureOptions.fullPage
|
||||
});
|
||||
// launchContext takes care of closing the browser.
|
||||
await page.close();
|
||||
}
|
||||
async function pdf(options, captureOptions, url, path) {
|
||||
if (options.browser !== 'chromium') throw new Error('PDF creation is only working with Chromium');
|
||||
const {
|
||||
context
|
||||
} = await launchContext({
|
||||
...options,
|
||||
browser: 'chromium'
|
||||
}, {
|
||||
headless: true
|
||||
});
|
||||
console.log('Navigating to ' + url);
|
||||
const page = await openPage(context, url);
|
||||
await waitForPage(page, captureOptions);
|
||||
console.log('Saving as pdf into ' + path);
|
||||
await page.pdf({
|
||||
path
|
||||
});
|
||||
// launchContext takes care of closing the browser.
|
||||
await page.close();
|
||||
}
|
||||
function lookupBrowserType(options) {
|
||||
let name = options.browser;
|
||||
if (options.device) {
|
||||
const device = playwright.devices[options.device];
|
||||
name = device.defaultBrowserType;
|
||||
}
|
||||
let browserType;
|
||||
switch (name) {
|
||||
case 'chromium':
|
||||
browserType = playwright.chromium;
|
||||
break;
|
||||
case 'webkit':
|
||||
browserType = playwright.webkit;
|
||||
break;
|
||||
case 'firefox':
|
||||
browserType = playwright.firefox;
|
||||
break;
|
||||
case 'cr':
|
||||
browserType = playwright.chromium;
|
||||
break;
|
||||
case 'wk':
|
||||
browserType = playwright.webkit;
|
||||
break;
|
||||
case 'ff':
|
||||
browserType = playwright.firefox;
|
||||
break;
|
||||
}
|
||||
if (browserType) return browserType;
|
||||
_utilsBundle.program.help();
|
||||
}
|
||||
function validateOptions(options) {
|
||||
if (options.device && !(options.device in playwright.devices)) {
|
||||
const lines = [`Device descriptor not found: '${options.device}', available devices are:`];
|
||||
for (const name in playwright.devices) lines.push(` "${name}"`);
|
||||
throw new Error(lines.join('\n'));
|
||||
}
|
||||
if (options.colorScheme && !['light', 'dark'].includes(options.colorScheme)) throw new Error('Invalid color scheme, should be one of "light", "dark"');
|
||||
}
|
||||
function logErrorAndExit(e) {
|
||||
if (process.env.PWDEBUGIMPL) console.error(e);else console.error(e.name + ': ' + e.message);
|
||||
(0, _utils.gracefullyProcessExitDoNotHang)(1);
|
||||
}
|
||||
function codegenId() {
|
||||
return process.env.PW_LANG_NAME || 'playwright-test';
|
||||
}
|
||||
function commandWithOpenOptions(command, description, options) {
|
||||
let result = _utilsBundle.program.command(command).description(description);
|
||||
for (const option of options) result = result.option(option[0], ...option.slice(1));
|
||||
return result.option('-b, --browser <browserType>', 'browser to use, one of cr, chromium, ff, firefox, wk, webkit', 'chromium').option('--block-service-workers', 'block service workers').option('--channel <channel>', 'Chromium distribution channel, "chrome", "chrome-beta", "msedge-dev", etc').option('--color-scheme <scheme>', 'emulate preferred color scheme, "light" or "dark"').option('--device <deviceName>', 'emulate device, for example "iPhone 11"').option('--geolocation <coordinates>', 'specify geolocation coordinates, for example "37.819722,-122.478611"').option('--ignore-https-errors', 'ignore https errors').option('--load-storage <filename>', 'load context storage state from the file, previously saved with --save-storage').option('--lang <language>', 'specify language / locale, for example "en-GB"').option('--proxy-server <proxy>', 'specify proxy server, for example "http://myproxy:3128" or "socks5://myproxy:8080"').option('--proxy-bypass <bypass>', 'comma-separated domains to bypass proxy, for example ".com,chromium.org,.domain.com"').option('--save-har <filename>', 'save HAR file with all network activity at the end').option('--save-har-glob <glob pattern>', 'filter entries in the HAR by matching url against this glob pattern').option('--save-storage <filename>', 'save context storage state at the end, for later use with --load-storage').option('--timezone <time zone>', 'time zone to emulate, for example "Europe/Rome"').option('--timeout <timeout>', 'timeout for Playwright actions in milliseconds, no timeout by default').option('--user-agent <ua string>', 'specify user agent string').option('--viewport-size <size>', 'specify browser viewport size in pixels, for example "1280, 720"');
|
||||
}
|
||||
function buildBasePlaywrightCLICommand(cliTargetLang) {
|
||||
switch (cliTargetLang) {
|
||||
case 'python':
|
||||
return `playwright`;
|
||||
case 'java':
|
||||
return `mvn exec:java -e -D exec.mainClass=com.microsoft.playwright.CLI -D exec.args="...options.."`;
|
||||
case 'csharp':
|
||||
return `pwsh bin/Debug/netX/playwright.ps1`;
|
||||
default:
|
||||
{
|
||||
const packageManagerCommand = (0, _utils.getPackageManagerExecCommand)();
|
||||
return `${packageManagerCommand} playwright`;
|
||||
}
|
||||
}
|
||||
}
|
||||
68
node_modules/playwright-core/lib/cli/programWithTestStub.js
generated
vendored
Normal file
68
node_modules/playwright-core/lib/cli/programWithTestStub.js
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "program", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _program.program;
|
||||
}
|
||||
});
|
||||
var _processLauncher = require("../server/utils/processLauncher");
|
||||
var _utils = require("../utils");
|
||||
var _program = require("./program");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable no-console */
|
||||
|
||||
function printPlaywrightTestError(command) {
|
||||
const packages = [];
|
||||
for (const pkg of ['playwright', 'playwright-chromium', 'playwright-firefox', 'playwright-webkit']) {
|
||||
try {
|
||||
require.resolve(pkg);
|
||||
packages.push(pkg);
|
||||
} catch (e) {}
|
||||
}
|
||||
if (!packages.length) packages.push('playwright');
|
||||
const packageManager = (0, _utils.getPackageManager)();
|
||||
if (packageManager === 'yarn') {
|
||||
console.error(`Please install @playwright/test package before running "yarn playwright ${command}"`);
|
||||
console.error(` yarn remove ${packages.join(' ')}`);
|
||||
console.error(' yarn add -D @playwright/test');
|
||||
} else if (packageManager === 'pnpm') {
|
||||
console.error(`Please install @playwright/test package before running "pnpm exec playwright ${command}"`);
|
||||
console.error(` pnpm remove ${packages.join(' ')}`);
|
||||
console.error(' pnpm add -D @playwright/test');
|
||||
} else {
|
||||
console.error(`Please install @playwright/test package before running "npx playwright ${command}"`);
|
||||
console.error(` npm uninstall ${packages.join(' ')}`);
|
||||
console.error(' npm install -D @playwright/test');
|
||||
}
|
||||
}
|
||||
const kExternalPlaywrightTestCommands = [['test', 'Run tests with Playwright Test.'], ['show-report', 'Show Playwright Test HTML report.'], ['merge-reports', 'Merge Playwright Test Blob reports']];
|
||||
function addExternalPlaywrightTestCommands() {
|
||||
for (const [command, description] of kExternalPlaywrightTestCommands) {
|
||||
const playwrightTest = _program.program.command(command).allowUnknownOption(true);
|
||||
playwrightTest.description(`${description} Available in @playwright/test package.`);
|
||||
playwrightTest.action(async () => {
|
||||
printPlaywrightTestError(command);
|
||||
(0, _processLauncher.gracefullyProcessExitDoNotHang)(1);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!process.env.PW_LANG_NAME) addExternalPlaywrightTestCommands();
|
||||
50
node_modules/playwright-core/lib/client/accessibility.js
generated
vendored
Normal file
50
node_modules/playwright-core/lib/client/accessibility.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Accessibility = void 0;
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
function axNodeFromProtocol(axNode) {
|
||||
const result = {
|
||||
...axNode,
|
||||
value: axNode.valueNumber !== undefined ? axNode.valueNumber : axNode.valueString,
|
||||
checked: axNode.checked === 'checked' ? true : axNode.checked === 'unchecked' ? false : axNode.checked,
|
||||
pressed: axNode.pressed === 'pressed' ? true : axNode.pressed === 'released' ? false : axNode.pressed,
|
||||
children: axNode.children ? axNode.children.map(axNodeFromProtocol) : undefined
|
||||
};
|
||||
delete result.valueNumber;
|
||||
delete result.valueString;
|
||||
return result;
|
||||
}
|
||||
class Accessibility {
|
||||
constructor(channel) {
|
||||
this._channel = void 0;
|
||||
this._channel = channel;
|
||||
}
|
||||
async snapshot(options = {}) {
|
||||
const root = options.root ? options.root._elementChannel : undefined;
|
||||
const result = await this._channel.accessibilitySnapshot({
|
||||
interestingOnly: options.interestingOnly,
|
||||
root
|
||||
});
|
||||
return result.rootAXNode ? axNodeFromProtocol(result.rootAXNode) : null;
|
||||
}
|
||||
}
|
||||
exports.Accessibility = Accessibility;
|
||||
452
node_modules/playwright-core/lib/client/android.js
generated
vendored
Normal file
452
node_modules/playwright-core/lib/client/android.js
generated
vendored
Normal file
@@ -0,0 +1,452 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.AndroidWebView = exports.AndroidSocket = exports.AndroidInput = exports.AndroidDevice = exports.Android = void 0;
|
||||
var _eventEmitter = require("./eventEmitter");
|
||||
var _browserContext = require("./browserContext");
|
||||
var _channelOwner = require("./channelOwner");
|
||||
var _errors = require("./errors");
|
||||
var _events = require("./events");
|
||||
var _waiter = require("./waiter");
|
||||
var _timeoutSettings = require("./timeoutSettings");
|
||||
var _rtti = require("../utils/isomorphic/rtti");
|
||||
var _time = require("../utils/isomorphic/time");
|
||||
var _timeoutRunner = require("../utils/isomorphic/timeoutRunner");
|
||||
var _webSocket = require("./webSocket");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Android extends _channelOwner.ChannelOwner {
|
||||
static from(android) {
|
||||
return android._object;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._timeoutSettings = void 0;
|
||||
this._serverLauncher = void 0;
|
||||
this._timeoutSettings = new _timeoutSettings.TimeoutSettings(this._platform);
|
||||
}
|
||||
setDefaultTimeout(timeout) {
|
||||
this._timeoutSettings.setDefaultTimeout(timeout);
|
||||
this._wrapApiCall(async () => {
|
||||
await this._channel.setDefaultTimeoutNoReply({
|
||||
timeout
|
||||
});
|
||||
}, true).catch(() => {});
|
||||
}
|
||||
async devices(options = {}) {
|
||||
const {
|
||||
devices
|
||||
} = await this._channel.devices(options);
|
||||
return devices.map(d => AndroidDevice.from(d));
|
||||
}
|
||||
async launchServer(options = {}) {
|
||||
if (!this._serverLauncher) throw new Error('Launching server is not supported');
|
||||
return await this._serverLauncher.launchServer(options);
|
||||
}
|
||||
async connect(wsEndpoint, options = {}) {
|
||||
return await this._wrapApiCall(async () => {
|
||||
const deadline = options.timeout ? (0, _time.monotonicTime)() + options.timeout : 0;
|
||||
const headers = {
|
||||
'x-playwright-browser': 'android',
|
||||
...options.headers
|
||||
};
|
||||
const connectParams = {
|
||||
wsEndpoint,
|
||||
headers,
|
||||
slowMo: options.slowMo,
|
||||
timeout: options.timeout
|
||||
};
|
||||
const connection = await (0, _webSocket.connectOverWebSocket)(this._connection, connectParams);
|
||||
let device;
|
||||
connection.on('close', () => {
|
||||
var _device;
|
||||
(_device = device) === null || _device === void 0 || _device._didClose();
|
||||
});
|
||||
const result = await (0, _timeoutRunner.raceAgainstDeadline)(async () => {
|
||||
const playwright = await connection.initializePlaywright();
|
||||
if (!playwright._initializer.preConnectedAndroidDevice) {
|
||||
connection.close();
|
||||
throw new Error('Malformed endpoint. Did you use Android.launchServer method?');
|
||||
}
|
||||
device = AndroidDevice.from(playwright._initializer.preConnectedAndroidDevice);
|
||||
device._shouldCloseConnectionOnClose = true;
|
||||
device.on(_events.Events.AndroidDevice.Close, () => connection.close());
|
||||
return device;
|
||||
}, deadline);
|
||||
if (!result.timedOut) {
|
||||
return result.result;
|
||||
} else {
|
||||
connection.close();
|
||||
throw new Error(`Timeout ${options.timeout}ms exceeded`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.Android = Android;
|
||||
class AndroidDevice extends _channelOwner.ChannelOwner {
|
||||
static from(androidDevice) {
|
||||
return androidDevice._object;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._timeoutSettings = void 0;
|
||||
this._webViews = new Map();
|
||||
this._shouldCloseConnectionOnClose = false;
|
||||
this.input = void 0;
|
||||
this.input = new AndroidInput(this);
|
||||
this._timeoutSettings = new _timeoutSettings.TimeoutSettings(this._platform, parent._timeoutSettings);
|
||||
this._channel.on('webViewAdded', ({
|
||||
webView
|
||||
}) => this._onWebViewAdded(webView));
|
||||
this._channel.on('webViewRemoved', ({
|
||||
socketName
|
||||
}) => this._onWebViewRemoved(socketName));
|
||||
this._channel.on('close', () => this._didClose());
|
||||
}
|
||||
_onWebViewAdded(webView) {
|
||||
const view = new AndroidWebView(this, webView);
|
||||
this._webViews.set(webView.socketName, view);
|
||||
this.emit(_events.Events.AndroidDevice.WebView, view);
|
||||
}
|
||||
_onWebViewRemoved(socketName) {
|
||||
const view = this._webViews.get(socketName);
|
||||
this._webViews.delete(socketName);
|
||||
if (view) view.emit(_events.Events.AndroidWebView.Close);
|
||||
}
|
||||
setDefaultTimeout(timeout) {
|
||||
this._timeoutSettings.setDefaultTimeout(timeout);
|
||||
this._wrapApiCall(async () => {
|
||||
await this._channel.setDefaultTimeoutNoReply({
|
||||
timeout
|
||||
});
|
||||
}, true).catch(() => {});
|
||||
}
|
||||
serial() {
|
||||
return this._initializer.serial;
|
||||
}
|
||||
model() {
|
||||
return this._initializer.model;
|
||||
}
|
||||
webViews() {
|
||||
return [...this._webViews.values()];
|
||||
}
|
||||
async webView(selector, options) {
|
||||
const predicate = v => {
|
||||
if (selector.pkg) return v.pkg() === selector.pkg;
|
||||
if (selector.socketName) return v._socketName() === selector.socketName;
|
||||
return false;
|
||||
};
|
||||
const webView = [...this._webViews.values()].find(predicate);
|
||||
if (webView) return webView;
|
||||
return await this.waitForEvent('webview', {
|
||||
...options,
|
||||
predicate
|
||||
});
|
||||
}
|
||||
async wait(selector, options) {
|
||||
await this._channel.wait({
|
||||
selector: toSelectorChannel(selector),
|
||||
...options
|
||||
});
|
||||
}
|
||||
async fill(selector, text, options) {
|
||||
await this._channel.fill({
|
||||
selector: toSelectorChannel(selector),
|
||||
text,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async press(selector, key, options) {
|
||||
await this.tap(selector, options);
|
||||
await this.input.press(key);
|
||||
}
|
||||
async tap(selector, options) {
|
||||
await this._channel.tap({
|
||||
selector: toSelectorChannel(selector),
|
||||
...options
|
||||
});
|
||||
}
|
||||
async drag(selector, dest, options) {
|
||||
await this._channel.drag({
|
||||
selector: toSelectorChannel(selector),
|
||||
dest,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async fling(selector, direction, options) {
|
||||
await this._channel.fling({
|
||||
selector: toSelectorChannel(selector),
|
||||
direction,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async longTap(selector, options) {
|
||||
await this._channel.longTap({
|
||||
selector: toSelectorChannel(selector),
|
||||
...options
|
||||
});
|
||||
}
|
||||
async pinchClose(selector, percent, options) {
|
||||
await this._channel.pinchClose({
|
||||
selector: toSelectorChannel(selector),
|
||||
percent,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async pinchOpen(selector, percent, options) {
|
||||
await this._channel.pinchOpen({
|
||||
selector: toSelectorChannel(selector),
|
||||
percent,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async scroll(selector, direction, percent, options) {
|
||||
await this._channel.scroll({
|
||||
selector: toSelectorChannel(selector),
|
||||
direction,
|
||||
percent,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async swipe(selector, direction, percent, options) {
|
||||
await this._channel.swipe({
|
||||
selector: toSelectorChannel(selector),
|
||||
direction,
|
||||
percent,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async info(selector) {
|
||||
return (await this._channel.info({
|
||||
selector: toSelectorChannel(selector)
|
||||
})).info;
|
||||
}
|
||||
async screenshot(options = {}) {
|
||||
const {
|
||||
binary
|
||||
} = await this._channel.screenshot();
|
||||
if (options.path) await this._platform.fs().promises.writeFile(options.path, binary);
|
||||
return binary;
|
||||
}
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.close();
|
||||
}
|
||||
async close() {
|
||||
try {
|
||||
if (this._shouldCloseConnectionOnClose) this._connection.close();else await this._channel.close();
|
||||
} catch (e) {
|
||||
if ((0, _errors.isTargetClosedError)(e)) return;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
_didClose() {
|
||||
this.emit(_events.Events.AndroidDevice.Close, this);
|
||||
}
|
||||
async shell(command) {
|
||||
const {
|
||||
result
|
||||
} = await this._channel.shell({
|
||||
command
|
||||
});
|
||||
return result;
|
||||
}
|
||||
async open(command) {
|
||||
return AndroidSocket.from((await this._channel.open({
|
||||
command
|
||||
})).socket);
|
||||
}
|
||||
async installApk(file, options) {
|
||||
await this._channel.installApk({
|
||||
file: await loadFile(this._platform, file),
|
||||
args: options && options.args
|
||||
});
|
||||
}
|
||||
async push(file, path, options) {
|
||||
await this._channel.push({
|
||||
file: await loadFile(this._platform, file),
|
||||
path,
|
||||
mode: options ? options.mode : undefined
|
||||
});
|
||||
}
|
||||
async launchBrowser(options = {}) {
|
||||
const contextOptions = await (0, _browserContext.prepareBrowserContextParams)(this._platform, options);
|
||||
const result = await this._channel.launchBrowser(contextOptions);
|
||||
const context = _browserContext.BrowserContext.from(result.context);
|
||||
context._setOptions(contextOptions, {});
|
||||
return context;
|
||||
}
|
||||
async waitForEvent(event, optionsOrPredicate = {}) {
|
||||
return await this._wrapApiCall(async () => {
|
||||
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
||||
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
|
||||
const waiter = _waiter.Waiter.createForEvent(this, event);
|
||||
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
|
||||
if (event !== _events.Events.AndroidDevice.Close) waiter.rejectOnEvent(this, _events.Events.AndroidDevice.Close, () => new _errors.TargetClosedError());
|
||||
const result = await waiter.waitForEvent(this, event, predicate);
|
||||
waiter.dispose();
|
||||
return result;
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.AndroidDevice = AndroidDevice;
|
||||
class AndroidSocket extends _channelOwner.ChannelOwner {
|
||||
static from(androidDevice) {
|
||||
return androidDevice._object;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._channel.on('data', ({
|
||||
data
|
||||
}) => this.emit(_events.Events.AndroidSocket.Data, data));
|
||||
this._channel.on('close', () => this.emit(_events.Events.AndroidSocket.Close));
|
||||
}
|
||||
async write(data) {
|
||||
await this._channel.write({
|
||||
data
|
||||
});
|
||||
}
|
||||
async close() {
|
||||
await this._channel.close();
|
||||
}
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.close();
|
||||
}
|
||||
}
|
||||
exports.AndroidSocket = AndroidSocket;
|
||||
async function loadFile(platform, file) {
|
||||
if ((0, _rtti.isString)(file)) return await platform.fs().promises.readFile(file);
|
||||
return file;
|
||||
}
|
||||
class AndroidInput {
|
||||
constructor(device) {
|
||||
this._device = void 0;
|
||||
this._device = device;
|
||||
}
|
||||
async type(text) {
|
||||
await this._device._channel.inputType({
|
||||
text
|
||||
});
|
||||
}
|
||||
async press(key) {
|
||||
await this._device._channel.inputPress({
|
||||
key
|
||||
});
|
||||
}
|
||||
async tap(point) {
|
||||
await this._device._channel.inputTap({
|
||||
point
|
||||
});
|
||||
}
|
||||
async swipe(from, segments, steps) {
|
||||
await this._device._channel.inputSwipe({
|
||||
segments,
|
||||
steps
|
||||
});
|
||||
}
|
||||
async drag(from, to, steps) {
|
||||
await this._device._channel.inputDrag({
|
||||
from,
|
||||
to,
|
||||
steps
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.AndroidInput = AndroidInput;
|
||||
function toSelectorChannel(selector) {
|
||||
const {
|
||||
checkable,
|
||||
checked,
|
||||
clazz,
|
||||
clickable,
|
||||
depth,
|
||||
desc,
|
||||
enabled,
|
||||
focusable,
|
||||
focused,
|
||||
hasChild,
|
||||
hasDescendant,
|
||||
longClickable,
|
||||
pkg,
|
||||
res,
|
||||
scrollable,
|
||||
selected,
|
||||
text
|
||||
} = selector;
|
||||
const toRegex = value => {
|
||||
if (value === undefined) return undefined;
|
||||
if ((0, _rtti.isRegExp)(value)) return value.source;
|
||||
return '^' + value.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d') + '$';
|
||||
};
|
||||
return {
|
||||
checkable,
|
||||
checked,
|
||||
clazz: toRegex(clazz),
|
||||
pkg: toRegex(pkg),
|
||||
desc: toRegex(desc),
|
||||
res: toRegex(res),
|
||||
text: toRegex(text),
|
||||
clickable,
|
||||
depth,
|
||||
enabled,
|
||||
focusable,
|
||||
focused,
|
||||
hasChild: hasChild ? {
|
||||
selector: toSelectorChannel(hasChild.selector)
|
||||
} : undefined,
|
||||
hasDescendant: hasDescendant ? {
|
||||
selector: toSelectorChannel(hasDescendant.selector),
|
||||
maxDepth: hasDescendant.maxDepth
|
||||
} : undefined,
|
||||
longClickable,
|
||||
scrollable,
|
||||
selected
|
||||
};
|
||||
}
|
||||
class AndroidWebView extends _eventEmitter.EventEmitter {
|
||||
constructor(device, data) {
|
||||
super(device._platform);
|
||||
this._device = void 0;
|
||||
this._data = void 0;
|
||||
this._pagePromise = void 0;
|
||||
this._device = device;
|
||||
this._data = data;
|
||||
}
|
||||
pid() {
|
||||
return this._data.pid;
|
||||
}
|
||||
pkg() {
|
||||
return this._data.pkg;
|
||||
}
|
||||
_socketName() {
|
||||
return this._data.socketName;
|
||||
}
|
||||
async page() {
|
||||
if (!this._pagePromise) this._pagePromise = this._fetchPage();
|
||||
return await this._pagePromise;
|
||||
}
|
||||
async _fetchPage() {
|
||||
const {
|
||||
context
|
||||
} = await this._device._channel.connectToWebView({
|
||||
socketName: this._data.socketName
|
||||
});
|
||||
return _browserContext.BrowserContext.from(context).pages()[0];
|
||||
}
|
||||
}
|
||||
exports.AndroidWebView = AndroidWebView;
|
||||
285
node_modules/playwright-core/lib/client/api.js
generated
vendored
Normal file
285
node_modules/playwright-core/lib/client/api.js
generated
vendored
Normal file
@@ -0,0 +1,285 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
Object.defineProperty(exports, "APIRequest", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _fetch.APIRequest;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "APIRequestContext", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _fetch.APIRequestContext;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "APIResponse", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _fetch.APIResponse;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Accessibility", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _accessibility.Accessibility;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Android", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _android.Android;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "AndroidDevice", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _android.AndroidDevice;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "AndroidInput", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _android.AndroidInput;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "AndroidSocket", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _android.AndroidSocket;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "AndroidWebView", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _android.AndroidWebView;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Browser", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _browser.Browser;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "BrowserContext", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _browserContext.BrowserContext;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "BrowserType", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _browserType.BrowserType;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "CDPSession", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _cdpSession.CDPSession;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Clock", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _clock.Clock;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "ConsoleMessage", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _consoleMessage.ConsoleMessage;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Coverage", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _coverage.Coverage;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Dialog", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _dialog.Dialog;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Download", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _download.Download;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Electron", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _electron.Electron;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "ElectronApplication", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _electron.ElectronApplication;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "ElementHandle", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _elementHandle.ElementHandle;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "FileChooser", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _fileChooser.FileChooser;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Frame", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _frame.Frame;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "FrameLocator", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _locator.FrameLocator;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "JSHandle", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _jsHandle.JSHandle;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Keyboard", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _input.Keyboard;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Locator", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _locator.Locator;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Mouse", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _input.Mouse;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Page", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _page.Page;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Playwright", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _playwright.Playwright;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Request", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _network.Request;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Response", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _network.Response;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Route", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _network.Route;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Selectors", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _selectors.Selectors;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "TimeoutError", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _errors.TimeoutError;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Touchscreen", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _input.Touchscreen;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Tracing", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _tracing.Tracing;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Video", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _video.Video;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "WebError", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _webError.WebError;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "WebSocket", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _network.WebSocket;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "WebSocketRoute", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _network.WebSocketRoute;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "Worker", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _worker.Worker;
|
||||
}
|
||||
});
|
||||
var _accessibility = require("./accessibility");
|
||||
var _android = require("./android");
|
||||
var _browser = require("./browser");
|
||||
var _browserContext = require("./browserContext");
|
||||
var _browserType = require("./browserType");
|
||||
var _clock = require("./clock");
|
||||
var _consoleMessage = require("./consoleMessage");
|
||||
var _coverage = require("./coverage");
|
||||
var _dialog = require("./dialog");
|
||||
var _download = require("./download");
|
||||
var _electron = require("./electron");
|
||||
var _locator = require("./locator");
|
||||
var _elementHandle = require("./elementHandle");
|
||||
var _fileChooser = require("./fileChooser");
|
||||
var _errors = require("./errors");
|
||||
var _frame = require("./frame");
|
||||
var _input = require("./input");
|
||||
var _jsHandle = require("./jsHandle");
|
||||
var _network = require("./network");
|
||||
var _fetch = require("./fetch");
|
||||
var _page = require("./page");
|
||||
var _selectors = require("./selectors");
|
||||
var _tracing = require("./tracing");
|
||||
var _video = require("./video");
|
||||
var _worker = require("./worker");
|
||||
var _cdpSession = require("./cdpSession");
|
||||
var _playwright = require("./playwright");
|
||||
var _webError = require("./webError");
|
||||
76
node_modules/playwright-core/lib/client/artifact.js
generated
vendored
Normal file
76
node_modules/playwright-core/lib/client/artifact.js
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Artifact = void 0;
|
||||
var _channelOwner = require("./channelOwner");
|
||||
var _stream = require("./stream");
|
||||
var _fileUtils = require("./fileUtils");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Artifact extends _channelOwner.ChannelOwner {
|
||||
static from(channel) {
|
||||
return channel._object;
|
||||
}
|
||||
async pathAfterFinished() {
|
||||
if (this._connection.isRemote()) throw new Error(`Path is not available when connecting remotely. Use saveAs() to save a local copy.`);
|
||||
return (await this._channel.pathAfterFinished()).value;
|
||||
}
|
||||
async saveAs(path) {
|
||||
if (!this._connection.isRemote()) {
|
||||
await this._channel.saveAs({
|
||||
path
|
||||
});
|
||||
return;
|
||||
}
|
||||
const result = await this._channel.saveAsStream();
|
||||
const stream = _stream.Stream.from(result.stream);
|
||||
await (0, _fileUtils.mkdirIfNeeded)(this._platform, path);
|
||||
await new Promise((resolve, reject) => {
|
||||
stream.stream().pipe(this._platform.fs().createWriteStream(path)).on('finish', resolve).on('error', reject);
|
||||
});
|
||||
}
|
||||
async failure() {
|
||||
return (await this._channel.failure()).error || null;
|
||||
}
|
||||
async createReadStream() {
|
||||
const result = await this._channel.stream();
|
||||
const stream = _stream.Stream.from(result.stream);
|
||||
return stream.stream();
|
||||
}
|
||||
async readIntoBuffer() {
|
||||
const stream = await this.createReadStream();
|
||||
return await new Promise((resolve, reject) => {
|
||||
const chunks = [];
|
||||
stream.on('data', chunk => {
|
||||
chunks.push(chunk);
|
||||
});
|
||||
stream.on('end', () => {
|
||||
resolve(Buffer.concat(chunks));
|
||||
});
|
||||
stream.on('error', reject);
|
||||
});
|
||||
}
|
||||
async cancel() {
|
||||
return await this._channel.cancel();
|
||||
}
|
||||
async delete() {
|
||||
return await this._channel.delete();
|
||||
}
|
||||
}
|
||||
exports.Artifact = Artifact;
|
||||
140
node_modules/playwright-core/lib/client/browser.js
generated
vendored
Normal file
140
node_modules/playwright-core/lib/client/browser.js
generated
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Browser = void 0;
|
||||
var _artifact = require("./artifact");
|
||||
var _browserContext = require("./browserContext");
|
||||
var _cdpSession = require("./cdpSession");
|
||||
var _channelOwner = require("./channelOwner");
|
||||
var _errors = require("./errors");
|
||||
var _events = require("./events");
|
||||
var _fileUtils = require("./fileUtils");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Browser extends _channelOwner.ChannelOwner {
|
||||
static from(browser) {
|
||||
return browser._object;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._contexts = new Set();
|
||||
this._isConnected = true;
|
||||
this._closedPromise = void 0;
|
||||
this._shouldCloseConnectionOnClose = false;
|
||||
this._browserType = void 0;
|
||||
this._options = {};
|
||||
this._name = void 0;
|
||||
this._path = void 0;
|
||||
this._closeReason = void 0;
|
||||
this._name = initializer.name;
|
||||
this._channel.on('close', () => this._didClose());
|
||||
this._closedPromise = new Promise(f => this.once(_events.Events.Browser.Disconnected, f));
|
||||
}
|
||||
browserType() {
|
||||
return this._browserType;
|
||||
}
|
||||
async newContext(options = {}) {
|
||||
return await this._innerNewContext(options, false);
|
||||
}
|
||||
async _newContextForReuse(options = {}) {
|
||||
return await this._wrapApiCall(async () => {
|
||||
for (const context of this._contexts) {
|
||||
await this._browserType._willCloseContext(context);
|
||||
for (const page of context.pages()) page._onClose();
|
||||
context._onClose();
|
||||
}
|
||||
return await this._innerNewContext(options, true);
|
||||
}, true);
|
||||
}
|
||||
async _stopPendingOperations(reason) {
|
||||
return await this._wrapApiCall(async () => {
|
||||
await this._channel.stopPendingOperations({
|
||||
reason
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
async _innerNewContext(options = {}, forReuse) {
|
||||
options = {
|
||||
...this._browserType._playwright._defaultContextOptions,
|
||||
...options
|
||||
};
|
||||
const contextOptions = await (0, _browserContext.prepareBrowserContextParams)(this._platform, options);
|
||||
const response = forReuse ? await this._channel.newContextForReuse(contextOptions) : await this._channel.newContext(contextOptions);
|
||||
const context = _browserContext.BrowserContext.from(response.context);
|
||||
await this._browserType._didCreateContext(context, contextOptions, this._options, options.logger || this._logger);
|
||||
return context;
|
||||
}
|
||||
contexts() {
|
||||
return [...this._contexts];
|
||||
}
|
||||
version() {
|
||||
return this._initializer.version;
|
||||
}
|
||||
async newPage(options = {}) {
|
||||
return await this._wrapApiCall(async () => {
|
||||
const context = await this.newContext(options);
|
||||
const page = await context.newPage();
|
||||
page._ownedContext = context;
|
||||
context._ownerPage = page;
|
||||
return page;
|
||||
});
|
||||
}
|
||||
isConnected() {
|
||||
return this._isConnected;
|
||||
}
|
||||
async newBrowserCDPSession() {
|
||||
return _cdpSession.CDPSession.from((await this._channel.newBrowserCDPSession()).session);
|
||||
}
|
||||
async startTracing(page, options = {}) {
|
||||
this._path = options.path;
|
||||
await this._channel.startTracing({
|
||||
...options,
|
||||
page: page ? page._channel : undefined
|
||||
});
|
||||
}
|
||||
async stopTracing() {
|
||||
const artifact = _artifact.Artifact.from((await this._channel.stopTracing()).artifact);
|
||||
const buffer = await artifact.readIntoBuffer();
|
||||
await artifact.delete();
|
||||
if (this._path) {
|
||||
await (0, _fileUtils.mkdirIfNeeded)(this._platform, this._path);
|
||||
await this._platform.fs().promises.writeFile(this._path, buffer);
|
||||
this._path = undefined;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.close();
|
||||
}
|
||||
async close(options = {}) {
|
||||
this._closeReason = options.reason;
|
||||
try {
|
||||
if (this._shouldCloseConnectionOnClose) this._connection.close();else await this._channel.close(options);
|
||||
await this._closedPromise;
|
||||
} catch (e) {
|
||||
if ((0, _errors.isTargetClosedError)(e)) return;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
_didClose() {
|
||||
this._isConnected = false;
|
||||
this.emit(_events.Events.Browser.Disconnected, this);
|
||||
}
|
||||
}
|
||||
exports.Browser = Browser;
|
||||
566
node_modules/playwright-core/lib/client/browserContext.js
generated
vendored
Normal file
566
node_modules/playwright-core/lib/client/browserContext.js
generated
vendored
Normal file
@@ -0,0 +1,566 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.BrowserContext = void 0;
|
||||
exports.prepareBrowserContextParams = prepareBrowserContextParams;
|
||||
exports.toClientCertificatesProtocol = toClientCertificatesProtocol;
|
||||
var _artifact = require("./artifact");
|
||||
var _browser = require("./browser");
|
||||
var _cdpSession = require("./cdpSession");
|
||||
var _channelOwner = require("./channelOwner");
|
||||
var _clientHelper = require("./clientHelper");
|
||||
var _clock = require("./clock");
|
||||
var _consoleMessage = require("./consoleMessage");
|
||||
var _dialog = require("./dialog");
|
||||
var _errors = require("./errors");
|
||||
var _events = require("./events");
|
||||
var _fetch = require("./fetch");
|
||||
var _frame = require("./frame");
|
||||
var _harRouter = require("./harRouter");
|
||||
var network = _interopRequireWildcard(require("./network"));
|
||||
var _page = require("./page");
|
||||
var _tracing = require("./tracing");
|
||||
var _waiter = require("./waiter");
|
||||
var _webError = require("./webError");
|
||||
var _worker = require("./worker");
|
||||
var _timeoutSettings = require("./timeoutSettings");
|
||||
var _fileUtils = require("./fileUtils");
|
||||
var _headers = require("../utils/isomorphic/headers");
|
||||
var _urlMatch = require("../utils/isomorphic/urlMatch");
|
||||
var _rtti = require("../utils/isomorphic/rtti");
|
||||
var _stackTrace = require("../utils/isomorphic/stackTrace");
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class BrowserContext extends _channelOwner.ChannelOwner {
|
||||
static from(context) {
|
||||
return context._object;
|
||||
}
|
||||
static fromNullable(context) {
|
||||
return context ? BrowserContext.from(context) : null;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
var _this$_browser, _this$_browser2;
|
||||
super(parent, type, guid, initializer);
|
||||
this._pages = new Set();
|
||||
this._routes = [];
|
||||
this._webSocketRoutes = [];
|
||||
this._browser = null;
|
||||
this._browserType = void 0;
|
||||
this._bindings = new Map();
|
||||
this._timeoutSettings = void 0;
|
||||
this._ownerPage = void 0;
|
||||
this._closedPromise = void 0;
|
||||
this._options = {};
|
||||
this.request = void 0;
|
||||
this.tracing = void 0;
|
||||
this.clock = void 0;
|
||||
this._backgroundPages = new Set();
|
||||
this._serviceWorkers = new Set();
|
||||
this._isChromium = void 0;
|
||||
this._harRecorders = new Map();
|
||||
this._closeWasCalled = false;
|
||||
this._closeReason = void 0;
|
||||
this._harRouters = [];
|
||||
this._timeoutSettings = new _timeoutSettings.TimeoutSettings(this._platform);
|
||||
if (parent instanceof _browser.Browser) this._browser = parent;
|
||||
(_this$_browser = this._browser) === null || _this$_browser === void 0 || _this$_browser._contexts.add(this);
|
||||
this._isChromium = ((_this$_browser2 = this._browser) === null || _this$_browser2 === void 0 ? void 0 : _this$_browser2._name) === 'chromium';
|
||||
this.tracing = _tracing.Tracing.from(initializer.tracing);
|
||||
this.request = _fetch.APIRequestContext.from(initializer.requestContext);
|
||||
this.clock = new _clock.Clock(this);
|
||||
this._channel.on('bindingCall', ({
|
||||
binding
|
||||
}) => this._onBinding(_page.BindingCall.from(binding)));
|
||||
this._channel.on('close', () => this._onClose());
|
||||
this._channel.on('page', ({
|
||||
page
|
||||
}) => this._onPage(_page.Page.from(page)));
|
||||
this._channel.on('route', ({
|
||||
route
|
||||
}) => this._onRoute(network.Route.from(route)));
|
||||
this._channel.on('webSocketRoute', ({
|
||||
webSocketRoute
|
||||
}) => this._onWebSocketRoute(network.WebSocketRoute.from(webSocketRoute)));
|
||||
this._channel.on('backgroundPage', ({
|
||||
page
|
||||
}) => {
|
||||
const backgroundPage = _page.Page.from(page);
|
||||
this._backgroundPages.add(backgroundPage);
|
||||
this.emit(_events.Events.BrowserContext.BackgroundPage, backgroundPage);
|
||||
});
|
||||
this._channel.on('serviceWorker', ({
|
||||
worker
|
||||
}) => {
|
||||
const serviceWorker = _worker.Worker.from(worker);
|
||||
serviceWorker._context = this;
|
||||
this._serviceWorkers.add(serviceWorker);
|
||||
this.emit(_events.Events.BrowserContext.ServiceWorker, serviceWorker);
|
||||
});
|
||||
this._channel.on('console', event => {
|
||||
const consoleMessage = new _consoleMessage.ConsoleMessage(this._platform, event);
|
||||
this.emit(_events.Events.BrowserContext.Console, consoleMessage);
|
||||
const page = consoleMessage.page();
|
||||
if (page) page.emit(_events.Events.Page.Console, consoleMessage);
|
||||
});
|
||||
this._channel.on('pageError', ({
|
||||
error,
|
||||
page
|
||||
}) => {
|
||||
const pageObject = _page.Page.from(page);
|
||||
const parsedError = (0, _errors.parseError)(error);
|
||||
this.emit(_events.Events.BrowserContext.WebError, new _webError.WebError(pageObject, parsedError));
|
||||
if (pageObject) pageObject.emit(_events.Events.Page.PageError, parsedError);
|
||||
});
|
||||
this._channel.on('dialog', ({
|
||||
dialog
|
||||
}) => {
|
||||
const dialogObject = _dialog.Dialog.from(dialog);
|
||||
let hasListeners = this.emit(_events.Events.BrowserContext.Dialog, dialogObject);
|
||||
const page = dialogObject.page();
|
||||
if (page) hasListeners = page.emit(_events.Events.Page.Dialog, dialogObject) || hasListeners;
|
||||
if (!hasListeners) {
|
||||
// Although we do similar handling on the server side, we still need this logic
|
||||
// on the client side due to a possible race condition between two async calls:
|
||||
// a) removing "dialog" listener subscription (client->server)
|
||||
// b) actual "dialog" event (server->client)
|
||||
if (dialogObject.type() === 'beforeunload') dialog.accept({}).catch(() => {});else dialog.dismiss().catch(() => {});
|
||||
}
|
||||
});
|
||||
this._channel.on('request', ({
|
||||
request,
|
||||
page
|
||||
}) => this._onRequest(network.Request.from(request), _page.Page.fromNullable(page)));
|
||||
this._channel.on('requestFailed', ({
|
||||
request,
|
||||
failureText,
|
||||
responseEndTiming,
|
||||
page
|
||||
}) => this._onRequestFailed(network.Request.from(request), responseEndTiming, failureText, _page.Page.fromNullable(page)));
|
||||
this._channel.on('requestFinished', params => this._onRequestFinished(params));
|
||||
this._channel.on('response', ({
|
||||
response,
|
||||
page
|
||||
}) => this._onResponse(network.Response.from(response), _page.Page.fromNullable(page)));
|
||||
this._closedPromise = new Promise(f => this.once(_events.Events.BrowserContext.Close, f));
|
||||
this._setEventToSubscriptionMapping(new Map([[_events.Events.BrowserContext.Console, 'console'], [_events.Events.BrowserContext.Dialog, 'dialog'], [_events.Events.BrowserContext.Request, 'request'], [_events.Events.BrowserContext.Response, 'response'], [_events.Events.BrowserContext.RequestFinished, 'requestFinished'], [_events.Events.BrowserContext.RequestFailed, 'requestFailed']]));
|
||||
}
|
||||
_setOptions(contextOptions, browserOptions) {
|
||||
this._options = contextOptions;
|
||||
if (this._options.recordHar) this._harRecorders.set('', {
|
||||
path: this._options.recordHar.path,
|
||||
content: this._options.recordHar.content
|
||||
});
|
||||
this.tracing._tracesDir = browserOptions.tracesDir;
|
||||
}
|
||||
_onPage(page) {
|
||||
this._pages.add(page);
|
||||
this.emit(_events.Events.BrowserContext.Page, page);
|
||||
if (page._opener && !page._opener.isClosed()) page._opener.emit(_events.Events.Page.Popup, page);
|
||||
}
|
||||
_onRequest(request, page) {
|
||||
this.emit(_events.Events.BrowserContext.Request, request);
|
||||
if (page) page.emit(_events.Events.Page.Request, request);
|
||||
}
|
||||
_onResponse(response, page) {
|
||||
this.emit(_events.Events.BrowserContext.Response, response);
|
||||
if (page) page.emit(_events.Events.Page.Response, response);
|
||||
}
|
||||
_onRequestFailed(request, responseEndTiming, failureText, page) {
|
||||
request._failureText = failureText || null;
|
||||
request._setResponseEndTiming(responseEndTiming);
|
||||
this.emit(_events.Events.BrowserContext.RequestFailed, request);
|
||||
if (page) page.emit(_events.Events.Page.RequestFailed, request);
|
||||
}
|
||||
_onRequestFinished(params) {
|
||||
const {
|
||||
responseEndTiming
|
||||
} = params;
|
||||
const request = network.Request.from(params.request);
|
||||
const response = network.Response.fromNullable(params.response);
|
||||
const page = _page.Page.fromNullable(params.page);
|
||||
request._setResponseEndTiming(responseEndTiming);
|
||||
this.emit(_events.Events.BrowserContext.RequestFinished, request);
|
||||
if (page) page.emit(_events.Events.Page.RequestFinished, request);
|
||||
if (response) response._finishedPromise.resolve(null);
|
||||
}
|
||||
async _onRoute(route) {
|
||||
route._context = this;
|
||||
const page = route.request()._safePage();
|
||||
const routeHandlers = this._routes.slice();
|
||||
for (const routeHandler of routeHandlers) {
|
||||
// If the page or the context was closed we stall all requests right away.
|
||||
if (page !== null && page !== void 0 && page._closeWasCalled || this._closeWasCalled) return;
|
||||
if (!routeHandler.matches(route.request().url())) continue;
|
||||
const index = this._routes.indexOf(routeHandler);
|
||||
if (index === -1) continue;
|
||||
if (routeHandler.willExpire()) this._routes.splice(index, 1);
|
||||
const handled = await routeHandler.handle(route);
|
||||
if (!this._routes.length) this._wrapApiCall(() => this._updateInterceptionPatterns(), true).catch(() => {});
|
||||
if (handled) return;
|
||||
}
|
||||
// If the page is closed or unrouteAll() was called without waiting and interception disabled,
|
||||
// the method will throw an error - silence it.
|
||||
await route._innerContinue(true /* isFallback */).catch(() => {});
|
||||
}
|
||||
async _onWebSocketRoute(webSocketRoute) {
|
||||
const routeHandler = this._webSocketRoutes.find(route => route.matches(webSocketRoute.url()));
|
||||
if (routeHandler) await routeHandler.handle(webSocketRoute);else webSocketRoute.connectToServer();
|
||||
}
|
||||
async _onBinding(bindingCall) {
|
||||
const func = this._bindings.get(bindingCall._initializer.name);
|
||||
if (!func) return;
|
||||
await bindingCall.call(func);
|
||||
}
|
||||
setDefaultNavigationTimeout(timeout) {
|
||||
this._timeoutSettings.setDefaultNavigationTimeout(timeout);
|
||||
this._wrapApiCall(async () => {
|
||||
await this._channel.setDefaultNavigationTimeoutNoReply({
|
||||
timeout
|
||||
});
|
||||
}, true).catch(() => {});
|
||||
}
|
||||
setDefaultTimeout(timeout) {
|
||||
this._timeoutSettings.setDefaultTimeout(timeout);
|
||||
this._wrapApiCall(async () => {
|
||||
await this._channel.setDefaultTimeoutNoReply({
|
||||
timeout
|
||||
});
|
||||
}, true).catch(() => {});
|
||||
}
|
||||
browser() {
|
||||
return this._browser;
|
||||
}
|
||||
pages() {
|
||||
return [...this._pages];
|
||||
}
|
||||
async newPage() {
|
||||
if (this._ownerPage) throw new Error('Please use browser.newContext()');
|
||||
return _page.Page.from((await this._channel.newPage()).page);
|
||||
}
|
||||
async cookies(urls) {
|
||||
if (!urls) urls = [];
|
||||
if (urls && typeof urls === 'string') urls = [urls];
|
||||
return (await this._channel.cookies({
|
||||
urls: urls
|
||||
})).cookies;
|
||||
}
|
||||
async addCookies(cookies) {
|
||||
await this._channel.addCookies({
|
||||
cookies
|
||||
});
|
||||
}
|
||||
async clearCookies(options = {}) {
|
||||
await this._channel.clearCookies({
|
||||
name: (0, _rtti.isString)(options.name) ? options.name : undefined,
|
||||
nameRegexSource: (0, _rtti.isRegExp)(options.name) ? options.name.source : undefined,
|
||||
nameRegexFlags: (0, _rtti.isRegExp)(options.name) ? options.name.flags : undefined,
|
||||
domain: (0, _rtti.isString)(options.domain) ? options.domain : undefined,
|
||||
domainRegexSource: (0, _rtti.isRegExp)(options.domain) ? options.domain.source : undefined,
|
||||
domainRegexFlags: (0, _rtti.isRegExp)(options.domain) ? options.domain.flags : undefined,
|
||||
path: (0, _rtti.isString)(options.path) ? options.path : undefined,
|
||||
pathRegexSource: (0, _rtti.isRegExp)(options.path) ? options.path.source : undefined,
|
||||
pathRegexFlags: (0, _rtti.isRegExp)(options.path) ? options.path.flags : undefined
|
||||
});
|
||||
}
|
||||
async grantPermissions(permissions, options) {
|
||||
await this._channel.grantPermissions({
|
||||
permissions,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async clearPermissions() {
|
||||
await this._channel.clearPermissions();
|
||||
}
|
||||
async setGeolocation(geolocation) {
|
||||
await this._channel.setGeolocation({
|
||||
geolocation: geolocation || undefined
|
||||
});
|
||||
}
|
||||
async setExtraHTTPHeaders(headers) {
|
||||
network.validateHeaders(headers);
|
||||
await this._channel.setExtraHTTPHeaders({
|
||||
headers: (0, _headers.headersObjectToArray)(headers)
|
||||
});
|
||||
}
|
||||
async setOffline(offline) {
|
||||
await this._channel.setOffline({
|
||||
offline
|
||||
});
|
||||
}
|
||||
async setHTTPCredentials(httpCredentials) {
|
||||
await this._channel.setHTTPCredentials({
|
||||
httpCredentials: httpCredentials || undefined
|
||||
});
|
||||
}
|
||||
async addInitScript(script, arg) {
|
||||
const source = await (0, _clientHelper.evaluationScript)(this._platform, script, arg);
|
||||
await this._channel.addInitScript({
|
||||
source
|
||||
});
|
||||
}
|
||||
async exposeBinding(name, callback, options = {}) {
|
||||
await this._channel.exposeBinding({
|
||||
name,
|
||||
needsHandle: options.handle
|
||||
});
|
||||
this._bindings.set(name, callback);
|
||||
}
|
||||
async exposeFunction(name, callback) {
|
||||
await this._channel.exposeBinding({
|
||||
name
|
||||
});
|
||||
const binding = (source, ...args) => callback(...args);
|
||||
this._bindings.set(name, binding);
|
||||
}
|
||||
async route(url, handler, options = {}) {
|
||||
this._routes.unshift(new network.RouteHandler(this._platform, this._options.baseURL, url, handler, options.times));
|
||||
await this._updateInterceptionPatterns();
|
||||
}
|
||||
async routeWebSocket(url, handler) {
|
||||
this._webSocketRoutes.unshift(new network.WebSocketRouteHandler(this._options.baseURL, url, handler));
|
||||
await this._updateWebSocketInterceptionPatterns();
|
||||
}
|
||||
async _recordIntoHAR(har, page, options = {}) {
|
||||
var _options$updateConten, _options$updateMode, _options$updateConten2;
|
||||
const {
|
||||
harId
|
||||
} = await this._channel.harStart({
|
||||
page: page === null || page === void 0 ? void 0 : page._channel,
|
||||
options: prepareRecordHarOptions({
|
||||
path: har,
|
||||
content: (_options$updateConten = options.updateContent) !== null && _options$updateConten !== void 0 ? _options$updateConten : 'attach',
|
||||
mode: (_options$updateMode = options.updateMode) !== null && _options$updateMode !== void 0 ? _options$updateMode : 'minimal',
|
||||
urlFilter: options.url
|
||||
})
|
||||
});
|
||||
this._harRecorders.set(harId, {
|
||||
path: har,
|
||||
content: (_options$updateConten2 = options.updateContent) !== null && _options$updateConten2 !== void 0 ? _options$updateConten2 : 'attach'
|
||||
});
|
||||
}
|
||||
async routeFromHAR(har, options = {}) {
|
||||
const localUtils = this._connection.localUtils();
|
||||
if (!localUtils) throw new Error('Route from har is not supported in thin clients');
|
||||
if (options.update) {
|
||||
await this._recordIntoHAR(har, null, options);
|
||||
return;
|
||||
}
|
||||
const harRouter = await _harRouter.HarRouter.create(localUtils, har, options.notFound || 'abort', {
|
||||
urlMatch: options.url
|
||||
});
|
||||
this._harRouters.push(harRouter);
|
||||
await harRouter.addContextRoute(this);
|
||||
}
|
||||
_disposeHarRouters() {
|
||||
this._harRouters.forEach(router => router.dispose());
|
||||
this._harRouters = [];
|
||||
}
|
||||
async unrouteAll(options) {
|
||||
await this._unrouteInternal(this._routes, [], options === null || options === void 0 ? void 0 : options.behavior);
|
||||
this._disposeHarRouters();
|
||||
}
|
||||
async unroute(url, handler) {
|
||||
const removed = [];
|
||||
const remaining = [];
|
||||
for (const route of this._routes) {
|
||||
if ((0, _urlMatch.urlMatchesEqual)(route.url, url) && (!handler || route.handler === handler)) removed.push(route);else remaining.push(route);
|
||||
}
|
||||
await this._unrouteInternal(removed, remaining, 'default');
|
||||
}
|
||||
async _unrouteInternal(removed, remaining, behavior) {
|
||||
this._routes = remaining;
|
||||
await this._updateInterceptionPatterns();
|
||||
if (!behavior || behavior === 'default') return;
|
||||
const promises = removed.map(routeHandler => routeHandler.stop(behavior));
|
||||
await Promise.all(promises);
|
||||
}
|
||||
async _updateInterceptionPatterns() {
|
||||
const patterns = network.RouteHandler.prepareInterceptionPatterns(this._routes);
|
||||
await this._channel.setNetworkInterceptionPatterns({
|
||||
patterns
|
||||
});
|
||||
}
|
||||
async _updateWebSocketInterceptionPatterns() {
|
||||
const patterns = network.WebSocketRouteHandler.prepareInterceptionPatterns(this._webSocketRoutes);
|
||||
await this._channel.setWebSocketInterceptionPatterns({
|
||||
patterns
|
||||
});
|
||||
}
|
||||
_effectiveCloseReason() {
|
||||
var _this$_browser3;
|
||||
return this._closeReason || ((_this$_browser3 = this._browser) === null || _this$_browser3 === void 0 ? void 0 : _this$_browser3._closeReason);
|
||||
}
|
||||
async waitForEvent(event, optionsOrPredicate = {}) {
|
||||
return await this._wrapApiCall(async () => {
|
||||
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
||||
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
|
||||
const waiter = _waiter.Waiter.createForEvent(this, event);
|
||||
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
|
||||
if (event !== _events.Events.BrowserContext.Close) waiter.rejectOnEvent(this, _events.Events.BrowserContext.Close, () => new _errors.TargetClosedError(this._effectiveCloseReason()));
|
||||
const result = await waiter.waitForEvent(this, event, predicate);
|
||||
waiter.dispose();
|
||||
return result;
|
||||
});
|
||||
}
|
||||
async storageState(options = {}) {
|
||||
const state = await this._channel.storageState({
|
||||
indexedDB: options.indexedDB
|
||||
});
|
||||
if (options.path) {
|
||||
await (0, _fileUtils.mkdirIfNeeded)(this._platform, options.path);
|
||||
await this._platform.fs().promises.writeFile(options.path, JSON.stringify(state, undefined, 2), 'utf8');
|
||||
}
|
||||
return state;
|
||||
}
|
||||
backgroundPages() {
|
||||
return [...this._backgroundPages];
|
||||
}
|
||||
serviceWorkers() {
|
||||
return [...this._serviceWorkers];
|
||||
}
|
||||
async newCDPSession(page) {
|
||||
// channelOwner.ts's validation messages don't handle the pseudo-union type, so we're explicit here
|
||||
if (!(page instanceof _page.Page) && !(page instanceof _frame.Frame)) throw new Error('page: expected Page or Frame');
|
||||
const result = await this._channel.newCDPSession(page instanceof _page.Page ? {
|
||||
page: page._channel
|
||||
} : {
|
||||
frame: page._channel
|
||||
});
|
||||
return _cdpSession.CDPSession.from(result.session);
|
||||
}
|
||||
_onClose() {
|
||||
var _this$_browserType;
|
||||
if (this._browser) this._browser._contexts.delete(this);
|
||||
(_this$_browserType = this._browserType) === null || _this$_browserType === void 0 || (_this$_browserType = _this$_browserType._contexts) === null || _this$_browserType === void 0 || _this$_browserType.delete(this);
|
||||
this._disposeHarRouters();
|
||||
this.tracing._resetStackCounter();
|
||||
this.emit(_events.Events.BrowserContext.Close, this);
|
||||
}
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.close();
|
||||
}
|
||||
async close(options = {}) {
|
||||
if (this._closeWasCalled) return;
|
||||
this._closeReason = options.reason;
|
||||
this._closeWasCalled = true;
|
||||
await this._wrapApiCall(async () => {
|
||||
await this.request.dispose(options);
|
||||
}, true);
|
||||
await this._wrapApiCall(async () => {
|
||||
var _this$_browserType2;
|
||||
await ((_this$_browserType2 = this._browserType) === null || _this$_browserType2 === void 0 ? void 0 : _this$_browserType2._willCloseContext(this));
|
||||
for (const [harId, harParams] of this._harRecorders) {
|
||||
const har = await this._channel.harExport({
|
||||
harId
|
||||
});
|
||||
const artifact = _artifact.Artifact.from(har.artifact);
|
||||
// Server side will compress artifact if content is attach or if file is .zip.
|
||||
const isCompressed = harParams.content === 'attach' || harParams.path.endsWith('.zip');
|
||||
const needCompressed = harParams.path.endsWith('.zip');
|
||||
if (isCompressed && !needCompressed) {
|
||||
const localUtils = this._connection.localUtils();
|
||||
if (!localUtils) throw new Error('Uncompressed har is not supported in thin clients');
|
||||
await artifact.saveAs(harParams.path + '.tmp');
|
||||
await localUtils.harUnzip({
|
||||
zipFile: harParams.path + '.tmp',
|
||||
harFile: harParams.path
|
||||
});
|
||||
} else {
|
||||
await artifact.saveAs(harParams.path);
|
||||
}
|
||||
await artifact.delete();
|
||||
}
|
||||
}, true);
|
||||
await this._channel.close(options);
|
||||
await this._closedPromise;
|
||||
}
|
||||
async _enableRecorder(params) {
|
||||
await this._channel.enableRecorder(params);
|
||||
}
|
||||
}
|
||||
exports.BrowserContext = BrowserContext;
|
||||
async function prepareStorageState(platform, options) {
|
||||
if (typeof options.storageState !== 'string') return options.storageState;
|
||||
try {
|
||||
return JSON.parse(await platform.fs().promises.readFile(options.storageState, 'utf8'));
|
||||
} catch (e) {
|
||||
(0, _stackTrace.rewriteErrorMessage)(e, `Error reading storage state from ${options.storageState}:\n` + e.message);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
function prepareRecordHarOptions(options) {
|
||||
if (!options) return;
|
||||
return {
|
||||
path: options.path,
|
||||
content: options.content || (options.omitContent ? 'omit' : undefined),
|
||||
urlGlob: (0, _rtti.isString)(options.urlFilter) ? options.urlFilter : undefined,
|
||||
urlRegexSource: (0, _rtti.isRegExp)(options.urlFilter) ? options.urlFilter.source : undefined,
|
||||
urlRegexFlags: (0, _rtti.isRegExp)(options.urlFilter) ? options.urlFilter.flags : undefined,
|
||||
mode: options.mode
|
||||
};
|
||||
}
|
||||
async function prepareBrowserContextParams(platform, options) {
|
||||
if (options.videoSize && !options.videosPath) throw new Error(`"videoSize" option requires "videosPath" to be specified`);
|
||||
if (options.extraHTTPHeaders) network.validateHeaders(options.extraHTTPHeaders);
|
||||
const contextParams = {
|
||||
...options,
|
||||
viewport: options.viewport === null ? undefined : options.viewport,
|
||||
noDefaultViewport: options.viewport === null,
|
||||
extraHTTPHeaders: options.extraHTTPHeaders ? (0, _headers.headersObjectToArray)(options.extraHTTPHeaders) : undefined,
|
||||
storageState: await prepareStorageState(platform, options),
|
||||
serviceWorkers: options.serviceWorkers,
|
||||
recordHar: prepareRecordHarOptions(options.recordHar),
|
||||
colorScheme: options.colorScheme === null ? 'no-override' : options.colorScheme,
|
||||
reducedMotion: options.reducedMotion === null ? 'no-override' : options.reducedMotion,
|
||||
forcedColors: options.forcedColors === null ? 'no-override' : options.forcedColors,
|
||||
contrast: options.contrast === null ? 'no-override' : options.contrast,
|
||||
acceptDownloads: toAcceptDownloadsProtocol(options.acceptDownloads),
|
||||
clientCertificates: await toClientCertificatesProtocol(platform, options.clientCertificates)
|
||||
};
|
||||
if (!contextParams.recordVideo && options.videosPath) {
|
||||
contextParams.recordVideo = {
|
||||
dir: options.videosPath,
|
||||
size: options.videoSize
|
||||
};
|
||||
}
|
||||
if (contextParams.recordVideo && contextParams.recordVideo.dir) contextParams.recordVideo.dir = platform.path().resolve(contextParams.recordVideo.dir);
|
||||
return contextParams;
|
||||
}
|
||||
function toAcceptDownloadsProtocol(acceptDownloads) {
|
||||
if (acceptDownloads === undefined) return undefined;
|
||||
if (acceptDownloads) return 'accept';
|
||||
return 'deny';
|
||||
}
|
||||
async function toClientCertificatesProtocol(platform, certs) {
|
||||
if (!certs) return undefined;
|
||||
const bufferizeContent = async (value, path) => {
|
||||
if (value) return value;
|
||||
if (path) return await platform.fs().promises.readFile(path);
|
||||
};
|
||||
return await Promise.all(certs.map(async cert => ({
|
||||
origin: cert.origin,
|
||||
cert: await bufferizeContent(cert.cert, cert.certPath),
|
||||
key: await bufferizeContent(cert.key, cert.keyPath),
|
||||
pfx: await bufferizeContent(cert.pfx, cert.pfxPath),
|
||||
passphrase: cert.passphrase
|
||||
})));
|
||||
}
|
||||
207
node_modules/playwright-core/lib/client/browserType.js
generated
vendored
Normal file
207
node_modules/playwright-core/lib/client/browserType.js
generated
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.BrowserType = void 0;
|
||||
var _browser3 = require("./browser");
|
||||
var _browserContext = require("./browserContext");
|
||||
var _channelOwner = require("./channelOwner");
|
||||
var _clientHelper = require("./clientHelper");
|
||||
var _events = require("./events");
|
||||
var _assert = require("../utils/isomorphic/assert");
|
||||
var _headers = require("../utils/isomorphic/headers");
|
||||
var _time = require("../utils/isomorphic/time");
|
||||
var _timeoutRunner = require("../utils/isomorphic/timeoutRunner");
|
||||
var _webSocket = require("./webSocket");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// This is here just for api generation and checking.
|
||||
|
||||
class BrowserType extends _channelOwner.ChannelOwner {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
this._serverLauncher = void 0;
|
||||
this._contexts = new Set();
|
||||
this._playwright = void 0;
|
||||
}
|
||||
static from(browserType) {
|
||||
return browserType._object;
|
||||
}
|
||||
executablePath() {
|
||||
if (!this._initializer.executablePath) throw new Error('Browser is not supported on current platform');
|
||||
return this._initializer.executablePath;
|
||||
}
|
||||
name() {
|
||||
return this._initializer.name;
|
||||
}
|
||||
async launch(options = {}) {
|
||||
var _this$_playwright$_de;
|
||||
(0, _assert.assert)(!options.userDataDir, 'userDataDir option is not supported in `browserType.launch`. Use `browserType.launchPersistentContext` instead');
|
||||
(0, _assert.assert)(!options.port, 'Cannot specify a port without launching as a server.');
|
||||
const logger = options.logger || ((_this$_playwright$_de = this._playwright._defaultLaunchOptions) === null || _this$_playwright$_de === void 0 ? void 0 : _this$_playwright$_de.logger);
|
||||
options = {
|
||||
...this._playwright._defaultLaunchOptions,
|
||||
...options
|
||||
};
|
||||
const launchOptions = {
|
||||
...options,
|
||||
ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined,
|
||||
ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs),
|
||||
env: options.env ? (0, _clientHelper.envObjectToArray)(options.env) : undefined
|
||||
};
|
||||
return await this._wrapApiCall(async () => {
|
||||
const browser = _browser3.Browser.from((await this._channel.launch(launchOptions)).browser);
|
||||
this._didLaunchBrowser(browser, options, logger);
|
||||
return browser;
|
||||
});
|
||||
}
|
||||
async launchServer(options = {}) {
|
||||
if (!this._serverLauncher) throw new Error('Launching server is not supported');
|
||||
options = {
|
||||
...this._playwright._defaultLaunchOptions,
|
||||
...options
|
||||
};
|
||||
return await this._serverLauncher.launchServer(options);
|
||||
}
|
||||
async launchPersistentContext(userDataDir, options = {}) {
|
||||
var _this$_playwright$_de2;
|
||||
const logger = options.logger || ((_this$_playwright$_de2 = this._playwright._defaultLaunchOptions) === null || _this$_playwright$_de2 === void 0 ? void 0 : _this$_playwright$_de2.logger);
|
||||
(0, _assert.assert)(!options.port, 'Cannot specify a port without launching as a server.');
|
||||
options = {
|
||||
...this._playwright._defaultLaunchOptions,
|
||||
...this._playwright._defaultContextOptions,
|
||||
...options
|
||||
};
|
||||
const contextParams = await (0, _browserContext.prepareBrowserContextParams)(this._platform, options);
|
||||
const persistentParams = {
|
||||
...contextParams,
|
||||
ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined,
|
||||
ignoreAllDefaultArgs: !!options.ignoreDefaultArgs && !Array.isArray(options.ignoreDefaultArgs),
|
||||
env: options.env ? (0, _clientHelper.envObjectToArray)(options.env) : undefined,
|
||||
channel: options.channel,
|
||||
userDataDir: this._platform.path().isAbsolute(userDataDir) || !userDataDir ? userDataDir : this._platform.path().resolve(userDataDir)
|
||||
};
|
||||
return await this._wrapApiCall(async () => {
|
||||
const result = await this._channel.launchPersistentContext(persistentParams);
|
||||
const context = _browserContext.BrowserContext.from(result.context);
|
||||
await this._didCreateContext(context, contextParams, options, logger);
|
||||
return context;
|
||||
});
|
||||
}
|
||||
async connect(optionsOrWsEndpoint, options) {
|
||||
if (typeof optionsOrWsEndpoint === 'string') return await this._connect({
|
||||
...options,
|
||||
wsEndpoint: optionsOrWsEndpoint
|
||||
});
|
||||
(0, _assert.assert)(optionsOrWsEndpoint.wsEndpoint, 'options.wsEndpoint is required');
|
||||
return await this._connect(optionsOrWsEndpoint);
|
||||
}
|
||||
async _connect(params) {
|
||||
const logger = params.logger;
|
||||
return await this._wrapApiCall(async () => {
|
||||
var _params$exposeNetwork;
|
||||
const deadline = params.timeout ? (0, _time.monotonicTime)() + params.timeout : 0;
|
||||
const headers = {
|
||||
'x-playwright-browser': this.name(),
|
||||
...params.headers
|
||||
};
|
||||
const connectParams = {
|
||||
wsEndpoint: params.wsEndpoint,
|
||||
headers,
|
||||
exposeNetwork: (_params$exposeNetwork = params.exposeNetwork) !== null && _params$exposeNetwork !== void 0 ? _params$exposeNetwork : params._exposeNetwork,
|
||||
slowMo: params.slowMo,
|
||||
timeout: params.timeout
|
||||
};
|
||||
if (params.__testHookRedirectPortForwarding) connectParams.socksProxyRedirectPortForTest = params.__testHookRedirectPortForwarding;
|
||||
const connection = await (0, _webSocket.connectOverWebSocket)(this._connection, connectParams);
|
||||
let browser;
|
||||
connection.on('close', () => {
|
||||
// Emulate all pages, contexts and the browser closing upon disconnect.
|
||||
for (const context of ((_browser = browser) === null || _browser === void 0 ? void 0 : _browser.contexts()) || []) {
|
||||
var _browser;
|
||||
for (const page of context.pages()) page._onClose();
|
||||
context._onClose();
|
||||
}
|
||||
setTimeout(() => {
|
||||
var _browser2;
|
||||
return (_browser2 = browser) === null || _browser2 === void 0 ? void 0 : _browser2._didClose();
|
||||
}, 0);
|
||||
});
|
||||
const result = await (0, _timeoutRunner.raceAgainstDeadline)(async () => {
|
||||
// For tests.
|
||||
if (params.__testHookBeforeCreateBrowser) await params.__testHookBeforeCreateBrowser();
|
||||
const playwright = await connection.initializePlaywright();
|
||||
if (!playwright._initializer.preLaunchedBrowser) {
|
||||
connection.close();
|
||||
throw new Error('Malformed endpoint. Did you use BrowserType.launchServer method?');
|
||||
}
|
||||
playwright._setSelectors(this._playwright.selectors);
|
||||
browser = _browser3.Browser.from(playwright._initializer.preLaunchedBrowser);
|
||||
this._didLaunchBrowser(browser, {}, logger);
|
||||
browser._shouldCloseConnectionOnClose = true;
|
||||
browser.on(_events.Events.Browser.Disconnected, () => connection.close());
|
||||
return browser;
|
||||
}, deadline);
|
||||
if (!result.timedOut) {
|
||||
return result.result;
|
||||
} else {
|
||||
connection.close();
|
||||
throw new Error(`Timeout ${params.timeout}ms exceeded`);
|
||||
}
|
||||
});
|
||||
}
|
||||
async connectOverCDP(endpointURLOrOptions, options) {
|
||||
if (typeof endpointURLOrOptions === 'string') return await this._connectOverCDP(endpointURLOrOptions, options);
|
||||
const endpointURL = 'endpointURL' in endpointURLOrOptions ? endpointURLOrOptions.endpointURL : endpointURLOrOptions.wsEndpoint;
|
||||
(0, _assert.assert)(endpointURL, 'Cannot connect over CDP without wsEndpoint.');
|
||||
return await this.connectOverCDP(endpointURL, endpointURLOrOptions);
|
||||
}
|
||||
async _connectOverCDP(endpointURL, params = {}) {
|
||||
if (this.name() !== 'chromium') throw new Error('Connecting over CDP is only supported in Chromium.');
|
||||
const headers = params.headers ? (0, _headers.headersObjectToArray)(params.headers) : undefined;
|
||||
const result = await this._channel.connectOverCDP({
|
||||
endpointURL,
|
||||
headers,
|
||||
slowMo: params.slowMo,
|
||||
timeout: params.timeout
|
||||
});
|
||||
const browser = _browser3.Browser.from(result.browser);
|
||||
this._didLaunchBrowser(browser, {}, params.logger);
|
||||
if (result.defaultContext) await this._didCreateContext(_browserContext.BrowserContext.from(result.defaultContext), {}, {}, params.logger);
|
||||
return browser;
|
||||
}
|
||||
_didLaunchBrowser(browser, browserOptions, logger) {
|
||||
browser._browserType = this;
|
||||
browser._options = browserOptions;
|
||||
browser._logger = logger;
|
||||
}
|
||||
async _didCreateContext(context, contextOptions, browserOptions, logger) {
|
||||
context._logger = logger;
|
||||
context._browserType = this;
|
||||
this._contexts.add(context);
|
||||
context._setOptions(contextOptions, browserOptions);
|
||||
if (this._playwright._defaultContextTimeout !== undefined) context.setDefaultTimeout(this._playwright._defaultContextTimeout);
|
||||
if (this._playwright._defaultContextNavigationTimeout !== undefined) context.setDefaultNavigationTimeout(this._playwright._defaultContextNavigationTimeout);
|
||||
await this._instrumentation.runAfterCreateBrowserContext(context);
|
||||
}
|
||||
async _willCloseContext(context) {
|
||||
this._contexts.delete(context);
|
||||
await this._instrumentation.runBeforeCloseBrowserContext(context);
|
||||
}
|
||||
}
|
||||
exports.BrowserType = BrowserType;
|
||||
53
node_modules/playwright-core/lib/client/cdpSession.js
generated
vendored
Normal file
53
node_modules/playwright-core/lib/client/cdpSession.js
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.CDPSession = void 0;
|
||||
var _channelOwner = require("./channelOwner");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class CDPSession extends _channelOwner.ChannelOwner {
|
||||
static from(cdpSession) {
|
||||
return cdpSession._object;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._channel.on('event', ({
|
||||
method,
|
||||
params
|
||||
}) => {
|
||||
this.emit(method, params);
|
||||
});
|
||||
this.on = super.on;
|
||||
this.addListener = super.addListener;
|
||||
this.off = super.removeListener;
|
||||
this.removeListener = super.removeListener;
|
||||
this.once = super.once;
|
||||
}
|
||||
async send(method, params) {
|
||||
const result = await this._channel.send({
|
||||
method,
|
||||
params
|
||||
});
|
||||
return result.result;
|
||||
}
|
||||
async detach() {
|
||||
return await this._channel.detach();
|
||||
}
|
||||
}
|
||||
exports.CDPSession = CDPSession;
|
||||
218
node_modules/playwright-core/lib/client/channelOwner.js
generated
vendored
Normal file
218
node_modules/playwright-core/lib/client/channelOwner.js
generated
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.ChannelOwner = void 0;
|
||||
var _eventEmitter = require("./eventEmitter");
|
||||
var _validator = require("../protocol/validator");
|
||||
var _clientStackTrace = require("./clientStackTrace");
|
||||
var _stackTrace = require("../utils/isomorphic/stackTrace");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class ChannelOwner extends _eventEmitter.EventEmitter {
|
||||
constructor(parent, type, guid, initializer) {
|
||||
const connection = parent instanceof ChannelOwner ? parent._connection : parent;
|
||||
super(connection._platform);
|
||||
this._connection = void 0;
|
||||
this._parent = void 0;
|
||||
this._objects = new Map();
|
||||
this._type = void 0;
|
||||
this._guid = void 0;
|
||||
this._channel = void 0;
|
||||
this._initializer = void 0;
|
||||
this._logger = void 0;
|
||||
this._instrumentation = void 0;
|
||||
this._eventToSubscriptionMapping = new Map();
|
||||
this._isInternalType = false;
|
||||
this._wasCollected = false;
|
||||
this.setMaxListeners(0);
|
||||
this._connection = connection;
|
||||
this._type = type;
|
||||
this._guid = guid;
|
||||
this._parent = parent instanceof ChannelOwner ? parent : undefined;
|
||||
this._instrumentation = this._connection._instrumentation;
|
||||
this._connection._objects.set(guid, this);
|
||||
if (this._parent) {
|
||||
this._parent._objects.set(guid, this);
|
||||
this._logger = this._parent._logger;
|
||||
}
|
||||
this._channel = this._createChannel(new _eventEmitter.EventEmitter(connection._platform));
|
||||
this._initializer = initializer;
|
||||
}
|
||||
markAsInternalType() {
|
||||
this._isInternalType = true;
|
||||
}
|
||||
_setEventToSubscriptionMapping(mapping) {
|
||||
this._eventToSubscriptionMapping = mapping;
|
||||
}
|
||||
_updateSubscription(event, enabled) {
|
||||
const protocolEvent = this._eventToSubscriptionMapping.get(String(event));
|
||||
if (protocolEvent) {
|
||||
this._wrapApiCall(async () => {
|
||||
await this._channel.updateSubscription({
|
||||
event: protocolEvent,
|
||||
enabled
|
||||
});
|
||||
}, true).catch(() => {});
|
||||
}
|
||||
}
|
||||
on(event, listener) {
|
||||
if (!this.listenerCount(event)) this._updateSubscription(event, true);
|
||||
super.on(event, listener);
|
||||
return this;
|
||||
}
|
||||
addListener(event, listener) {
|
||||
if (!this.listenerCount(event)) this._updateSubscription(event, true);
|
||||
super.addListener(event, listener);
|
||||
return this;
|
||||
}
|
||||
prependListener(event, listener) {
|
||||
if (!this.listenerCount(event)) this._updateSubscription(event, true);
|
||||
super.prependListener(event, listener);
|
||||
return this;
|
||||
}
|
||||
off(event, listener) {
|
||||
super.off(event, listener);
|
||||
if (!this.listenerCount(event)) this._updateSubscription(event, false);
|
||||
return this;
|
||||
}
|
||||
removeListener(event, listener) {
|
||||
super.removeListener(event, listener);
|
||||
if (!this.listenerCount(event)) this._updateSubscription(event, false);
|
||||
return this;
|
||||
}
|
||||
_adopt(child) {
|
||||
child._parent._objects.delete(child._guid);
|
||||
this._objects.set(child._guid, child);
|
||||
child._parent = this;
|
||||
}
|
||||
_dispose(reason) {
|
||||
// Clean up from parent and connection.
|
||||
if (this._parent) this._parent._objects.delete(this._guid);
|
||||
this._connection._objects.delete(this._guid);
|
||||
this._wasCollected = reason === 'gc';
|
||||
|
||||
// Dispose all children.
|
||||
for (const object of [...this._objects.values()]) object._dispose(reason);
|
||||
this._objects.clear();
|
||||
}
|
||||
_debugScopeState() {
|
||||
return {
|
||||
_guid: this._guid,
|
||||
objects: Array.from(this._objects.values()).map(o => o._debugScopeState())
|
||||
};
|
||||
}
|
||||
_validatorToWireContext() {
|
||||
return {
|
||||
tChannelImpl: tChannelImplToWire,
|
||||
binary: this._connection.rawBuffers() ? 'buffer' : 'toBase64',
|
||||
isUnderTest: () => this._platform.isUnderTest()
|
||||
};
|
||||
}
|
||||
_createChannel(base) {
|
||||
const channel = new Proxy(base, {
|
||||
get: (obj, prop) => {
|
||||
if (typeof prop === 'string') {
|
||||
const validator = (0, _validator.maybeFindValidator)(this._type, prop, 'Params');
|
||||
if (validator) {
|
||||
return async params => {
|
||||
return await this._wrapApiCall(async apiZone => {
|
||||
const validatedParams = validator(params, '', this._validatorToWireContext());
|
||||
if (!apiZone.isInternal && !apiZone.reported) {
|
||||
// Reporting/tracing/logging this api call for the first time.
|
||||
apiZone.params = params;
|
||||
apiZone.reported = true;
|
||||
this._instrumentation.onApiCallBegin(apiZone);
|
||||
logApiCall(this._platform, this._logger, `=> ${apiZone.apiName} started`);
|
||||
return await this._connection.sendMessageToServer(this, prop, validatedParams, apiZone.apiName, apiZone.frames, apiZone.stepId);
|
||||
}
|
||||
// Since this api call is either internal, or has already been reported/traced once,
|
||||
// passing undefined apiName will avoid an extra unneeded tracing entry.
|
||||
return await this._connection.sendMessageToServer(this, prop, validatedParams, undefined, [], undefined);
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
return obj[prop];
|
||||
}
|
||||
});
|
||||
channel._object = this;
|
||||
return channel;
|
||||
}
|
||||
async _wrapApiCall(func, isInternal) {
|
||||
const logger = this._logger;
|
||||
const existingApiZone = this._platform.zones.current().data();
|
||||
if (existingApiZone) return await func(existingApiZone);
|
||||
if (isInternal === undefined) isInternal = this._isInternalType;
|
||||
const stackTrace = (0, _clientStackTrace.captureLibraryStackTrace)(this._platform);
|
||||
const apiZone = {
|
||||
apiName: stackTrace.apiName,
|
||||
frames: stackTrace.frames,
|
||||
isInternal,
|
||||
reported: false,
|
||||
userData: undefined,
|
||||
stepId: undefined
|
||||
};
|
||||
try {
|
||||
const result = await this._platform.zones.current().push(apiZone).run(async () => await func(apiZone));
|
||||
if (!isInternal) {
|
||||
logApiCall(this._platform, logger, `<= ${apiZone.apiName} succeeded`);
|
||||
this._instrumentation.onApiCallEnd(apiZone);
|
||||
}
|
||||
return result;
|
||||
} catch (e) {
|
||||
const innerError = (this._platform.showInternalStackFrames() || this._platform.isUnderTest()) && e.stack ? '\n<inner error>\n' + e.stack : '';
|
||||
if (apiZone.apiName && !apiZone.apiName.includes('<anonymous>')) e.message = apiZone.apiName + ': ' + e.message;
|
||||
const stackFrames = '\n' + (0, _stackTrace.stringifyStackFrames)(stackTrace.frames).join('\n') + innerError;
|
||||
if (stackFrames.trim()) e.stack = e.message + stackFrames;else e.stack = '';
|
||||
if (!isInternal) {
|
||||
apiZone.error = e;
|
||||
logApiCall(this._platform, logger, `<= ${apiZone.apiName} failed`);
|
||||
this._instrumentation.onApiCallEnd(apiZone);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
_toImpl() {
|
||||
var _this$_connection$toI, _this$_connection;
|
||||
return (_this$_connection$toI = (_this$_connection = this._connection).toImpl) === null || _this$_connection$toI === void 0 ? void 0 : _this$_connection$toI.call(_this$_connection, this);
|
||||
}
|
||||
toJSON() {
|
||||
// Jest's expect library tries to print objects sometimes.
|
||||
// RPC objects can contain links to lots of other objects,
|
||||
// which can cause jest to crash. Let's help it out
|
||||
// by just returning the important values.
|
||||
return {
|
||||
_type: this._type,
|
||||
_guid: this._guid
|
||||
};
|
||||
}
|
||||
}
|
||||
exports.ChannelOwner = ChannelOwner;
|
||||
function logApiCall(platform, logger, message) {
|
||||
if (logger && logger.isEnabled('api', 'info')) logger.log('api', 'info', message, [], {
|
||||
color: 'cyan'
|
||||
});
|
||||
platform.log('api', message);
|
||||
}
|
||||
function tChannelImplToWire(names, arg, path, context) {
|
||||
if (arg._object instanceof ChannelOwner && (names === '*' || names.includes(arg._object._type))) return {
|
||||
guid: arg._object._guid
|
||||
};
|
||||
throw new _validator.ValidationError(`${path}: expected channel ${names.toString()}`);
|
||||
}
|
||||
55
node_modules/playwright-core/lib/client/clientHelper.js
generated
vendored
Normal file
55
node_modules/playwright-core/lib/client/clientHelper.js
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.addSourceUrlToScript = addSourceUrlToScript;
|
||||
exports.envObjectToArray = envObjectToArray;
|
||||
exports.evaluationScript = evaluationScript;
|
||||
var _rtti = require("../utils/isomorphic/rtti");
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
function envObjectToArray(env) {
|
||||
const result = [];
|
||||
for (const name in env) {
|
||||
if (!Object.is(env[name], undefined)) result.push({
|
||||
name,
|
||||
value: String(env[name])
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
async function evaluationScript(platform, fun, arg, addSourceUrl = true) {
|
||||
if (typeof fun === 'function') {
|
||||
const source = fun.toString();
|
||||
const argString = Object.is(arg, undefined) ? 'undefined' : JSON.stringify(arg);
|
||||
return `(${source})(${argString})`;
|
||||
}
|
||||
if (arg !== undefined) throw new Error('Cannot evaluate a string with arguments');
|
||||
if ((0, _rtti.isString)(fun)) return fun;
|
||||
if (fun.content !== undefined) return fun.content;
|
||||
if (fun.path !== undefined) {
|
||||
let source = await platform.fs().promises.readFile(fun.path, 'utf8');
|
||||
if (addSourceUrl) source = addSourceUrlToScript(source, fun.path);
|
||||
return source;
|
||||
}
|
||||
throw new Error('Either path or content property must be present');
|
||||
}
|
||||
function addSourceUrlToScript(source, path) {
|
||||
return `${source}\n//# sourceURL=${path.replace(/\n/g, '')}`;
|
||||
}
|
||||
52
node_modules/playwright-core/lib/client/clientInstrumentation.js
generated
vendored
Normal file
52
node_modules/playwright-core/lib/client/clientInstrumentation.js
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.createInstrumentation = createInstrumentation;
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Instrumentation can mutate the data, for example change apiName or stepId.
|
||||
|
||||
function createInstrumentation() {
|
||||
const listeners = [];
|
||||
return new Proxy({}, {
|
||||
get: (obj, prop) => {
|
||||
if (typeof prop !== 'string') return obj[prop];
|
||||
if (prop === 'addListener') return listener => listeners.push(listener);
|
||||
if (prop === 'removeListener') return listener => listeners.splice(listeners.indexOf(listener), 1);
|
||||
if (prop === 'removeAllListeners') return () => listeners.splice(0, listeners.length);
|
||||
if (prop.startsWith('run')) {
|
||||
return async (...params) => {
|
||||
for (const listener of listeners) {
|
||||
var _prop, _ref;
|
||||
await ((_prop = (_ref = listener)[prop]) === null || _prop === void 0 ? void 0 : _prop.call(_ref, ...params));
|
||||
}
|
||||
};
|
||||
}
|
||||
if (prop.startsWith('on')) {
|
||||
return (...params) => {
|
||||
for (const listener of listeners) {
|
||||
var _prop2, _ref2;
|
||||
(_prop2 = (_ref2 = listener)[prop]) === null || _prop2 === void 0 || _prop2.call(_ref2, ...params);
|
||||
}
|
||||
};
|
||||
}
|
||||
return obj[prop];
|
||||
}
|
||||
});
|
||||
}
|
||||
65
node_modules/playwright-core/lib/client/clientStackTrace.js
generated
vendored
Normal file
65
node_modules/playwright-core/lib/client/clientStackTrace.js
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.captureLibraryStackTrace = captureLibraryStackTrace;
|
||||
var _stackTrace = require("../utils/isomorphic/stackTrace");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
function captureLibraryStackTrace(platform) {
|
||||
const stack = (0, _stackTrace.captureRawStack)();
|
||||
let parsedFrames = stack.map(line => {
|
||||
const frame = (0, _stackTrace.parseStackFrame)(line, platform.pathSeparator, platform.showInternalStackFrames());
|
||||
if (!frame || !frame.file) return null;
|
||||
const isPlaywrightLibrary = !!platform.coreDir && frame.file.startsWith(platform.coreDir);
|
||||
const parsed = {
|
||||
frame,
|
||||
frameText: line,
|
||||
isPlaywrightLibrary
|
||||
};
|
||||
return parsed;
|
||||
}).filter(Boolean);
|
||||
let apiName = '';
|
||||
|
||||
// Deepest transition between non-client code calling into client
|
||||
// code is the api entry.
|
||||
for (let i = 0; i < parsedFrames.length - 1; i++) {
|
||||
const parsedFrame = parsedFrames[i];
|
||||
if (parsedFrame.isPlaywrightLibrary && !parsedFrames[i + 1].isPlaywrightLibrary) {
|
||||
apiName = apiName || normalizeAPIName(parsedFrame.frame.function);
|
||||
break;
|
||||
}
|
||||
}
|
||||
function normalizeAPIName(name) {
|
||||
if (!name) return '';
|
||||
const match = name.match(/(API|JS|CDP|[A-Z])(.*)/);
|
||||
if (!match) return name;
|
||||
return match[1].toLowerCase() + match[2];
|
||||
}
|
||||
|
||||
// This is for the inspector so that it did not include the test runner stack frames.
|
||||
const filterPrefixes = platform.boxedStackPrefixes();
|
||||
parsedFrames = parsedFrames.filter(f => {
|
||||
if (filterPrefixes.some(prefix => f.frame.file.startsWith(prefix))) return false;
|
||||
return true;
|
||||
});
|
||||
return {
|
||||
frames: parsedFrames.map(p => p.frame),
|
||||
apiName
|
||||
};
|
||||
}
|
||||
68
node_modules/playwright-core/lib/client/clock.js
generated
vendored
Normal file
68
node_modules/playwright-core/lib/client/clock.js
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Clock = void 0;
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Clock {
|
||||
constructor(browserContext) {
|
||||
this._browserContext = void 0;
|
||||
this._browserContext = browserContext;
|
||||
}
|
||||
async install(options = {}) {
|
||||
await this._browserContext._channel.clockInstall(options.time !== undefined ? parseTime(options.time) : {});
|
||||
}
|
||||
async fastForward(ticks) {
|
||||
await this._browserContext._channel.clockFastForward(parseTicks(ticks));
|
||||
}
|
||||
async pauseAt(time) {
|
||||
await this._browserContext._channel.clockPauseAt(parseTime(time));
|
||||
}
|
||||
async resume() {
|
||||
await this._browserContext._channel.clockResume({});
|
||||
}
|
||||
async runFor(ticks) {
|
||||
await this._browserContext._channel.clockRunFor(parseTicks(ticks));
|
||||
}
|
||||
async setFixedTime(time) {
|
||||
await this._browserContext._channel.clockSetFixedTime(parseTime(time));
|
||||
}
|
||||
async setSystemTime(time) {
|
||||
await this._browserContext._channel.clockSetSystemTime(parseTime(time));
|
||||
}
|
||||
}
|
||||
exports.Clock = Clock;
|
||||
function parseTime(time) {
|
||||
if (typeof time === 'number') return {
|
||||
timeNumber: time
|
||||
};
|
||||
if (typeof time === 'string') return {
|
||||
timeString: time
|
||||
};
|
||||
if (!isFinite(time.getTime())) throw new Error(`Invalid date: ${time}`);
|
||||
return {
|
||||
timeNumber: time.getTime()
|
||||
};
|
||||
}
|
||||
function parseTicks(ticks) {
|
||||
return {
|
||||
ticksNumber: typeof ticks === 'number' ? ticks : undefined,
|
||||
ticksString: typeof ticks === 'string' ? ticks : undefined
|
||||
};
|
||||
}
|
||||
340
node_modules/playwright-core/lib/client/connection.js
generated
vendored
Normal file
340
node_modules/playwright-core/lib/client/connection.js
generated
vendored
Normal file
@@ -0,0 +1,340 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Connection = void 0;
|
||||
var _eventEmitter = require("./eventEmitter");
|
||||
var _android = require("./android");
|
||||
var _artifact = require("./artifact");
|
||||
var _browser = require("./browser");
|
||||
var _browserContext = require("./browserContext");
|
||||
var _browserType = require("./browserType");
|
||||
var _cdpSession = require("./cdpSession");
|
||||
var _channelOwner = require("./channelOwner");
|
||||
var _clientInstrumentation = require("./clientInstrumentation");
|
||||
var _dialog = require("./dialog");
|
||||
var _electron = require("./electron");
|
||||
var _elementHandle = require("./elementHandle");
|
||||
var _errors = require("./errors");
|
||||
var _fetch = require("./fetch");
|
||||
var _frame = require("./frame");
|
||||
var _jsHandle = require("./jsHandle");
|
||||
var _jsonPipe = require("./jsonPipe");
|
||||
var _localUtils = require("./localUtils");
|
||||
var _network = require("./network");
|
||||
var _page = require("./page");
|
||||
var _playwright = require("./playwright");
|
||||
var _selectors = require("./selectors");
|
||||
var _stream = require("./stream");
|
||||
var _tracing = require("./tracing");
|
||||
var _worker = require("./worker");
|
||||
var _writableStream = require("./writableStream");
|
||||
var _validator = require("../protocol/validator");
|
||||
var _stackTrace = require("../utils/isomorphic/stackTrace");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Root extends _channelOwner.ChannelOwner {
|
||||
constructor(connection) {
|
||||
super(connection, 'Root', '', {});
|
||||
}
|
||||
async initialize() {
|
||||
return _playwright.Playwright.from((await this._channel.initialize({
|
||||
sdkLanguage: 'javascript'
|
||||
})).playwright);
|
||||
}
|
||||
}
|
||||
class DummyChannelOwner extends _channelOwner.ChannelOwner {}
|
||||
class Connection extends _eventEmitter.EventEmitter {
|
||||
constructor(platform, localUtils, instrumentation, headers = []) {
|
||||
super(platform);
|
||||
this._objects = new Map();
|
||||
this.onmessage = message => {};
|
||||
this._lastId = 0;
|
||||
this._callbacks = new Map();
|
||||
this._rootObject = void 0;
|
||||
this._closedError = void 0;
|
||||
this._isRemote = false;
|
||||
this._localUtils = void 0;
|
||||
this._rawBuffers = false;
|
||||
// Some connections allow resolving in-process dispatchers.
|
||||
this.toImpl = void 0;
|
||||
this._tracingCount = 0;
|
||||
this._instrumentation = void 0;
|
||||
// Used from @playwright/test fixtures -> TODO remove?
|
||||
this.headers = void 0;
|
||||
this._instrumentation = instrumentation || (0, _clientInstrumentation.createInstrumentation)();
|
||||
this._localUtils = localUtils;
|
||||
this._rootObject = new Root(this);
|
||||
this.headers = headers;
|
||||
}
|
||||
markAsRemote() {
|
||||
this._isRemote = true;
|
||||
}
|
||||
isRemote() {
|
||||
return this._isRemote;
|
||||
}
|
||||
useRawBuffers() {
|
||||
this._rawBuffers = true;
|
||||
}
|
||||
rawBuffers() {
|
||||
return this._rawBuffers;
|
||||
}
|
||||
localUtils() {
|
||||
return this._localUtils;
|
||||
}
|
||||
async initializePlaywright() {
|
||||
return await this._rootObject.initialize();
|
||||
}
|
||||
getObjectWithKnownName(guid) {
|
||||
return this._objects.get(guid);
|
||||
}
|
||||
setIsTracing(isTracing) {
|
||||
if (isTracing) this._tracingCount++;else this._tracingCount--;
|
||||
}
|
||||
async sendMessageToServer(object, method, params, apiName, frames, stepId) {
|
||||
var _this$_localUtils;
|
||||
if (this._closedError) throw this._closedError;
|
||||
if (object._wasCollected) throw new Error('The object has been collected to prevent unbounded heap growth.');
|
||||
const guid = object._guid;
|
||||
const type = object._type;
|
||||
const id = ++this._lastId;
|
||||
const message = {
|
||||
id,
|
||||
guid,
|
||||
method,
|
||||
params
|
||||
};
|
||||
if (this._platform.isLogEnabled('channel')) {
|
||||
// Do not include metadata in debug logs to avoid noise.
|
||||
this._platform.log('channel', 'SEND> ' + JSON.stringify(message));
|
||||
}
|
||||
const location = frames[0] ? {
|
||||
file: frames[0].file,
|
||||
line: frames[0].line,
|
||||
column: frames[0].column
|
||||
} : undefined;
|
||||
const metadata = {
|
||||
apiName,
|
||||
location,
|
||||
internal: !apiName,
|
||||
stepId
|
||||
};
|
||||
if (this._tracingCount && frames && type !== 'LocalUtils') (_this$_localUtils = this._localUtils) === null || _this$_localUtils === void 0 || _this$_localUtils.addStackToTracingNoReply({
|
||||
callData: {
|
||||
stack: frames,
|
||||
id
|
||||
}
|
||||
}).catch(() => {});
|
||||
// We need to exit zones before calling into the server, otherwise
|
||||
// when we receive events from the server, we would be in an API zone.
|
||||
this._platform.zones.empty.run(() => this.onmessage({
|
||||
...message,
|
||||
metadata
|
||||
}));
|
||||
return await new Promise((resolve, reject) => this._callbacks.set(id, {
|
||||
resolve,
|
||||
reject,
|
||||
apiName,
|
||||
type,
|
||||
method
|
||||
}));
|
||||
}
|
||||
_validatorFromWireContext() {
|
||||
return {
|
||||
tChannelImpl: this._tChannelImplFromWire.bind(this),
|
||||
binary: this._rawBuffers ? 'buffer' : 'fromBase64',
|
||||
isUnderTest: () => this._platform.isUnderTest()
|
||||
};
|
||||
}
|
||||
dispatch(message) {
|
||||
if (this._closedError) return;
|
||||
const {
|
||||
id,
|
||||
guid,
|
||||
method,
|
||||
params,
|
||||
result,
|
||||
error,
|
||||
log
|
||||
} = message;
|
||||
if (id) {
|
||||
if (this._platform.isLogEnabled('channel')) this._platform.log('channel', '<RECV ' + JSON.stringify(message));
|
||||
const callback = this._callbacks.get(id);
|
||||
if (!callback) throw new Error(`Cannot find command to respond: ${id}`);
|
||||
this._callbacks.delete(id);
|
||||
if (error && !result) {
|
||||
const parsedError = (0, _errors.parseError)(error);
|
||||
(0, _stackTrace.rewriteErrorMessage)(parsedError, parsedError.message + formatCallLog(this._platform, log));
|
||||
callback.reject(parsedError);
|
||||
} else {
|
||||
const validator = (0, _validator.findValidator)(callback.type, callback.method, 'Result');
|
||||
callback.resolve(validator(result, '', this._validatorFromWireContext()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this._platform.isLogEnabled('channel')) this._platform.log('channel', '<EVENT ' + JSON.stringify(message));
|
||||
if (method === '__create__') {
|
||||
this._createRemoteObject(guid, params.type, params.guid, params.initializer);
|
||||
return;
|
||||
}
|
||||
const object = this._objects.get(guid);
|
||||
if (!object) throw new Error(`Cannot find object to "${method}": ${guid}`);
|
||||
if (method === '__adopt__') {
|
||||
const child = this._objects.get(params.guid);
|
||||
if (!child) throw new Error(`Unknown new child: ${params.guid}`);
|
||||
object._adopt(child);
|
||||
return;
|
||||
}
|
||||
if (method === '__dispose__') {
|
||||
object._dispose(params.reason);
|
||||
return;
|
||||
}
|
||||
const validator = (0, _validator.findValidator)(object._type, method, 'Event');
|
||||
object._channel.emit(method, validator(params, '', this._validatorFromWireContext()));
|
||||
}
|
||||
close(cause) {
|
||||
if (this._closedError) return;
|
||||
this._closedError = new _errors.TargetClosedError(cause);
|
||||
for (const callback of this._callbacks.values()) callback.reject(this._closedError);
|
||||
this._callbacks.clear();
|
||||
this.emit('close');
|
||||
}
|
||||
_tChannelImplFromWire(names, arg, path, context) {
|
||||
if (arg && typeof arg === 'object' && typeof arg.guid === 'string') {
|
||||
const object = this._objects.get(arg.guid);
|
||||
if (!object) throw new Error(`Object with guid ${arg.guid} was not bound in the connection`);
|
||||
if (names !== '*' && !names.includes(object._type)) throw new _validator.ValidationError(`${path}: expected channel ${names.toString()}`);
|
||||
return object._channel;
|
||||
}
|
||||
throw new _validator.ValidationError(`${path}: expected channel ${names.toString()}`);
|
||||
}
|
||||
_createRemoteObject(parentGuid, type, guid, initializer) {
|
||||
const parent = this._objects.get(parentGuid);
|
||||
if (!parent) throw new Error(`Cannot find parent object ${parentGuid} to create ${guid}`);
|
||||
let result;
|
||||
const validator = (0, _validator.findValidator)(type, '', 'Initializer');
|
||||
initializer = validator(initializer, '', this._validatorFromWireContext());
|
||||
switch (type) {
|
||||
case 'Android':
|
||||
result = new _android.Android(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'AndroidSocket':
|
||||
result = new _android.AndroidSocket(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'AndroidDevice':
|
||||
result = new _android.AndroidDevice(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'APIRequestContext':
|
||||
result = new _fetch.APIRequestContext(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'Artifact':
|
||||
result = new _artifact.Artifact(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'BindingCall':
|
||||
result = new _page.BindingCall(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'Browser':
|
||||
result = new _browser.Browser(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'BrowserContext':
|
||||
result = new _browserContext.BrowserContext(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'BrowserType':
|
||||
result = new _browserType.BrowserType(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'CDPSession':
|
||||
result = new _cdpSession.CDPSession(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'Dialog':
|
||||
result = new _dialog.Dialog(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'Electron':
|
||||
result = new _electron.Electron(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'ElectronApplication':
|
||||
result = new _electron.ElectronApplication(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'ElementHandle':
|
||||
result = new _elementHandle.ElementHandle(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'Frame':
|
||||
result = new _frame.Frame(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'JSHandle':
|
||||
result = new _jsHandle.JSHandle(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'JsonPipe':
|
||||
result = new _jsonPipe.JsonPipe(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'LocalUtils':
|
||||
result = new _localUtils.LocalUtils(parent, type, guid, initializer);
|
||||
if (!this._localUtils) this._localUtils = result;
|
||||
break;
|
||||
case 'Page':
|
||||
result = new _page.Page(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'Playwright':
|
||||
result = new _playwright.Playwright(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'Request':
|
||||
result = new _network.Request(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'Response':
|
||||
result = new _network.Response(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'Route':
|
||||
result = new _network.Route(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'Stream':
|
||||
result = new _stream.Stream(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'Selectors':
|
||||
result = new _selectors.SelectorsOwner(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'SocksSupport':
|
||||
result = new DummyChannelOwner(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'Tracing':
|
||||
result = new _tracing.Tracing(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'WebSocket':
|
||||
result = new _network.WebSocket(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'WebSocketRoute':
|
||||
result = new _network.WebSocketRoute(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'Worker':
|
||||
result = new _worker.Worker(parent, type, guid, initializer);
|
||||
break;
|
||||
case 'WritableStream':
|
||||
result = new _writableStream.WritableStream(parent, type, guid, initializer);
|
||||
break;
|
||||
default:
|
||||
throw new Error('Missing type ' + type);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
exports.Connection = Connection;
|
||||
function formatCallLog(platform, log) {
|
||||
if (!log || !log.some(l => !!l)) return '';
|
||||
return `
|
||||
Call log:
|
||||
${platform.colors.dim(log.join('\n'))}
|
||||
`;
|
||||
}
|
||||
52
node_modules/playwright-core/lib/client/consoleMessage.js
generated
vendored
Normal file
52
node_modules/playwright-core/lib/client/consoleMessage.js
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.ConsoleMessage = void 0;
|
||||
var _jsHandle = require("./jsHandle");
|
||||
var _page = require("./page");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class ConsoleMessage {
|
||||
constructor(platform, event) {
|
||||
this._page = void 0;
|
||||
this._event = void 0;
|
||||
this._page = 'page' in event && event.page ? _page.Page.from(event.page) : null;
|
||||
this._event = event;
|
||||
if (platform.inspectCustom) this[platform.inspectCustom] = () => this._inspect();
|
||||
}
|
||||
page() {
|
||||
return this._page;
|
||||
}
|
||||
type() {
|
||||
return this._event.type;
|
||||
}
|
||||
text() {
|
||||
return this._event.text;
|
||||
}
|
||||
args() {
|
||||
return this._event.args.map(_jsHandle.JSHandle.from);
|
||||
}
|
||||
location() {
|
||||
return this._event.location;
|
||||
}
|
||||
_inspect() {
|
||||
return this.text();
|
||||
}
|
||||
}
|
||||
exports.ConsoleMessage = ConsoleMessage;
|
||||
41
node_modules/playwright-core/lib/client/coverage.js
generated
vendored
Normal file
41
node_modules/playwright-core/lib/client/coverage.js
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Coverage = void 0;
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Coverage {
|
||||
constructor(channel) {
|
||||
this._channel = void 0;
|
||||
this._channel = channel;
|
||||
}
|
||||
async startJSCoverage(options = {}) {
|
||||
await this._channel.startJSCoverage(options);
|
||||
}
|
||||
async stopJSCoverage() {
|
||||
return (await this._channel.stopJSCoverage()).entries;
|
||||
}
|
||||
async startCSSCoverage(options = {}) {
|
||||
await this._channel.startCSSCoverage(options);
|
||||
}
|
||||
async stopCSSCoverage() {
|
||||
return (await this._channel.stopCSSCoverage()).entries;
|
||||
}
|
||||
}
|
||||
exports.Coverage = Coverage;
|
||||
57
node_modules/playwright-core/lib/client/dialog.js
generated
vendored
Normal file
57
node_modules/playwright-core/lib/client/dialog.js
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Dialog = void 0;
|
||||
var _channelOwner = require("./channelOwner");
|
||||
var _page = require("./page");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Dialog extends _channelOwner.ChannelOwner {
|
||||
static from(dialog) {
|
||||
return dialog._object;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
// Note: dialogs that open early during page initialization block it.
|
||||
// Therefore, we must report the dialog without a page to be able to handle it.
|
||||
this._page = void 0;
|
||||
this._page = _page.Page.fromNullable(initializer.page);
|
||||
}
|
||||
page() {
|
||||
return this._page;
|
||||
}
|
||||
type() {
|
||||
return this._initializer.type;
|
||||
}
|
||||
message() {
|
||||
return this._initializer.message;
|
||||
}
|
||||
defaultValue() {
|
||||
return this._initializer.defaultValue;
|
||||
}
|
||||
async accept(promptText) {
|
||||
await this._channel.accept({
|
||||
promptText
|
||||
});
|
||||
}
|
||||
async dismiss() {
|
||||
await this._channel.dismiss();
|
||||
}
|
||||
}
|
||||
exports.Dialog = Dialog;
|
||||
62
node_modules/playwright-core/lib/client/download.js
generated
vendored
Normal file
62
node_modules/playwright-core/lib/client/download.js
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Download = void 0;
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Download {
|
||||
constructor(page, url, suggestedFilename, artifact) {
|
||||
this._page = void 0;
|
||||
this._url = void 0;
|
||||
this._suggestedFilename = void 0;
|
||||
this._artifact = void 0;
|
||||
this._page = page;
|
||||
this._url = url;
|
||||
this._suggestedFilename = suggestedFilename;
|
||||
this._artifact = artifact;
|
||||
}
|
||||
page() {
|
||||
return this._page;
|
||||
}
|
||||
url() {
|
||||
return this._url;
|
||||
}
|
||||
suggestedFilename() {
|
||||
return this._suggestedFilename;
|
||||
}
|
||||
async path() {
|
||||
return await this._artifact.pathAfterFinished();
|
||||
}
|
||||
async saveAs(path) {
|
||||
return await this._artifact.saveAs(path);
|
||||
}
|
||||
async failure() {
|
||||
return await this._artifact.failure();
|
||||
}
|
||||
async createReadStream() {
|
||||
return await this._artifact.createReadStream();
|
||||
}
|
||||
async cancel() {
|
||||
return await this._artifact.cancel();
|
||||
}
|
||||
async delete() {
|
||||
return await this._artifact.delete();
|
||||
}
|
||||
}
|
||||
exports.Download = Download;
|
||||
135
node_modules/playwright-core/lib/client/electron.js
generated
vendored
Normal file
135
node_modules/playwright-core/lib/client/electron.js
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.ElectronApplication = exports.Electron = void 0;
|
||||
var _browserContext = require("./browserContext");
|
||||
var _channelOwner = require("./channelOwner");
|
||||
var _clientHelper = require("./clientHelper");
|
||||
var _consoleMessage = require("./consoleMessage");
|
||||
var _errors = require("./errors");
|
||||
var _events = require("./events");
|
||||
var _jsHandle = require("./jsHandle");
|
||||
var _waiter = require("./waiter");
|
||||
var _timeoutSettings = require("./timeoutSettings");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Electron extends _channelOwner.ChannelOwner {
|
||||
static from(electron) {
|
||||
return electron._object;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
}
|
||||
async launch(options = {}) {
|
||||
const params = {
|
||||
...(await (0, _browserContext.prepareBrowserContextParams)(this._platform, options)),
|
||||
env: (0, _clientHelper.envObjectToArray)(options.env ? options.env : this._platform.env),
|
||||
tracesDir: options.tracesDir
|
||||
};
|
||||
const app = ElectronApplication.from((await this._channel.launch(params)).electronApplication);
|
||||
app._context._setOptions(params, options);
|
||||
return app;
|
||||
}
|
||||
}
|
||||
exports.Electron = Electron;
|
||||
class ElectronApplication extends _channelOwner.ChannelOwner {
|
||||
static from(electronApplication) {
|
||||
return electronApplication._object;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._context = void 0;
|
||||
this._windows = new Set();
|
||||
this._timeoutSettings = void 0;
|
||||
this._timeoutSettings = new _timeoutSettings.TimeoutSettings(this._platform);
|
||||
this._context = _browserContext.BrowserContext.from(initializer.context);
|
||||
for (const page of this._context._pages) this._onPage(page);
|
||||
this._context.on(_events.Events.BrowserContext.Page, page => this._onPage(page));
|
||||
this._channel.on('close', () => {
|
||||
this.emit(_events.Events.ElectronApplication.Close);
|
||||
});
|
||||
this._channel.on('console', event => this.emit(_events.Events.ElectronApplication.Console, new _consoleMessage.ConsoleMessage(this._platform, event)));
|
||||
this._setEventToSubscriptionMapping(new Map([[_events.Events.ElectronApplication.Console, 'console']]));
|
||||
}
|
||||
process() {
|
||||
return this._toImpl().process();
|
||||
}
|
||||
_onPage(page) {
|
||||
this._windows.add(page);
|
||||
this.emit(_events.Events.ElectronApplication.Window, page);
|
||||
page.once(_events.Events.Page.Close, () => this._windows.delete(page));
|
||||
}
|
||||
windows() {
|
||||
// TODO: add ElectronPage class inheriting from Page.
|
||||
return [...this._windows];
|
||||
}
|
||||
async firstWindow(options) {
|
||||
if (this._windows.size) return this._windows.values().next().value;
|
||||
return await this.waitForEvent('window', options);
|
||||
}
|
||||
context() {
|
||||
return this._context;
|
||||
}
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.close();
|
||||
}
|
||||
async close() {
|
||||
try {
|
||||
await this._context.close();
|
||||
} catch (e) {
|
||||
if ((0, _errors.isTargetClosedError)(e)) return;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
async waitForEvent(event, optionsOrPredicate = {}) {
|
||||
return await this._wrapApiCall(async () => {
|
||||
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
||||
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
|
||||
const waiter = _waiter.Waiter.createForEvent(this, event);
|
||||
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
|
||||
if (event !== _events.Events.ElectronApplication.Close) waiter.rejectOnEvent(this, _events.Events.ElectronApplication.Close, () => new _errors.TargetClosedError());
|
||||
const result = await waiter.waitForEvent(this, event, predicate);
|
||||
waiter.dispose();
|
||||
return result;
|
||||
});
|
||||
}
|
||||
async browserWindow(page) {
|
||||
const result = await this._channel.browserWindow({
|
||||
page: page._channel
|
||||
});
|
||||
return _jsHandle.JSHandle.from(result.handle);
|
||||
}
|
||||
async evaluate(pageFunction, arg) {
|
||||
const result = await this._channel.evaluateExpression({
|
||||
expression: String(pageFunction),
|
||||
isFunction: typeof pageFunction === 'function',
|
||||
arg: (0, _jsHandle.serializeArgument)(arg)
|
||||
});
|
||||
return (0, _jsHandle.parseResult)(result.value);
|
||||
}
|
||||
async evaluateHandle(pageFunction, arg) {
|
||||
const result = await this._channel.evaluateExpressionHandle({
|
||||
expression: String(pageFunction),
|
||||
isFunction: typeof pageFunction === 'function',
|
||||
arg: (0, _jsHandle.serializeArgument)(arg)
|
||||
});
|
||||
return _jsHandle.JSHandle.from(result.handle);
|
||||
}
|
||||
}
|
||||
exports.ElectronApplication = ElectronApplication;
|
||||
320
node_modules/playwright-core/lib/client/elementHandle.js
generated
vendored
Normal file
320
node_modules/playwright-core/lib/client/elementHandle.js
generated
vendored
Normal file
@@ -0,0 +1,320 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.ElementHandle = void 0;
|
||||
exports.convertInputFiles = convertInputFiles;
|
||||
exports.convertSelectOptionValues = convertSelectOptionValues;
|
||||
exports.determineScreenshotType = determineScreenshotType;
|
||||
var _frame = require("./frame");
|
||||
var _jsHandle = require("./jsHandle");
|
||||
var _assert = require("../utils/isomorphic/assert");
|
||||
var _fileUtils = require("./fileUtils");
|
||||
var _rtti = require("../utils/isomorphic/rtti");
|
||||
var _writableStream = require("./writableStream");
|
||||
var _mimeType = require("../utils/isomorphic/mimeType");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class ElementHandle extends _jsHandle.JSHandle {
|
||||
static from(handle) {
|
||||
return handle._object;
|
||||
}
|
||||
static fromNullable(handle) {
|
||||
return handle ? ElementHandle.from(handle) : null;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._elementChannel = void 0;
|
||||
this._elementChannel = this._channel;
|
||||
}
|
||||
asElement() {
|
||||
return this;
|
||||
}
|
||||
async ownerFrame() {
|
||||
return _frame.Frame.fromNullable((await this._elementChannel.ownerFrame()).frame);
|
||||
}
|
||||
async contentFrame() {
|
||||
return _frame.Frame.fromNullable((await this._elementChannel.contentFrame()).frame);
|
||||
}
|
||||
async _generateLocatorString() {
|
||||
const value = (await this._elementChannel.generateLocatorString()).value;
|
||||
return value === undefined ? null : value;
|
||||
}
|
||||
async getAttribute(name) {
|
||||
const value = (await this._elementChannel.getAttribute({
|
||||
name
|
||||
})).value;
|
||||
return value === undefined ? null : value;
|
||||
}
|
||||
async inputValue() {
|
||||
return (await this._elementChannel.inputValue()).value;
|
||||
}
|
||||
async textContent() {
|
||||
const value = (await this._elementChannel.textContent()).value;
|
||||
return value === undefined ? null : value;
|
||||
}
|
||||
async innerText() {
|
||||
return (await this._elementChannel.innerText()).value;
|
||||
}
|
||||
async innerHTML() {
|
||||
return (await this._elementChannel.innerHTML()).value;
|
||||
}
|
||||
async isChecked() {
|
||||
return (await this._elementChannel.isChecked()).value;
|
||||
}
|
||||
async isDisabled() {
|
||||
return (await this._elementChannel.isDisabled()).value;
|
||||
}
|
||||
async isEditable() {
|
||||
return (await this._elementChannel.isEditable()).value;
|
||||
}
|
||||
async isEnabled() {
|
||||
return (await this._elementChannel.isEnabled()).value;
|
||||
}
|
||||
async isHidden() {
|
||||
return (await this._elementChannel.isHidden()).value;
|
||||
}
|
||||
async isVisible() {
|
||||
return (await this._elementChannel.isVisible()).value;
|
||||
}
|
||||
async dispatchEvent(type, eventInit = {}) {
|
||||
await this._elementChannel.dispatchEvent({
|
||||
type,
|
||||
eventInit: (0, _jsHandle.serializeArgument)(eventInit)
|
||||
});
|
||||
}
|
||||
async scrollIntoViewIfNeeded(options = {}) {
|
||||
await this._elementChannel.scrollIntoViewIfNeeded(options);
|
||||
}
|
||||
async hover(options = {}) {
|
||||
await this._elementChannel.hover(options);
|
||||
}
|
||||
async click(options = {}) {
|
||||
return await this._elementChannel.click(options);
|
||||
}
|
||||
async dblclick(options = {}) {
|
||||
return await this._elementChannel.dblclick(options);
|
||||
}
|
||||
async tap(options = {}) {
|
||||
return await this._elementChannel.tap(options);
|
||||
}
|
||||
async selectOption(values, options = {}) {
|
||||
const result = await this._elementChannel.selectOption({
|
||||
...convertSelectOptionValues(values),
|
||||
...options
|
||||
});
|
||||
return result.values;
|
||||
}
|
||||
async fill(value, options = {}) {
|
||||
return await this._elementChannel.fill({
|
||||
value,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async selectText(options = {}) {
|
||||
await this._elementChannel.selectText(options);
|
||||
}
|
||||
async setInputFiles(files, options = {}) {
|
||||
const frame = await this.ownerFrame();
|
||||
if (!frame) throw new Error('Cannot set input files to detached element');
|
||||
const converted = await convertInputFiles(this._platform, files, frame.page().context());
|
||||
await this._elementChannel.setInputFiles({
|
||||
...converted,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async focus() {
|
||||
await this._elementChannel.focus();
|
||||
}
|
||||
async type(text, options = {}) {
|
||||
await this._elementChannel.type({
|
||||
text,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async press(key, options = {}) {
|
||||
await this._elementChannel.press({
|
||||
key,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async check(options = {}) {
|
||||
return await this._elementChannel.check(options);
|
||||
}
|
||||
async uncheck(options = {}) {
|
||||
return await this._elementChannel.uncheck(options);
|
||||
}
|
||||
async setChecked(checked, options) {
|
||||
if (checked) await this.check(options);else await this.uncheck(options);
|
||||
}
|
||||
async boundingBox() {
|
||||
const value = (await this._elementChannel.boundingBox()).value;
|
||||
return value === undefined ? null : value;
|
||||
}
|
||||
async screenshot(options = {}) {
|
||||
const mask = options.mask;
|
||||
const copy = {
|
||||
...options,
|
||||
mask: undefined
|
||||
};
|
||||
if (!copy.type) copy.type = determineScreenshotType(options);
|
||||
if (mask) {
|
||||
copy.mask = mask.map(locator => ({
|
||||
frame: locator._frame._channel,
|
||||
selector: locator._selector
|
||||
}));
|
||||
}
|
||||
const result = await this._elementChannel.screenshot(copy);
|
||||
if (options.path) {
|
||||
await (0, _fileUtils.mkdirIfNeeded)(this._platform, options.path);
|
||||
await this._platform.fs().promises.writeFile(options.path, result.binary);
|
||||
}
|
||||
return result.binary;
|
||||
}
|
||||
async $(selector) {
|
||||
return ElementHandle.fromNullable((await this._elementChannel.querySelector({
|
||||
selector
|
||||
})).element);
|
||||
}
|
||||
async $$(selector) {
|
||||
const result = await this._elementChannel.querySelectorAll({
|
||||
selector
|
||||
});
|
||||
return result.elements.map(h => ElementHandle.from(h));
|
||||
}
|
||||
async $eval(selector, pageFunction, arg) {
|
||||
const result = await this._elementChannel.evalOnSelector({
|
||||
selector,
|
||||
expression: String(pageFunction),
|
||||
isFunction: typeof pageFunction === 'function',
|
||||
arg: (0, _jsHandle.serializeArgument)(arg)
|
||||
});
|
||||
return (0, _jsHandle.parseResult)(result.value);
|
||||
}
|
||||
async $$eval(selector, pageFunction, arg) {
|
||||
const result = await this._elementChannel.evalOnSelectorAll({
|
||||
selector,
|
||||
expression: String(pageFunction),
|
||||
isFunction: typeof pageFunction === 'function',
|
||||
arg: (0, _jsHandle.serializeArgument)(arg)
|
||||
});
|
||||
return (0, _jsHandle.parseResult)(result.value);
|
||||
}
|
||||
async waitForElementState(state, options = {}) {
|
||||
return await this._elementChannel.waitForElementState({
|
||||
state,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async waitForSelector(selector, options = {}) {
|
||||
const result = await this._elementChannel.waitForSelector({
|
||||
selector,
|
||||
...options
|
||||
});
|
||||
return ElementHandle.fromNullable(result.element);
|
||||
}
|
||||
}
|
||||
exports.ElementHandle = ElementHandle;
|
||||
function convertSelectOptionValues(values) {
|
||||
if (values === null) return {};
|
||||
if (!Array.isArray(values)) values = [values];
|
||||
if (!values.length) return {};
|
||||
for (let i = 0; i < values.length; i++) (0, _assert.assert)(values[i] !== null, `options[${i}]: expected object, got null`);
|
||||
if (values[0] instanceof ElementHandle) return {
|
||||
elements: values.map(v => v._elementChannel)
|
||||
};
|
||||
if ((0, _rtti.isString)(values[0])) return {
|
||||
options: values.map(valueOrLabel => ({
|
||||
valueOrLabel
|
||||
}))
|
||||
};
|
||||
return {
|
||||
options: values
|
||||
};
|
||||
}
|
||||
function filePayloadExceedsSizeLimit(payloads) {
|
||||
return payloads.reduce((size, item) => size + (item.buffer ? item.buffer.byteLength : 0), 0) >= _fileUtils.fileUploadSizeLimit;
|
||||
}
|
||||
async function resolvePathsAndDirectoryForInputFiles(platform, items) {
|
||||
var _localPaths;
|
||||
let localPaths;
|
||||
let localDirectory;
|
||||
for (const item of items) {
|
||||
const stat = await platform.fs().promises.stat(item);
|
||||
if (stat.isDirectory()) {
|
||||
if (localDirectory) throw new Error('Multiple directories are not supported');
|
||||
localDirectory = platform.path().resolve(item);
|
||||
} else {
|
||||
localPaths !== null && localPaths !== void 0 ? localPaths : localPaths = [];
|
||||
localPaths.push(platform.path().resolve(item));
|
||||
}
|
||||
}
|
||||
if ((_localPaths = localPaths) !== null && _localPaths !== void 0 && _localPaths.length && localDirectory) throw new Error('File paths must be all files or a single directory');
|
||||
return [localPaths, localDirectory];
|
||||
}
|
||||
async function convertInputFiles(platform, files, context) {
|
||||
const items = Array.isArray(files) ? files.slice() : [files];
|
||||
if (items.some(item => typeof item === 'string')) {
|
||||
if (!items.every(item => typeof item === 'string')) throw new Error('File paths cannot be mixed with buffers');
|
||||
const [localPaths, localDirectory] = await resolvePathsAndDirectoryForInputFiles(platform, items);
|
||||
if (context._connection.isRemote()) {
|
||||
const files = localDirectory ? (await platform.fs().promises.readdir(localDirectory, {
|
||||
withFileTypes: true,
|
||||
recursive: true
|
||||
})).filter(f => f.isFile()).map(f => platform.path().join(f.path, f.name)) : localPaths;
|
||||
const {
|
||||
writableStreams,
|
||||
rootDir
|
||||
} = await context._wrapApiCall(async () => context._channel.createTempFiles({
|
||||
rootDirName: localDirectory ? platform.path().basename(localDirectory) : undefined,
|
||||
items: await Promise.all(files.map(async file => {
|
||||
const lastModifiedMs = (await platform.fs().promises.stat(file)).mtimeMs;
|
||||
return {
|
||||
name: localDirectory ? platform.path().relative(localDirectory, file) : platform.path().basename(file),
|
||||
lastModifiedMs
|
||||
};
|
||||
}))
|
||||
}), true);
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const writable = _writableStream.WritableStream.from(writableStreams[i]);
|
||||
await platform.streamFile(files[i], writable.stream());
|
||||
}
|
||||
return {
|
||||
directoryStream: rootDir,
|
||||
streams: localDirectory ? undefined : writableStreams
|
||||
};
|
||||
}
|
||||
return {
|
||||
localPaths,
|
||||
localDirectory
|
||||
};
|
||||
}
|
||||
const payloads = items;
|
||||
if (filePayloadExceedsSizeLimit(payloads)) throw new Error('Cannot set buffer larger than 50Mb, please write it to a file and pass its path instead.');
|
||||
return {
|
||||
payloads
|
||||
};
|
||||
}
|
||||
function determineScreenshotType(options) {
|
||||
if (options.path) {
|
||||
const mimeType = (0, _mimeType.getMimeTypeForPath)(options.path);
|
||||
if (mimeType === 'image/png') return 'png';else if (mimeType === 'image/jpeg') return 'jpeg';
|
||||
throw new Error(`path: unsupported mime type "${mimeType}"`);
|
||||
}
|
||||
return options.type;
|
||||
}
|
||||
77
node_modules/playwright-core/lib/client/errors.js
generated
vendored
Normal file
77
node_modules/playwright-core/lib/client/errors.js
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.TimeoutError = exports.TargetClosedError = void 0;
|
||||
exports.isTargetClosedError = isTargetClosedError;
|
||||
exports.parseError = parseError;
|
||||
exports.serializeError = serializeError;
|
||||
var _serializers = require("../protocol/serializers");
|
||||
var _rtti = require("../utils/isomorphic/rtti");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class TimeoutError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.name = 'TimeoutError';
|
||||
}
|
||||
}
|
||||
exports.TimeoutError = TimeoutError;
|
||||
class TargetClosedError extends Error {
|
||||
constructor(cause) {
|
||||
super(cause || 'Target page, context or browser has been closed');
|
||||
}
|
||||
}
|
||||
exports.TargetClosedError = TargetClosedError;
|
||||
function isTargetClosedError(error) {
|
||||
return error instanceof TargetClosedError;
|
||||
}
|
||||
function serializeError(e) {
|
||||
if ((0, _rtti.isError)(e)) return {
|
||||
error: {
|
||||
message: e.message,
|
||||
stack: e.stack,
|
||||
name: e.name
|
||||
}
|
||||
};
|
||||
return {
|
||||
value: (0, _serializers.serializeValue)(e, value => ({
|
||||
fallThrough: value
|
||||
}))
|
||||
};
|
||||
}
|
||||
function parseError(error) {
|
||||
if (!error.error) {
|
||||
if (error.value === undefined) throw new Error('Serialized error must have either an error or a value');
|
||||
return (0, _serializers.parseSerializedValue)(error.value, undefined);
|
||||
}
|
||||
if (error.error.name === 'TimeoutError') {
|
||||
const e = new TimeoutError(error.error.message);
|
||||
e.stack = error.error.stack || '';
|
||||
return e;
|
||||
}
|
||||
if (error.error.name === 'TargetClosedError') {
|
||||
const e = new TargetClosedError(error.error.message);
|
||||
e.stack = error.error.stack || '';
|
||||
return e;
|
||||
}
|
||||
const e = new Error(error.error.message);
|
||||
e.stack = error.error.stack || '';
|
||||
e.name = error.error.name;
|
||||
return e;
|
||||
}
|
||||
311
node_modules/playwright-core/lib/client/eventEmitter.js
generated
vendored
Normal file
311
node_modules/playwright-core/lib/client/eventEmitter.js
generated
vendored
Normal file
@@ -0,0 +1,311 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.EventEmitter = void 0;
|
||||
/**
|
||||
* Copyright Joyent, Inc. and other Node contributors.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
* persons to whom the Software is furnished to do so, subject to the
|
||||
* following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
class EventEmitter {
|
||||
constructor(platform) {
|
||||
this._events = undefined;
|
||||
this._eventsCount = 0;
|
||||
this._maxListeners = undefined;
|
||||
this._pendingHandlers = new Map();
|
||||
this._rejectionHandler = void 0;
|
||||
this._platform = void 0;
|
||||
this._platform = platform;
|
||||
if (this._events === undefined || this._events === Object.getPrototypeOf(this)._events) {
|
||||
this._events = Object.create(null);
|
||||
this._eventsCount = 0;
|
||||
}
|
||||
this._maxListeners = this._maxListeners || undefined;
|
||||
this.on = this.addListener;
|
||||
this.off = this.removeListener;
|
||||
}
|
||||
setMaxListeners(n) {
|
||||
if (typeof n !== 'number' || n < 0 || Number.isNaN(n)) throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.');
|
||||
this._maxListeners = n;
|
||||
return this;
|
||||
}
|
||||
getMaxListeners() {
|
||||
return this._maxListeners === undefined ? this._platform.defaultMaxListeners() : this._maxListeners;
|
||||
}
|
||||
emit(type, ...args) {
|
||||
const events = this._events;
|
||||
if (events === undefined) return false;
|
||||
const handler = events === null || events === void 0 ? void 0 : events[type];
|
||||
if (handler === undefined) return false;
|
||||
if (typeof handler === 'function') {
|
||||
this._callHandler(type, handler, args);
|
||||
} else {
|
||||
const len = handler.length;
|
||||
const listeners = handler.slice();
|
||||
for (let i = 0; i < len; ++i) this._callHandler(type, listeners[i], args);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
_callHandler(type, handler, args) {
|
||||
const promise = Reflect.apply(handler, this, args);
|
||||
if (!(promise instanceof Promise)) return;
|
||||
let set = this._pendingHandlers.get(type);
|
||||
if (!set) {
|
||||
set = new Set();
|
||||
this._pendingHandlers.set(type, set);
|
||||
}
|
||||
set.add(promise);
|
||||
promise.catch(e => {
|
||||
if (this._rejectionHandler) this._rejectionHandler(e);else throw e;
|
||||
}).finally(() => set.delete(promise));
|
||||
}
|
||||
addListener(type, listener) {
|
||||
return this._addListener(type, listener, false);
|
||||
}
|
||||
on(type, listener) {
|
||||
return this._addListener(type, listener, false);
|
||||
}
|
||||
_addListener(type, listener, prepend) {
|
||||
checkListener(listener);
|
||||
let events = this._events;
|
||||
let existing;
|
||||
if (events === undefined) {
|
||||
events = this._events = Object.create(null);
|
||||
this._eventsCount = 0;
|
||||
} else {
|
||||
// To avoid recursion in the case that type === "newListener"! Before
|
||||
// adding it to the listeners, first emit "newListener".
|
||||
if (events.newListener !== undefined) {
|
||||
this.emit('newListener', type, unwrapListener(listener));
|
||||
|
||||
// Re-assign `events` because a newListener handler could have caused the
|
||||
// this._events to be assigned to a new object
|
||||
events = this._events;
|
||||
}
|
||||
existing = events[type];
|
||||
}
|
||||
if (existing === undefined) {
|
||||
// Optimize the case of one listener. Don't need the extra array object.
|
||||
existing = events[type] = listener;
|
||||
++this._eventsCount;
|
||||
} else {
|
||||
if (typeof existing === 'function') {
|
||||
// Adding the second element, need to change to array.
|
||||
existing = events[type] = prepend ? [listener, existing] : [existing, listener];
|
||||
// If we've already got an array, just append.
|
||||
} else if (prepend) {
|
||||
existing.unshift(listener);
|
||||
} else {
|
||||
existing.push(listener);
|
||||
}
|
||||
|
||||
// Check for listener leak
|
||||
const m = this.getMaxListeners();
|
||||
if (m > 0 && existing.length > m && !existing.warned) {
|
||||
existing.warned = true;
|
||||
// No error code for this since it is a Warning
|
||||
const w = new Error('Possible EventEmitter memory leak detected. ' + existing.length + ' ' + String(type) + ' listeners ' + 'added. Use emitter.setMaxListeners() to ' + 'increase limit');
|
||||
w.name = 'MaxListenersExceededWarning';
|
||||
w.emitter = this;
|
||||
w.type = type;
|
||||
w.count = existing.length;
|
||||
if (!this._platform.isUnderTest()) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
prependListener(type, listener) {
|
||||
return this._addListener(type, listener, true);
|
||||
}
|
||||
once(type, listener) {
|
||||
checkListener(listener);
|
||||
this.on(type, new OnceWrapper(this, type, listener).wrapperFunction);
|
||||
return this;
|
||||
}
|
||||
prependOnceListener(type, listener) {
|
||||
checkListener(listener);
|
||||
this.prependListener(type, new OnceWrapper(this, type, listener).wrapperFunction);
|
||||
return this;
|
||||
}
|
||||
removeListener(type, listener) {
|
||||
checkListener(listener);
|
||||
const events = this._events;
|
||||
if (events === undefined) return this;
|
||||
const list = events[type];
|
||||
if (list === undefined) return this;
|
||||
if (list === listener || list.listener === listener) {
|
||||
if (--this._eventsCount === 0) {
|
||||
this._events = Object.create(null);
|
||||
} else {
|
||||
var _listener;
|
||||
delete events[type];
|
||||
if (events.removeListener) this.emit('removeListener', type, (_listener = list.listener) !== null && _listener !== void 0 ? _listener : listener);
|
||||
}
|
||||
} else if (typeof list !== 'function') {
|
||||
let position = -1;
|
||||
let originalListener;
|
||||
for (let i = list.length - 1; i >= 0; i--) {
|
||||
if (list[i] === listener || wrappedListener(list[i]) === listener) {
|
||||
originalListener = wrappedListener(list[i]);
|
||||
position = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (position < 0) return this;
|
||||
if (position === 0) list.shift();else list.splice(position, 1);
|
||||
if (list.length === 1) events[type] = list[0];
|
||||
if (events.removeListener !== undefined) this.emit('removeListener', type, originalListener || listener);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
off(type, listener) {
|
||||
return this.removeListener(type, listener);
|
||||
}
|
||||
removeAllListeners(type, options) {
|
||||
this._removeAllListeners(type);
|
||||
if (!options) return this;
|
||||
if (options.behavior === 'wait') {
|
||||
const errors = [];
|
||||
this._rejectionHandler = error => errors.push(error);
|
||||
return this._waitFor(type).then(() => {
|
||||
if (errors.length) throw errors[0];
|
||||
});
|
||||
}
|
||||
if (options.behavior === 'ignoreErrors') this._rejectionHandler = () => {};
|
||||
return Promise.resolve();
|
||||
}
|
||||
_removeAllListeners(type) {
|
||||
const events = this._events;
|
||||
if (!events) return;
|
||||
|
||||
// not listening for removeListener, no need to emit
|
||||
if (!events.removeListener) {
|
||||
if (type === undefined) {
|
||||
this._events = Object.create(null);
|
||||
this._eventsCount = 0;
|
||||
} else if (events[type] !== undefined) {
|
||||
if (--this._eventsCount === 0) this._events = Object.create(null);else delete events[type];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// emit removeListener for all listeners on all events
|
||||
if (type === undefined) {
|
||||
const keys = Object.keys(events);
|
||||
let key;
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
key = keys[i];
|
||||
if (key === 'removeListener') continue;
|
||||
this._removeAllListeners(key);
|
||||
}
|
||||
this._removeAllListeners('removeListener');
|
||||
this._events = Object.create(null);
|
||||
this._eventsCount = 0;
|
||||
return;
|
||||
}
|
||||
const listeners = events[type];
|
||||
if (typeof listeners === 'function') {
|
||||
this.removeListener(type, listeners);
|
||||
} else if (listeners !== undefined) {
|
||||
// LIFO order
|
||||
for (let i = listeners.length - 1; i >= 0; i--) this.removeListener(type, listeners[i]);
|
||||
}
|
||||
}
|
||||
listeners(type) {
|
||||
return this._listeners(this, type, true);
|
||||
}
|
||||
rawListeners(type) {
|
||||
return this._listeners(this, type, false);
|
||||
}
|
||||
listenerCount(type) {
|
||||
const events = this._events;
|
||||
if (events !== undefined) {
|
||||
const listener = events[type];
|
||||
if (typeof listener === 'function') return 1;
|
||||
if (listener !== undefined) return listener.length;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
eventNames() {
|
||||
return this._eventsCount > 0 && this._events ? Reflect.ownKeys(this._events) : [];
|
||||
}
|
||||
async _waitFor(type) {
|
||||
let promises = [];
|
||||
if (type) {
|
||||
promises = [...(this._pendingHandlers.get(type) || [])];
|
||||
} else {
|
||||
promises = [];
|
||||
for (const [, pending] of this._pendingHandlers) promises.push(...pending);
|
||||
}
|
||||
await Promise.all(promises);
|
||||
}
|
||||
_listeners(target, type, unwrap) {
|
||||
const events = target._events;
|
||||
if (events === undefined) return [];
|
||||
const listener = events[type];
|
||||
if (listener === undefined) return [];
|
||||
if (typeof listener === 'function') return unwrap ? [unwrapListener(listener)] : [listener];
|
||||
return unwrap ? unwrapListeners(listener) : listener.slice();
|
||||
}
|
||||
}
|
||||
exports.EventEmitter = EventEmitter;
|
||||
function checkListener(listener) {
|
||||
if (typeof listener !== 'function') throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
|
||||
}
|
||||
class OnceWrapper {
|
||||
constructor(eventEmitter, eventType, listener) {
|
||||
this._fired = false;
|
||||
this.wrapperFunction = void 0;
|
||||
this._listener = void 0;
|
||||
this._eventEmitter = void 0;
|
||||
this._eventType = void 0;
|
||||
this._eventEmitter = eventEmitter;
|
||||
this._eventType = eventType;
|
||||
this._listener = listener;
|
||||
this.wrapperFunction = this._handle.bind(this);
|
||||
this.wrapperFunction.listener = listener;
|
||||
}
|
||||
_handle(...args) {
|
||||
if (this._fired) return;
|
||||
this._fired = true;
|
||||
this._eventEmitter.removeListener(this._eventType, this.wrapperFunction);
|
||||
return this._listener.apply(this._eventEmitter, args);
|
||||
}
|
||||
}
|
||||
function unwrapListener(l) {
|
||||
var _wrappedListener;
|
||||
return (_wrappedListener = wrappedListener(l)) !== null && _wrappedListener !== void 0 ? _wrappedListener : l;
|
||||
}
|
||||
function unwrapListeners(arr) {
|
||||
return arr.map(l => {
|
||||
var _wrappedListener2;
|
||||
return (_wrappedListener2 = wrappedListener(l)) !== null && _wrappedListener2 !== void 0 ? _wrappedListener2 : l;
|
||||
});
|
||||
}
|
||||
function wrappedListener(l) {
|
||||
return l.listener;
|
||||
}
|
||||
94
node_modules/playwright-core/lib/client/events.js
generated
vendored
Normal file
94
node_modules/playwright-core/lib/client/events.js
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Events = void 0;
|
||||
/**
|
||||
* Copyright 2019 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const Events = exports.Events = {
|
||||
AndroidDevice: {
|
||||
WebView: 'webview',
|
||||
Close: 'close'
|
||||
},
|
||||
AndroidSocket: {
|
||||
Data: 'data',
|
||||
Close: 'close'
|
||||
},
|
||||
AndroidWebView: {
|
||||
Close: 'close'
|
||||
},
|
||||
Browser: {
|
||||
Disconnected: 'disconnected'
|
||||
},
|
||||
BrowserContext: {
|
||||
Console: 'console',
|
||||
Close: 'close',
|
||||
Dialog: 'dialog',
|
||||
Page: 'page',
|
||||
// Can't use just 'error' due to node.js special treatment of error events.
|
||||
// @see https://nodejs.org/api/events.html#events_error_events
|
||||
WebError: 'weberror',
|
||||
BackgroundPage: 'backgroundpage',
|
||||
ServiceWorker: 'serviceworker',
|
||||
Request: 'request',
|
||||
Response: 'response',
|
||||
RequestFailed: 'requestfailed',
|
||||
RequestFinished: 'requestfinished'
|
||||
},
|
||||
BrowserServer: {
|
||||
Close: 'close'
|
||||
},
|
||||
Page: {
|
||||
Close: 'close',
|
||||
Crash: 'crash',
|
||||
Console: 'console',
|
||||
Dialog: 'dialog',
|
||||
Download: 'download',
|
||||
FileChooser: 'filechooser',
|
||||
DOMContentLoaded: 'domcontentloaded',
|
||||
// Can't use just 'error' due to node.js special treatment of error events.
|
||||
// @see https://nodejs.org/api/events.html#events_error_events
|
||||
PageError: 'pageerror',
|
||||
Request: 'request',
|
||||
Response: 'response',
|
||||
RequestFailed: 'requestfailed',
|
||||
RequestFinished: 'requestfinished',
|
||||
FrameAttached: 'frameattached',
|
||||
FrameDetached: 'framedetached',
|
||||
FrameNavigated: 'framenavigated',
|
||||
Load: 'load',
|
||||
Popup: 'popup',
|
||||
WebSocket: 'websocket',
|
||||
Worker: 'worker'
|
||||
},
|
||||
WebSocket: {
|
||||
Close: 'close',
|
||||
Error: 'socketerror',
|
||||
FrameReceived: 'framereceived',
|
||||
FrameSent: 'framesent'
|
||||
},
|
||||
Worker: {
|
||||
Close: 'close'
|
||||
},
|
||||
ElectronApplication: {
|
||||
Close: 'close',
|
||||
Console: 'console',
|
||||
Window: 'window'
|
||||
}
|
||||
};
|
||||
390
node_modules/playwright-core/lib/client/fetch.js
generated
vendored
Normal file
390
node_modules/playwright-core/lib/client/fetch.js
generated
vendored
Normal file
@@ -0,0 +1,390 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.APIResponse = exports.APIRequestContext = exports.APIRequest = void 0;
|
||||
var _browserContext = require("./browserContext");
|
||||
var _channelOwner = require("./channelOwner");
|
||||
var _errors = require("./errors");
|
||||
var _network = require("./network");
|
||||
var _tracing = require("./tracing");
|
||||
var _assert = require("../utils/isomorphic/assert");
|
||||
var _fileUtils = require("./fileUtils");
|
||||
var _headers = require("../utils/isomorphic/headers");
|
||||
var _rtti = require("../utils/isomorphic/rtti");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class APIRequest {
|
||||
constructor(playwright) {
|
||||
this._playwright = void 0;
|
||||
this._contexts = new Set();
|
||||
this._playwright = playwright;
|
||||
}
|
||||
async newContext(options = {}) {
|
||||
var _this$_playwright$_de, _this$_playwright$_de2;
|
||||
options = {
|
||||
...this._playwright._defaultContextOptions,
|
||||
timeout: this._playwright._defaultContextTimeout,
|
||||
...options
|
||||
};
|
||||
const storageState = typeof options.storageState === 'string' ? JSON.parse(await this._playwright._platform.fs().promises.readFile(options.storageState, 'utf8')) : options.storageState;
|
||||
const context = APIRequestContext.from((await this._playwright._channel.newRequest({
|
||||
...options,
|
||||
extraHTTPHeaders: options.extraHTTPHeaders ? (0, _headers.headersObjectToArray)(options.extraHTTPHeaders) : undefined,
|
||||
storageState,
|
||||
tracesDir: (_this$_playwright$_de = this._playwright._defaultLaunchOptions) === null || _this$_playwright$_de === void 0 ? void 0 : _this$_playwright$_de.tracesDir,
|
||||
// We do not expose tracesDir in the API, so do not allow options to accidentally override it.
|
||||
clientCertificates: await (0, _browserContext.toClientCertificatesProtocol)(this._playwright._platform, options.clientCertificates)
|
||||
})).request);
|
||||
this._contexts.add(context);
|
||||
context._request = this;
|
||||
context._tracing._tracesDir = (_this$_playwright$_de2 = this._playwright._defaultLaunchOptions) === null || _this$_playwright$_de2 === void 0 ? void 0 : _this$_playwright$_de2.tracesDir;
|
||||
await context._instrumentation.runAfterCreateRequestContext(context);
|
||||
return context;
|
||||
}
|
||||
}
|
||||
exports.APIRequest = APIRequest;
|
||||
class APIRequestContext extends _channelOwner.ChannelOwner {
|
||||
static from(channel) {
|
||||
return channel._object;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._request = void 0;
|
||||
this._tracing = void 0;
|
||||
this._closeReason = void 0;
|
||||
this._tracing = _tracing.Tracing.from(initializer.tracing);
|
||||
}
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.dispose();
|
||||
}
|
||||
async dispose(options = {}) {
|
||||
var _this$_request;
|
||||
this._closeReason = options.reason;
|
||||
await this._instrumentation.runBeforeCloseRequestContext(this);
|
||||
try {
|
||||
await this._channel.dispose(options);
|
||||
} catch (e) {
|
||||
if ((0, _errors.isTargetClosedError)(e)) return;
|
||||
throw e;
|
||||
}
|
||||
this._tracing._resetStackCounter();
|
||||
(_this$_request = this._request) === null || _this$_request === void 0 || _this$_request._contexts.delete(this);
|
||||
}
|
||||
async delete(url, options) {
|
||||
return await this.fetch(url, {
|
||||
...options,
|
||||
method: 'DELETE'
|
||||
});
|
||||
}
|
||||
async head(url, options) {
|
||||
return await this.fetch(url, {
|
||||
...options,
|
||||
method: 'HEAD'
|
||||
});
|
||||
}
|
||||
async get(url, options) {
|
||||
return await this.fetch(url, {
|
||||
...options,
|
||||
method: 'GET'
|
||||
});
|
||||
}
|
||||
async patch(url, options) {
|
||||
return await this.fetch(url, {
|
||||
...options,
|
||||
method: 'PATCH'
|
||||
});
|
||||
}
|
||||
async post(url, options) {
|
||||
return await this.fetch(url, {
|
||||
...options,
|
||||
method: 'POST'
|
||||
});
|
||||
}
|
||||
async put(url, options) {
|
||||
return await this.fetch(url, {
|
||||
...options,
|
||||
method: 'PUT'
|
||||
});
|
||||
}
|
||||
async fetch(urlOrRequest, options = {}) {
|
||||
const url = (0, _rtti.isString)(urlOrRequest) ? urlOrRequest : undefined;
|
||||
const request = (0, _rtti.isString)(urlOrRequest) ? undefined : urlOrRequest;
|
||||
return await this._innerFetch({
|
||||
url,
|
||||
request,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async _innerFetch(options = {}) {
|
||||
return await this._wrapApiCall(async () => {
|
||||
var _options$request, _options$request2, _options$request3;
|
||||
if (this._closeReason) throw new _errors.TargetClosedError(this._closeReason);
|
||||
(0, _assert.assert)(options.request || typeof options.url === 'string', 'First argument must be either URL string or Request');
|
||||
(0, _assert.assert)((options.data === undefined ? 0 : 1) + (options.form === undefined ? 0 : 1) + (options.multipart === undefined ? 0 : 1) <= 1, `Only one of 'data', 'form' or 'multipart' can be specified`);
|
||||
(0, _assert.assert)(options.maxRedirects === undefined || options.maxRedirects >= 0, `'maxRedirects' must be greater than or equal to '0'`);
|
||||
(0, _assert.assert)(options.maxRetries === undefined || options.maxRetries >= 0, `'maxRetries' must be greater than or equal to '0'`);
|
||||
const url = options.url !== undefined ? options.url : options.request.url();
|
||||
const method = options.method || ((_options$request = options.request) === null || _options$request === void 0 ? void 0 : _options$request.method());
|
||||
let encodedParams = undefined;
|
||||
if (typeof options.params === 'string') encodedParams = options.params;else if (options.params instanceof URLSearchParams) encodedParams = options.params.toString();
|
||||
// Cannot call allHeaders() here as the request may be paused inside route handler.
|
||||
const headersObj = options.headers || ((_options$request2 = options.request) === null || _options$request2 === void 0 ? void 0 : _options$request2.headers());
|
||||
const headers = headersObj ? (0, _headers.headersObjectToArray)(headersObj) : undefined;
|
||||
let jsonData;
|
||||
let formData;
|
||||
let multipartData;
|
||||
let postDataBuffer;
|
||||
if (options.data !== undefined) {
|
||||
if ((0, _rtti.isString)(options.data)) {
|
||||
if (isJsonContentType(headers)) jsonData = isJsonParsable(options.data) ? options.data : JSON.stringify(options.data);else postDataBuffer = Buffer.from(options.data, 'utf8');
|
||||
} else if (Buffer.isBuffer(options.data)) {
|
||||
postDataBuffer = options.data;
|
||||
} else if (typeof options.data === 'object' || typeof options.data === 'number' || typeof options.data === 'boolean') {
|
||||
jsonData = JSON.stringify(options.data);
|
||||
} else {
|
||||
throw new Error(`Unexpected 'data' type`);
|
||||
}
|
||||
} else if (options.form) {
|
||||
if (globalThis.FormData && options.form instanceof FormData) {
|
||||
formData = [];
|
||||
for (const [name, value] of options.form.entries()) {
|
||||
if (typeof value !== 'string') throw new Error(`Expected string for options.form["${name}"], found File. Please use options.multipart instead.`);
|
||||
formData.push({
|
||||
name,
|
||||
value
|
||||
});
|
||||
}
|
||||
} else {
|
||||
formData = objectToArray(options.form);
|
||||
}
|
||||
} else if (options.multipart) {
|
||||
multipartData = [];
|
||||
if (globalThis.FormData && options.multipart instanceof FormData) {
|
||||
const form = options.multipart;
|
||||
for (const [name, value] of form.entries()) {
|
||||
if ((0, _rtti.isString)(value)) {
|
||||
multipartData.push({
|
||||
name,
|
||||
value
|
||||
});
|
||||
} else {
|
||||
const file = {
|
||||
name: value.name,
|
||||
mimeType: value.type,
|
||||
buffer: Buffer.from(await value.arrayBuffer())
|
||||
};
|
||||
multipartData.push({
|
||||
name,
|
||||
file
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Convert file-like values to ServerFilePayload structs.
|
||||
for (const [name, value] of Object.entries(options.multipart)) multipartData.push(await toFormField(this._platform, name, value));
|
||||
}
|
||||
}
|
||||
if (postDataBuffer === undefined && jsonData === undefined && formData === undefined && multipartData === undefined) postDataBuffer = ((_options$request3 = options.request) === null || _options$request3 === void 0 ? void 0 : _options$request3.postDataBuffer()) || undefined;
|
||||
const fixtures = {
|
||||
__testHookLookup: options.__testHookLookup
|
||||
};
|
||||
const result = await this._channel.fetch({
|
||||
url,
|
||||
params: typeof options.params === 'object' ? objectToArray(options.params) : undefined,
|
||||
encodedParams,
|
||||
method,
|
||||
headers,
|
||||
postData: postDataBuffer,
|
||||
jsonData,
|
||||
formData,
|
||||
multipartData,
|
||||
timeout: options.timeout,
|
||||
failOnStatusCode: options.failOnStatusCode,
|
||||
ignoreHTTPSErrors: options.ignoreHTTPSErrors,
|
||||
maxRedirects: options.maxRedirects,
|
||||
maxRetries: options.maxRetries,
|
||||
...fixtures
|
||||
});
|
||||
return new APIResponse(this, result.response);
|
||||
});
|
||||
}
|
||||
async storageState(options = {}) {
|
||||
const state = await this._channel.storageState({
|
||||
indexedDB: options.indexedDB
|
||||
});
|
||||
if (options.path) {
|
||||
await (0, _fileUtils.mkdirIfNeeded)(this._platform, options.path);
|
||||
await this._platform.fs().promises.writeFile(options.path, JSON.stringify(state, undefined, 2), 'utf8');
|
||||
}
|
||||
return state;
|
||||
}
|
||||
}
|
||||
exports.APIRequestContext = APIRequestContext;
|
||||
async function toFormField(platform, name, value) {
|
||||
const typeOfValue = typeof value;
|
||||
if (isFilePayload(value)) {
|
||||
const payload = value;
|
||||
if (!Buffer.isBuffer(payload.buffer)) throw new Error(`Unexpected buffer type of 'data.${name}'`);
|
||||
return {
|
||||
name,
|
||||
file: filePayloadToJson(payload)
|
||||
};
|
||||
} else if (typeOfValue === 'string' || typeOfValue === 'number' || typeOfValue === 'boolean') {
|
||||
return {
|
||||
name,
|
||||
value: String(value)
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
name,
|
||||
file: await readStreamToJson(platform, value)
|
||||
};
|
||||
}
|
||||
}
|
||||
function isJsonParsable(value) {
|
||||
if (typeof value !== 'string') return false;
|
||||
try {
|
||||
JSON.parse(value);
|
||||
return true;
|
||||
} catch (e) {
|
||||
if (e instanceof SyntaxError) return false;else throw e;
|
||||
}
|
||||
}
|
||||
class APIResponse {
|
||||
constructor(context, initializer) {
|
||||
this._initializer = void 0;
|
||||
this._headers = void 0;
|
||||
this._request = void 0;
|
||||
this._request = context;
|
||||
this._initializer = initializer;
|
||||
this._headers = new _network.RawHeaders(this._initializer.headers);
|
||||
if (context._platform.inspectCustom) this[context._platform.inspectCustom] = () => this._inspect();
|
||||
}
|
||||
ok() {
|
||||
return this._initializer.status >= 200 && this._initializer.status <= 299;
|
||||
}
|
||||
url() {
|
||||
return this._initializer.url;
|
||||
}
|
||||
status() {
|
||||
return this._initializer.status;
|
||||
}
|
||||
statusText() {
|
||||
return this._initializer.statusText;
|
||||
}
|
||||
headers() {
|
||||
return this._headers.headers();
|
||||
}
|
||||
headersArray() {
|
||||
return this._headers.headersArray();
|
||||
}
|
||||
async body() {
|
||||
return await this._request._wrapApiCall(async () => {
|
||||
try {
|
||||
const result = await this._request._channel.fetchResponseBody({
|
||||
fetchUid: this._fetchUid()
|
||||
});
|
||||
if (result.binary === undefined) throw new Error('Response has been disposed');
|
||||
return result.binary;
|
||||
} catch (e) {
|
||||
if ((0, _errors.isTargetClosedError)(e)) throw new Error('Response has been disposed');
|
||||
throw e;
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
async text() {
|
||||
const content = await this.body();
|
||||
return content.toString('utf8');
|
||||
}
|
||||
async json() {
|
||||
const content = await this.text();
|
||||
return JSON.parse(content);
|
||||
}
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.dispose();
|
||||
}
|
||||
async dispose() {
|
||||
await this._request._channel.disposeAPIResponse({
|
||||
fetchUid: this._fetchUid()
|
||||
});
|
||||
}
|
||||
_inspect() {
|
||||
const headers = this.headersArray().map(({
|
||||
name,
|
||||
value
|
||||
}) => ` ${name}: ${value}`);
|
||||
return `APIResponse: ${this.status()} ${this.statusText()}\n${headers.join('\n')}`;
|
||||
}
|
||||
_fetchUid() {
|
||||
return this._initializer.fetchUid;
|
||||
}
|
||||
async _fetchLog() {
|
||||
const {
|
||||
log
|
||||
} = await this._request._channel.fetchLog({
|
||||
fetchUid: this._fetchUid()
|
||||
});
|
||||
return log;
|
||||
}
|
||||
}
|
||||
exports.APIResponse = APIResponse;
|
||||
function filePayloadToJson(payload) {
|
||||
return {
|
||||
name: payload.name,
|
||||
mimeType: payload.mimeType,
|
||||
buffer: payload.buffer
|
||||
};
|
||||
}
|
||||
async function readStreamToJson(platform, stream) {
|
||||
const buffer = await new Promise((resolve, reject) => {
|
||||
const chunks = [];
|
||||
stream.on('data', chunk => chunks.push(chunk));
|
||||
stream.on('end', () => resolve(Buffer.concat(chunks)));
|
||||
stream.on('error', err => reject(err));
|
||||
});
|
||||
const streamPath = Buffer.isBuffer(stream.path) ? stream.path.toString('utf8') : stream.path;
|
||||
return {
|
||||
name: platform.path().basename(streamPath),
|
||||
buffer
|
||||
};
|
||||
}
|
||||
function isJsonContentType(headers) {
|
||||
if (!headers) return false;
|
||||
for (const {
|
||||
name,
|
||||
value
|
||||
} of headers) {
|
||||
if (name.toLocaleLowerCase() === 'content-type') return value === 'application/json';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function objectToArray(map) {
|
||||
if (!map) return undefined;
|
||||
const result = [];
|
||||
for (const [name, value] of Object.entries(map)) {
|
||||
if (value !== undefined) result.push({
|
||||
name,
|
||||
value: String(value)
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function isFilePayload(value) {
|
||||
return typeof value === 'object' && value['name'] && value['mimeType'] && value['buffer'];
|
||||
}
|
||||
45
node_modules/playwright-core/lib/client/fileChooser.js
generated
vendored
Normal file
45
node_modules/playwright-core/lib/client/fileChooser.js
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.FileChooser = void 0;
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class FileChooser {
|
||||
constructor(page, elementHandle, isMultiple) {
|
||||
this._page = void 0;
|
||||
this._elementHandle = void 0;
|
||||
this._isMultiple = void 0;
|
||||
this._page = page;
|
||||
this._elementHandle = elementHandle;
|
||||
this._isMultiple = isMultiple;
|
||||
}
|
||||
element() {
|
||||
return this._elementHandle;
|
||||
}
|
||||
isMultiple() {
|
||||
return this._isMultiple;
|
||||
}
|
||||
page() {
|
||||
return this._page;
|
||||
}
|
||||
async setFiles(files, options) {
|
||||
return await this._elementHandle.setInputFiles(files, options);
|
||||
}
|
||||
}
|
||||
exports.FileChooser = FileChooser;
|
||||
31
node_modules/playwright-core/lib/client/fileUtils.js
generated
vendored
Normal file
31
node_modules/playwright-core/lib/client/fileUtils.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.fileUploadSizeLimit = void 0;
|
||||
exports.mkdirIfNeeded = mkdirIfNeeded;
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Keep in sync with the server.
|
||||
const fileUploadSizeLimit = exports.fileUploadSizeLimit = 50 * 1024 * 1024;
|
||||
async function mkdirIfNeeded(platform, filePath) {
|
||||
// This will harmlessly throw on windows if the dirname is the root directory.
|
||||
await platform.fs().promises.mkdir(platform.path().dirname(filePath), {
|
||||
recursive: true
|
||||
}).catch(() => {});
|
||||
}
|
||||
503
node_modules/playwright-core/lib/client/frame.js
generated
vendored
Normal file
503
node_modules/playwright-core/lib/client/frame.js
generated
vendored
Normal file
@@ -0,0 +1,503 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Frame = void 0;
|
||||
exports.verifyLoadState = verifyLoadState;
|
||||
var _eventEmitter = require("./eventEmitter");
|
||||
var _channelOwner = require("./channelOwner");
|
||||
var _clientHelper = require("./clientHelper");
|
||||
var _elementHandle = require("./elementHandle");
|
||||
var _events = require("./events");
|
||||
var _jsHandle = require("./jsHandle");
|
||||
var _locator = require("./locator");
|
||||
var network = _interopRequireWildcard(require("./network"));
|
||||
var _types = require("./types");
|
||||
var _waiter = require("./waiter");
|
||||
var _assert = require("../utils/isomorphic/assert");
|
||||
var _locatorUtils = require("../utils/isomorphic/locatorUtils");
|
||||
var _urlMatch = require("../utils/isomorphic/urlMatch");
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Frame extends _channelOwner.ChannelOwner {
|
||||
static from(frame) {
|
||||
return frame._object;
|
||||
}
|
||||
static fromNullable(frame) {
|
||||
return frame ? Frame.from(frame) : null;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._eventEmitter = void 0;
|
||||
this._loadStates = void 0;
|
||||
this._parentFrame = null;
|
||||
this._url = '';
|
||||
this._name = '';
|
||||
this._detached = false;
|
||||
this._childFrames = new Set();
|
||||
this._page = void 0;
|
||||
this._eventEmitter = new _eventEmitter.EventEmitter(parent._platform);
|
||||
this._eventEmitter.setMaxListeners(0);
|
||||
this._parentFrame = Frame.fromNullable(initializer.parentFrame);
|
||||
if (this._parentFrame) this._parentFrame._childFrames.add(this);
|
||||
this._name = initializer.name;
|
||||
this._url = initializer.url;
|
||||
this._loadStates = new Set(initializer.loadStates);
|
||||
this._channel.on('loadstate', event => {
|
||||
if (event.add) {
|
||||
this._loadStates.add(event.add);
|
||||
this._eventEmitter.emit('loadstate', event.add);
|
||||
}
|
||||
if (event.remove) this._loadStates.delete(event.remove);
|
||||
if (!this._parentFrame && event.add === 'load' && this._page) this._page.emit(_events.Events.Page.Load, this._page);
|
||||
if (!this._parentFrame && event.add === 'domcontentloaded' && this._page) this._page.emit(_events.Events.Page.DOMContentLoaded, this._page);
|
||||
});
|
||||
this._channel.on('navigated', event => {
|
||||
this._url = event.url;
|
||||
this._name = event.name;
|
||||
this._eventEmitter.emit('navigated', event);
|
||||
if (!event.error && this._page) this._page.emit(_events.Events.Page.FrameNavigated, this);
|
||||
});
|
||||
}
|
||||
page() {
|
||||
return this._page;
|
||||
}
|
||||
async goto(url, options = {}) {
|
||||
const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
||||
return network.Response.fromNullable((await this._channel.goto({
|
||||
url,
|
||||
...options,
|
||||
waitUntil
|
||||
})).response);
|
||||
}
|
||||
_setupNavigationWaiter(options) {
|
||||
const waiter = new _waiter.Waiter(this._page, '');
|
||||
if (this._page.isClosed()) waiter.rejectImmediately(this._page._closeErrorWithReason());
|
||||
waiter.rejectOnEvent(this._page, _events.Events.Page.Close, () => this._page._closeErrorWithReason());
|
||||
waiter.rejectOnEvent(this._page, _events.Events.Page.Crash, new Error('Navigation failed because page crashed!'));
|
||||
waiter.rejectOnEvent(this._page, _events.Events.Page.FrameDetached, new Error('Navigating frame was detached!'), frame => frame === this);
|
||||
const timeout = this._page._timeoutSettings.navigationTimeout(options);
|
||||
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded.`);
|
||||
return waiter;
|
||||
}
|
||||
async waitForNavigation(options = {}) {
|
||||
return await this._page._wrapApiCall(async () => {
|
||||
const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
||||
const waiter = this._setupNavigationWaiter(options);
|
||||
const toUrl = typeof options.url === 'string' ? ` to "${options.url}"` : '';
|
||||
waiter.log(`waiting for navigation${toUrl} until "${waitUntil}"`);
|
||||
const navigatedEvent = await waiter.waitForEvent(this._eventEmitter, 'navigated', event => {
|
||||
var _this$_page;
|
||||
// Any failed navigation results in a rejection.
|
||||
if (event.error) return true;
|
||||
waiter.log(` navigated to "${event.url}"`);
|
||||
return (0, _urlMatch.urlMatches)((_this$_page = this._page) === null || _this$_page === void 0 ? void 0 : _this$_page.context()._options.baseURL, event.url, options.url);
|
||||
});
|
||||
if (navigatedEvent.error) {
|
||||
const e = new Error(navigatedEvent.error);
|
||||
e.stack = '';
|
||||
await waiter.waitForPromise(Promise.reject(e));
|
||||
}
|
||||
if (!this._loadStates.has(waitUntil)) {
|
||||
await waiter.waitForEvent(this._eventEmitter, 'loadstate', s => {
|
||||
waiter.log(` "${s}" event fired`);
|
||||
return s === waitUntil;
|
||||
});
|
||||
}
|
||||
const request = navigatedEvent.newDocument ? network.Request.fromNullable(navigatedEvent.newDocument.request) : null;
|
||||
const response = request ? await waiter.waitForPromise(request._finalRequest()._internalResponse()) : null;
|
||||
waiter.dispose();
|
||||
return response;
|
||||
});
|
||||
}
|
||||
async waitForLoadState(state = 'load', options = {}) {
|
||||
state = verifyLoadState('state', state);
|
||||
return await this._page._wrapApiCall(async () => {
|
||||
const waiter = this._setupNavigationWaiter(options);
|
||||
if (this._loadStates.has(state)) {
|
||||
waiter.log(` not waiting, "${state}" event already fired`);
|
||||
} else {
|
||||
await waiter.waitForEvent(this._eventEmitter, 'loadstate', s => {
|
||||
waiter.log(` "${s}" event fired`);
|
||||
return s === state;
|
||||
});
|
||||
}
|
||||
waiter.dispose();
|
||||
});
|
||||
}
|
||||
async waitForURL(url, options = {}) {
|
||||
var _this$_page2;
|
||||
if ((0, _urlMatch.urlMatches)((_this$_page2 = this._page) === null || _this$_page2 === void 0 ? void 0 : _this$_page2.context()._options.baseURL, this.url(), url)) return await this.waitForLoadState(options.waitUntil, options);
|
||||
await this.waitForNavigation({
|
||||
url,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async frameElement() {
|
||||
return _elementHandle.ElementHandle.from((await this._channel.frameElement()).element);
|
||||
}
|
||||
async evaluateHandle(pageFunction, arg) {
|
||||
(0, _jsHandle.assertMaxArguments)(arguments.length, 2);
|
||||
const result = await this._channel.evaluateExpressionHandle({
|
||||
expression: String(pageFunction),
|
||||
isFunction: typeof pageFunction === 'function',
|
||||
arg: (0, _jsHandle.serializeArgument)(arg)
|
||||
});
|
||||
return _jsHandle.JSHandle.from(result.handle);
|
||||
}
|
||||
async evaluate(pageFunction, arg) {
|
||||
(0, _jsHandle.assertMaxArguments)(arguments.length, 2);
|
||||
const result = await this._channel.evaluateExpression({
|
||||
expression: String(pageFunction),
|
||||
isFunction: typeof pageFunction === 'function',
|
||||
arg: (0, _jsHandle.serializeArgument)(arg)
|
||||
});
|
||||
return (0, _jsHandle.parseResult)(result.value);
|
||||
}
|
||||
async _evaluateExposeUtilityScript(pageFunction, arg) {
|
||||
(0, _jsHandle.assertMaxArguments)(arguments.length, 2);
|
||||
const result = await this._channel.evaluateExpression({
|
||||
expression: String(pageFunction),
|
||||
isFunction: typeof pageFunction === 'function',
|
||||
arg: (0, _jsHandle.serializeArgument)(arg)
|
||||
});
|
||||
return (0, _jsHandle.parseResult)(result.value);
|
||||
}
|
||||
async $(selector, options) {
|
||||
const result = await this._channel.querySelector({
|
||||
selector,
|
||||
...options
|
||||
});
|
||||
return _elementHandle.ElementHandle.fromNullable(result.element);
|
||||
}
|
||||
async waitForSelector(selector, options = {}) {
|
||||
if (options.visibility) throw new Error('options.visibility is not supported, did you mean options.state?');
|
||||
if (options.waitFor && options.waitFor !== 'visible') throw new Error('options.waitFor is not supported, did you mean options.state?');
|
||||
const result = await this._channel.waitForSelector({
|
||||
selector,
|
||||
...options
|
||||
});
|
||||
return _elementHandle.ElementHandle.fromNullable(result.element);
|
||||
}
|
||||
async dispatchEvent(selector, type, eventInit, options = {}) {
|
||||
await this._channel.dispatchEvent({
|
||||
selector,
|
||||
type,
|
||||
eventInit: (0, _jsHandle.serializeArgument)(eventInit),
|
||||
...options
|
||||
});
|
||||
}
|
||||
async $eval(selector, pageFunction, arg) {
|
||||
(0, _jsHandle.assertMaxArguments)(arguments.length, 3);
|
||||
const result = await this._channel.evalOnSelector({
|
||||
selector,
|
||||
expression: String(pageFunction),
|
||||
isFunction: typeof pageFunction === 'function',
|
||||
arg: (0, _jsHandle.serializeArgument)(arg)
|
||||
});
|
||||
return (0, _jsHandle.parseResult)(result.value);
|
||||
}
|
||||
async $$eval(selector, pageFunction, arg) {
|
||||
(0, _jsHandle.assertMaxArguments)(arguments.length, 3);
|
||||
const result = await this._channel.evalOnSelectorAll({
|
||||
selector,
|
||||
expression: String(pageFunction),
|
||||
isFunction: typeof pageFunction === 'function',
|
||||
arg: (0, _jsHandle.serializeArgument)(arg)
|
||||
});
|
||||
return (0, _jsHandle.parseResult)(result.value);
|
||||
}
|
||||
async $$(selector) {
|
||||
const result = await this._channel.querySelectorAll({
|
||||
selector
|
||||
});
|
||||
return result.elements.map(e => _elementHandle.ElementHandle.from(e));
|
||||
}
|
||||
async _queryCount(selector) {
|
||||
return (await this._channel.queryCount({
|
||||
selector
|
||||
})).value;
|
||||
}
|
||||
async content() {
|
||||
return (await this._channel.content()).value;
|
||||
}
|
||||
async setContent(html, options = {}) {
|
||||
const waitUntil = verifyLoadState('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
||||
await this._channel.setContent({
|
||||
html,
|
||||
...options,
|
||||
waitUntil
|
||||
});
|
||||
}
|
||||
name() {
|
||||
return this._name || '';
|
||||
}
|
||||
url() {
|
||||
return this._url;
|
||||
}
|
||||
parentFrame() {
|
||||
return this._parentFrame;
|
||||
}
|
||||
childFrames() {
|
||||
return Array.from(this._childFrames);
|
||||
}
|
||||
isDetached() {
|
||||
return this._detached;
|
||||
}
|
||||
async addScriptTag(options = {}) {
|
||||
const copy = {
|
||||
...options
|
||||
};
|
||||
if (copy.path) {
|
||||
copy.content = (await this._platform.fs().promises.readFile(copy.path)).toString();
|
||||
copy.content = (0, _clientHelper.addSourceUrlToScript)(copy.content, copy.path);
|
||||
}
|
||||
return _elementHandle.ElementHandle.from((await this._channel.addScriptTag({
|
||||
...copy
|
||||
})).element);
|
||||
}
|
||||
async addStyleTag(options = {}) {
|
||||
const copy = {
|
||||
...options
|
||||
};
|
||||
if (copy.path) {
|
||||
copy.content = (await this._platform.fs().promises.readFile(copy.path)).toString();
|
||||
copy.content += '/*# sourceURL=' + copy.path.replace(/\n/g, '') + '*/';
|
||||
}
|
||||
return _elementHandle.ElementHandle.from((await this._channel.addStyleTag({
|
||||
...copy
|
||||
})).element);
|
||||
}
|
||||
async click(selector, options = {}) {
|
||||
return await this._channel.click({
|
||||
selector,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async dblclick(selector, options = {}) {
|
||||
return await this._channel.dblclick({
|
||||
selector,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async dragAndDrop(source, target, options = {}) {
|
||||
return await this._channel.dragAndDrop({
|
||||
source,
|
||||
target,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async tap(selector, options = {}) {
|
||||
return await this._channel.tap({
|
||||
selector,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async fill(selector, value, options = {}) {
|
||||
return await this._channel.fill({
|
||||
selector,
|
||||
value,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async _highlight(selector) {
|
||||
return await this._channel.highlight({
|
||||
selector
|
||||
});
|
||||
}
|
||||
locator(selector, options) {
|
||||
return new _locator.Locator(this, selector, options);
|
||||
}
|
||||
getByTestId(testId) {
|
||||
return this.locator((0, _locatorUtils.getByTestIdSelector)((0, _locator.testIdAttributeName)(), testId));
|
||||
}
|
||||
getByAltText(text, options) {
|
||||
return this.locator((0, _locatorUtils.getByAltTextSelector)(text, options));
|
||||
}
|
||||
getByLabel(text, options) {
|
||||
return this.locator((0, _locatorUtils.getByLabelSelector)(text, options));
|
||||
}
|
||||
getByPlaceholder(text, options) {
|
||||
return this.locator((0, _locatorUtils.getByPlaceholderSelector)(text, options));
|
||||
}
|
||||
getByText(text, options) {
|
||||
return this.locator((0, _locatorUtils.getByTextSelector)(text, options));
|
||||
}
|
||||
getByTitle(text, options) {
|
||||
return this.locator((0, _locatorUtils.getByTitleSelector)(text, options));
|
||||
}
|
||||
getByRole(role, options = {}) {
|
||||
return this.locator((0, _locatorUtils.getByRoleSelector)(role, options));
|
||||
}
|
||||
frameLocator(selector) {
|
||||
return new _locator.FrameLocator(this, selector);
|
||||
}
|
||||
async focus(selector, options = {}) {
|
||||
await this._channel.focus({
|
||||
selector,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async textContent(selector, options = {}) {
|
||||
const value = (await this._channel.textContent({
|
||||
selector,
|
||||
...options
|
||||
})).value;
|
||||
return value === undefined ? null : value;
|
||||
}
|
||||
async innerText(selector, options = {}) {
|
||||
return (await this._channel.innerText({
|
||||
selector,
|
||||
...options
|
||||
})).value;
|
||||
}
|
||||
async innerHTML(selector, options = {}) {
|
||||
return (await this._channel.innerHTML({
|
||||
selector,
|
||||
...options
|
||||
})).value;
|
||||
}
|
||||
async getAttribute(selector, name, options = {}) {
|
||||
const value = (await this._channel.getAttribute({
|
||||
selector,
|
||||
name,
|
||||
...options
|
||||
})).value;
|
||||
return value === undefined ? null : value;
|
||||
}
|
||||
async inputValue(selector, options = {}) {
|
||||
return (await this._channel.inputValue({
|
||||
selector,
|
||||
...options
|
||||
})).value;
|
||||
}
|
||||
async isChecked(selector, options = {}) {
|
||||
return (await this._channel.isChecked({
|
||||
selector,
|
||||
...options
|
||||
})).value;
|
||||
}
|
||||
async isDisabled(selector, options = {}) {
|
||||
return (await this._channel.isDisabled({
|
||||
selector,
|
||||
...options
|
||||
})).value;
|
||||
}
|
||||
async isEditable(selector, options = {}) {
|
||||
return (await this._channel.isEditable({
|
||||
selector,
|
||||
...options
|
||||
})).value;
|
||||
}
|
||||
async isEnabled(selector, options = {}) {
|
||||
return (await this._channel.isEnabled({
|
||||
selector,
|
||||
...options
|
||||
})).value;
|
||||
}
|
||||
async isHidden(selector, options = {}) {
|
||||
return (await this._channel.isHidden({
|
||||
selector,
|
||||
...options
|
||||
})).value;
|
||||
}
|
||||
async isVisible(selector, options = {}) {
|
||||
return (await this._channel.isVisible({
|
||||
selector,
|
||||
...options
|
||||
})).value;
|
||||
}
|
||||
async hover(selector, options = {}) {
|
||||
await this._channel.hover({
|
||||
selector,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async selectOption(selector, values, options = {}) {
|
||||
return (await this._channel.selectOption({
|
||||
selector,
|
||||
...(0, _elementHandle.convertSelectOptionValues)(values),
|
||||
...options
|
||||
})).values;
|
||||
}
|
||||
async setInputFiles(selector, files, options = {}) {
|
||||
const converted = await (0, _elementHandle.convertInputFiles)(this._platform, files, this.page().context());
|
||||
await this._channel.setInputFiles({
|
||||
selector,
|
||||
...converted,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async type(selector, text, options = {}) {
|
||||
await this._channel.type({
|
||||
selector,
|
||||
text,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async press(selector, key, options = {}) {
|
||||
await this._channel.press({
|
||||
selector,
|
||||
key,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async check(selector, options = {}) {
|
||||
await this._channel.check({
|
||||
selector,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async uncheck(selector, options = {}) {
|
||||
await this._channel.uncheck({
|
||||
selector,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async setChecked(selector, checked, options) {
|
||||
if (checked) await this.check(selector, options);else await this.uncheck(selector, options);
|
||||
}
|
||||
async waitForTimeout(timeout) {
|
||||
await this._channel.waitForTimeout({
|
||||
timeout
|
||||
});
|
||||
}
|
||||
async waitForFunction(pageFunction, arg, options = {}) {
|
||||
if (typeof options.polling === 'string') (0, _assert.assert)(options.polling === 'raf', 'Unknown polling option: ' + options.polling);
|
||||
const result = await this._channel.waitForFunction({
|
||||
...options,
|
||||
pollingInterval: options.polling === 'raf' ? undefined : options.polling,
|
||||
expression: String(pageFunction),
|
||||
isFunction: typeof pageFunction === 'function',
|
||||
arg: (0, _jsHandle.serializeArgument)(arg)
|
||||
});
|
||||
return _jsHandle.JSHandle.from(result.handle);
|
||||
}
|
||||
async title() {
|
||||
return (await this._channel.title()).value;
|
||||
}
|
||||
}
|
||||
exports.Frame = Frame;
|
||||
function verifyLoadState(name, waitUntil) {
|
||||
if (waitUntil === 'networkidle0') waitUntil = 'networkidle';
|
||||
if (!_types.kLifecycleEvents.has(waitUntil)) throw new Error(`${name}: expected one of (load|domcontentloaded|networkidle|commit)`);
|
||||
return waitUntil;
|
||||
}
|
||||
97
node_modules/playwright-core/lib/client/harRouter.js
generated
vendored
Normal file
97
node_modules/playwright-core/lib/client/harRouter.js
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.HarRouter = void 0;
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class HarRouter {
|
||||
static async create(localUtils, file, notFoundAction, options) {
|
||||
const {
|
||||
harId,
|
||||
error
|
||||
} = await localUtils.harOpen({
|
||||
file
|
||||
});
|
||||
if (error) throw new Error(error);
|
||||
return new HarRouter(localUtils, harId, notFoundAction, options);
|
||||
}
|
||||
constructor(localUtils, harId, notFoundAction, options) {
|
||||
this._localUtils = void 0;
|
||||
this._harId = void 0;
|
||||
this._notFoundAction = void 0;
|
||||
this._options = void 0;
|
||||
this._localUtils = localUtils;
|
||||
this._harId = harId;
|
||||
this._options = options;
|
||||
this._notFoundAction = notFoundAction;
|
||||
}
|
||||
async _handle(route) {
|
||||
const request = route.request();
|
||||
const response = await this._localUtils.harLookup({
|
||||
harId: this._harId,
|
||||
url: request.url(),
|
||||
method: request.method(),
|
||||
headers: await request.headersArray(),
|
||||
postData: request.postDataBuffer() || undefined,
|
||||
isNavigationRequest: request.isNavigationRequest()
|
||||
});
|
||||
if (response.action === 'redirect') {
|
||||
route._platform.log('api', `HAR: ${route.request().url()} redirected to ${response.redirectURL}`);
|
||||
await route._redirectNavigationRequest(response.redirectURL);
|
||||
return;
|
||||
}
|
||||
if (response.action === 'fulfill') {
|
||||
// If the response status is -1, the request was canceled or stalled, so we just stall it here.
|
||||
// See https://github.com/microsoft/playwright/issues/29311.
|
||||
// TODO: it'd be better to abort such requests, but then we likely need to respect the timing,
|
||||
// because the request might have been stalled for a long time until the very end of the
|
||||
// test when HAR was recorded but we'd abort it immediately.
|
||||
if (response.status === -1) return;
|
||||
await route.fulfill({
|
||||
status: response.status,
|
||||
headers: Object.fromEntries(response.headers.map(h => [h.name, h.value])),
|
||||
body: response.body
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (response.action === 'error') route._platform.log('api', 'HAR: ' + response.message);
|
||||
// Report the error, but fall through to the default handler.
|
||||
|
||||
if (this._notFoundAction === 'abort') {
|
||||
await route.abort();
|
||||
return;
|
||||
}
|
||||
await route.fallback();
|
||||
}
|
||||
async addContextRoute(context) {
|
||||
await context.route(this._options.urlMatch || '**/*', route => this._handle(route));
|
||||
}
|
||||
async addPageRoute(page) {
|
||||
await page.route(this._options.urlMatch || '**/*', route => this._handle(route));
|
||||
}
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.dispose();
|
||||
}
|
||||
dispose() {
|
||||
this._localUtils.harClose({
|
||||
harId: this._harId
|
||||
}).catch(() => {});
|
||||
}
|
||||
}
|
||||
exports.HarRouter = HarRouter;
|
||||
111
node_modules/playwright-core/lib/client/input.js
generated
vendored
Normal file
111
node_modules/playwright-core/lib/client/input.js
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Touchscreen = exports.Mouse = exports.Keyboard = void 0;
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Keyboard {
|
||||
constructor(page) {
|
||||
this._page = void 0;
|
||||
this._page = page;
|
||||
}
|
||||
async down(key) {
|
||||
await this._page._channel.keyboardDown({
|
||||
key
|
||||
});
|
||||
}
|
||||
async up(key) {
|
||||
await this._page._channel.keyboardUp({
|
||||
key
|
||||
});
|
||||
}
|
||||
async insertText(text) {
|
||||
await this._page._channel.keyboardInsertText({
|
||||
text
|
||||
});
|
||||
}
|
||||
async type(text, options = {}) {
|
||||
await this._page._channel.keyboardType({
|
||||
text,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async press(key, options = {}) {
|
||||
await this._page._channel.keyboardPress({
|
||||
key,
|
||||
...options
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.Keyboard = Keyboard;
|
||||
class Mouse {
|
||||
constructor(page) {
|
||||
this._page = void 0;
|
||||
this._page = page;
|
||||
}
|
||||
async move(x, y, options = {}) {
|
||||
await this._page._channel.mouseMove({
|
||||
x,
|
||||
y,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async down(options = {}) {
|
||||
await this._page._channel.mouseDown({
|
||||
...options
|
||||
});
|
||||
}
|
||||
async up(options = {}) {
|
||||
await this._page._channel.mouseUp(options);
|
||||
}
|
||||
async click(x, y, options = {}) {
|
||||
await this._page._channel.mouseClick({
|
||||
x,
|
||||
y,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async dblclick(x, y, options = {}) {
|
||||
await this.click(x, y, {
|
||||
...options,
|
||||
clickCount: 2
|
||||
});
|
||||
}
|
||||
async wheel(deltaX, deltaY) {
|
||||
await this._page._channel.mouseWheel({
|
||||
deltaX,
|
||||
deltaY
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.Mouse = Mouse;
|
||||
class Touchscreen {
|
||||
constructor(page) {
|
||||
this._page = void 0;
|
||||
this._page = page;
|
||||
}
|
||||
async tap(x, y) {
|
||||
await this._page._channel.touchscreenTap({
|
||||
x,
|
||||
y
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.Touchscreen = Touchscreen;
|
||||
120
node_modules/playwright-core/lib/client/jsHandle.js
generated
vendored
Normal file
120
node_modules/playwright-core/lib/client/jsHandle.js
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.JSHandle = void 0;
|
||||
exports.assertMaxArguments = assertMaxArguments;
|
||||
exports.parseResult = parseResult;
|
||||
exports.serializeArgument = serializeArgument;
|
||||
var _channelOwner = require("./channelOwner");
|
||||
var _errors = require("./errors");
|
||||
var _serializers = require("../protocol/serializers");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class JSHandle extends _channelOwner.ChannelOwner {
|
||||
static from(handle) {
|
||||
return handle._object;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._preview = void 0;
|
||||
this._preview = this._initializer.preview;
|
||||
this._channel.on('previewUpdated', ({
|
||||
preview
|
||||
}) => this._preview = preview);
|
||||
}
|
||||
async evaluate(pageFunction, arg) {
|
||||
const result = await this._channel.evaluateExpression({
|
||||
expression: String(pageFunction),
|
||||
isFunction: typeof pageFunction === 'function',
|
||||
arg: serializeArgument(arg)
|
||||
});
|
||||
return parseResult(result.value);
|
||||
}
|
||||
async evaluateHandle(pageFunction, arg) {
|
||||
const result = await this._channel.evaluateExpressionHandle({
|
||||
expression: String(pageFunction),
|
||||
isFunction: typeof pageFunction === 'function',
|
||||
arg: serializeArgument(arg)
|
||||
});
|
||||
return JSHandle.from(result.handle);
|
||||
}
|
||||
async getProperty(propertyName) {
|
||||
const result = await this._channel.getProperty({
|
||||
name: propertyName
|
||||
});
|
||||
return JSHandle.from(result.handle);
|
||||
}
|
||||
async getProperties() {
|
||||
const map = new Map();
|
||||
for (const {
|
||||
name,
|
||||
value
|
||||
} of (await this._channel.getPropertyList()).properties) map.set(name, JSHandle.from(value));
|
||||
return map;
|
||||
}
|
||||
async jsonValue() {
|
||||
return parseResult((await this._channel.jsonValue()).value);
|
||||
}
|
||||
asElement() {
|
||||
return null;
|
||||
}
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.dispose();
|
||||
}
|
||||
async dispose() {
|
||||
try {
|
||||
await this._channel.dispose();
|
||||
} catch (e) {
|
||||
if ((0, _errors.isTargetClosedError)(e)) return;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
toString() {
|
||||
return this._preview;
|
||||
}
|
||||
}
|
||||
|
||||
// This function takes care of converting all JSHandles to their channels,
|
||||
// so that generic channel serializer converts them to guids.
|
||||
exports.JSHandle = JSHandle;
|
||||
function serializeArgument(arg) {
|
||||
const handles = [];
|
||||
const pushHandle = channel => {
|
||||
handles.push(channel);
|
||||
return handles.length - 1;
|
||||
};
|
||||
const value = (0, _serializers.serializeValue)(arg, value => {
|
||||
if (value instanceof JSHandle) return {
|
||||
h: pushHandle(value._channel)
|
||||
};
|
||||
return {
|
||||
fallThrough: value
|
||||
};
|
||||
});
|
||||
return {
|
||||
value,
|
||||
handles
|
||||
};
|
||||
}
|
||||
function parseResult(value) {
|
||||
return (0, _serializers.parseSerializedValue)(value, undefined);
|
||||
}
|
||||
function assertMaxArguments(count, max) {
|
||||
if (count > max) throw new Error('Too many arguments. If you need to pass more than 1 argument to the function wrap them in an object.');
|
||||
}
|
||||
35
node_modules/playwright-core/lib/client/jsonPipe.js
generated
vendored
Normal file
35
node_modules/playwright-core/lib/client/jsonPipe.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.JsonPipe = void 0;
|
||||
var _channelOwner = require("./channelOwner");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class JsonPipe extends _channelOwner.ChannelOwner {
|
||||
static from(jsonPipe) {
|
||||
return jsonPipe._object;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
}
|
||||
channel() {
|
||||
return this._channel;
|
||||
}
|
||||
}
|
||||
exports.JsonPipe = JsonPipe;
|
||||
60
node_modules/playwright-core/lib/client/localUtils.js
generated
vendored
Normal file
60
node_modules/playwright-core/lib/client/localUtils.js
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.LocalUtils = void 0;
|
||||
var _channelOwner = require("./channelOwner");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class LocalUtils extends _channelOwner.ChannelOwner {
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this.devices = void 0;
|
||||
this.markAsInternalType();
|
||||
this.devices = {};
|
||||
for (const {
|
||||
name,
|
||||
descriptor
|
||||
} of initializer.deviceDescriptors) this.devices[name] = descriptor;
|
||||
}
|
||||
async zip(params) {
|
||||
return await this._channel.zip(params);
|
||||
}
|
||||
async harOpen(params) {
|
||||
return await this._channel.harOpen(params);
|
||||
}
|
||||
async harLookup(params) {
|
||||
return await this._channel.harLookup(params);
|
||||
}
|
||||
async harClose(params) {
|
||||
return await this._channel.harClose(params);
|
||||
}
|
||||
async harUnzip(params) {
|
||||
return await this._channel.harUnzip(params);
|
||||
}
|
||||
async tracingStarted(params) {
|
||||
return await this._channel.tracingStarted(params);
|
||||
}
|
||||
async traceDiscarded(params) {
|
||||
return await this._channel.traceDiscarded(params);
|
||||
}
|
||||
async addStackToTracingNoReply(params) {
|
||||
return await this._channel.addStackToTracingNoReply(params);
|
||||
}
|
||||
}
|
||||
exports.LocalUtils = LocalUtils;
|
||||
455
node_modules/playwright-core/lib/client/locator.js
generated
vendored
Normal file
455
node_modules/playwright-core/lib/client/locator.js
generated
vendored
Normal file
@@ -0,0 +1,455 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Locator = exports.FrameLocator = void 0;
|
||||
exports.setTestIdAttribute = setTestIdAttribute;
|
||||
exports.testIdAttributeName = testIdAttributeName;
|
||||
var _elementHandle = require("./elementHandle");
|
||||
var _jsHandle = require("./jsHandle");
|
||||
var _locatorGenerators = require("../utils/isomorphic/locatorGenerators");
|
||||
var _locatorUtils = require("../utils/isomorphic/locatorUtils");
|
||||
var _stringUtils = require("../utils/isomorphic/stringUtils");
|
||||
var _rtti = require("../utils/isomorphic/rtti");
|
||||
var _time = require("../utils/isomorphic/time");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Locator {
|
||||
constructor(frame, selector, options) {
|
||||
this._frame = void 0;
|
||||
this._selector = void 0;
|
||||
this._frame = frame;
|
||||
this._selector = selector;
|
||||
if (options !== null && options !== void 0 && options.hasText) this._selector += ` >> internal:has-text=${(0, _stringUtils.escapeForTextSelector)(options.hasText, false)}`;
|
||||
if (options !== null && options !== void 0 && options.hasNotText) this._selector += ` >> internal:has-not-text=${(0, _stringUtils.escapeForTextSelector)(options.hasNotText, false)}`;
|
||||
if (options !== null && options !== void 0 && options.has) {
|
||||
const locator = options.has;
|
||||
if (locator._frame !== frame) throw new Error(`Inner "has" locator must belong to the same frame.`);
|
||||
this._selector += ` >> internal:has=` + JSON.stringify(locator._selector);
|
||||
}
|
||||
if (options !== null && options !== void 0 && options.hasNot) {
|
||||
const locator = options.hasNot;
|
||||
if (locator._frame !== frame) throw new Error(`Inner "hasNot" locator must belong to the same frame.`);
|
||||
this._selector += ` >> internal:has-not=` + JSON.stringify(locator._selector);
|
||||
}
|
||||
if ((options === null || options === void 0 ? void 0 : options.visible) !== undefined) this._selector += ` >> visible=${options.visible ? 'true' : 'false'}`;
|
||||
if (this._frame._platform.inspectCustom) this[this._frame._platform.inspectCustom] = () => this._inspect();
|
||||
}
|
||||
async _withElement(task, timeout) {
|
||||
timeout = this._frame.page()._timeoutSettings.timeout({
|
||||
timeout
|
||||
});
|
||||
const deadline = timeout ? (0, _time.monotonicTime)() + timeout : 0;
|
||||
return await this._frame._wrapApiCall(async () => {
|
||||
const result = await this._frame._channel.waitForSelector({
|
||||
selector: this._selector,
|
||||
strict: true,
|
||||
state: 'attached',
|
||||
timeout
|
||||
});
|
||||
const handle = _elementHandle.ElementHandle.fromNullable(result.element);
|
||||
if (!handle) throw new Error(`Could not resolve ${this._selector} to DOM Element`);
|
||||
try {
|
||||
return await task(handle, deadline ? deadline - (0, _time.monotonicTime)() : 0);
|
||||
} finally {
|
||||
await handle.dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
_equals(locator) {
|
||||
return this._frame === locator._frame && this._selector === locator._selector;
|
||||
}
|
||||
page() {
|
||||
return this._frame.page();
|
||||
}
|
||||
async boundingBox(options) {
|
||||
return await this._withElement(h => h.boundingBox(), options === null || options === void 0 ? void 0 : options.timeout);
|
||||
}
|
||||
async check(options = {}) {
|
||||
return await this._frame.check(this._selector, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async click(options = {}) {
|
||||
return await this._frame.click(this._selector, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async dblclick(options = {}) {
|
||||
return await this._frame.dblclick(this._selector, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async dispatchEvent(type, eventInit = {}, options) {
|
||||
return await this._frame.dispatchEvent(this._selector, type, eventInit, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async dragTo(target, options = {}) {
|
||||
return await this._frame.dragAndDrop(this._selector, target._selector, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async evaluate(pageFunction, arg, options) {
|
||||
return await this._withElement(h => h.evaluate(pageFunction, arg), options === null || options === void 0 ? void 0 : options.timeout);
|
||||
}
|
||||
async evaluateAll(pageFunction, arg) {
|
||||
return await this._frame.$$eval(this._selector, pageFunction, arg);
|
||||
}
|
||||
async evaluateHandle(pageFunction, arg, options) {
|
||||
return await this._withElement(h => h.evaluateHandle(pageFunction, arg), options === null || options === void 0 ? void 0 : options.timeout);
|
||||
}
|
||||
async fill(value, options = {}) {
|
||||
return await this._frame.fill(this._selector, value, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async clear(options = {}) {
|
||||
return await this.fill('', options);
|
||||
}
|
||||
async _highlight() {
|
||||
// VS Code extension uses this one, keep it for now.
|
||||
return await this._frame._highlight(this._selector);
|
||||
}
|
||||
async highlight() {
|
||||
return await this._frame._highlight(this._selector);
|
||||
}
|
||||
locator(selectorOrLocator, options) {
|
||||
if ((0, _rtti.isString)(selectorOrLocator)) return new Locator(this._frame, this._selector + ' >> ' + selectorOrLocator, options);
|
||||
if (selectorOrLocator._frame !== this._frame) throw new Error(`Locators must belong to the same frame.`);
|
||||
return new Locator(this._frame, this._selector + ' >> internal:chain=' + JSON.stringify(selectorOrLocator._selector), options);
|
||||
}
|
||||
getByTestId(testId) {
|
||||
return this.locator((0, _locatorUtils.getByTestIdSelector)(testIdAttributeName(), testId));
|
||||
}
|
||||
getByAltText(text, options) {
|
||||
return this.locator((0, _locatorUtils.getByAltTextSelector)(text, options));
|
||||
}
|
||||
getByLabel(text, options) {
|
||||
return this.locator((0, _locatorUtils.getByLabelSelector)(text, options));
|
||||
}
|
||||
getByPlaceholder(text, options) {
|
||||
return this.locator((0, _locatorUtils.getByPlaceholderSelector)(text, options));
|
||||
}
|
||||
getByText(text, options) {
|
||||
return this.locator((0, _locatorUtils.getByTextSelector)(text, options));
|
||||
}
|
||||
getByTitle(text, options) {
|
||||
return this.locator((0, _locatorUtils.getByTitleSelector)(text, options));
|
||||
}
|
||||
getByRole(role, options = {}) {
|
||||
return this.locator((0, _locatorUtils.getByRoleSelector)(role, options));
|
||||
}
|
||||
frameLocator(selector) {
|
||||
return new FrameLocator(this._frame, this._selector + ' >> ' + selector);
|
||||
}
|
||||
filter(options) {
|
||||
return new Locator(this._frame, this._selector, options);
|
||||
}
|
||||
async elementHandle(options) {
|
||||
return await this._frame.waitForSelector(this._selector, {
|
||||
strict: true,
|
||||
state: 'attached',
|
||||
...options
|
||||
});
|
||||
}
|
||||
async elementHandles() {
|
||||
return await this._frame.$$(this._selector);
|
||||
}
|
||||
contentFrame() {
|
||||
return new FrameLocator(this._frame, this._selector);
|
||||
}
|
||||
first() {
|
||||
return new Locator(this._frame, this._selector + ' >> nth=0');
|
||||
}
|
||||
last() {
|
||||
return new Locator(this._frame, this._selector + ` >> nth=-1`);
|
||||
}
|
||||
nth(index) {
|
||||
return new Locator(this._frame, this._selector + ` >> nth=${index}`);
|
||||
}
|
||||
and(locator) {
|
||||
if (locator._frame !== this._frame) throw new Error(`Locators must belong to the same frame.`);
|
||||
return new Locator(this._frame, this._selector + ` >> internal:and=` + JSON.stringify(locator._selector));
|
||||
}
|
||||
or(locator) {
|
||||
if (locator._frame !== this._frame) throw new Error(`Locators must belong to the same frame.`);
|
||||
return new Locator(this._frame, this._selector + ` >> internal:or=` + JSON.stringify(locator._selector));
|
||||
}
|
||||
async focus(options) {
|
||||
return await this._frame.focus(this._selector, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async blur(options) {
|
||||
await this._frame._channel.blur({
|
||||
selector: this._selector,
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async count() {
|
||||
return await this._frame._queryCount(this._selector);
|
||||
}
|
||||
async _generateLocatorString() {
|
||||
return await this._withElement(h => h._generateLocatorString());
|
||||
}
|
||||
async getAttribute(name, options) {
|
||||
return await this._frame.getAttribute(this._selector, name, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async hover(options = {}) {
|
||||
return await this._frame.hover(this._selector, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async innerHTML(options) {
|
||||
return await this._frame.innerHTML(this._selector, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async innerText(options) {
|
||||
return await this._frame.innerText(this._selector, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async inputValue(options) {
|
||||
return await this._frame.inputValue(this._selector, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async isChecked(options) {
|
||||
return await this._frame.isChecked(this._selector, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async isDisabled(options) {
|
||||
return await this._frame.isDisabled(this._selector, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async isEditable(options) {
|
||||
return await this._frame.isEditable(this._selector, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async isEnabled(options) {
|
||||
return await this._frame.isEnabled(this._selector, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async isHidden(options) {
|
||||
return await this._frame.isHidden(this._selector, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async isVisible(options) {
|
||||
return await this._frame.isVisible(this._selector, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async press(key, options = {}) {
|
||||
return await this._frame.press(this._selector, key, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async screenshot(options = {}) {
|
||||
const mask = options.mask;
|
||||
return await this._withElement((h, timeout) => h.screenshot({
|
||||
...options,
|
||||
mask,
|
||||
timeout
|
||||
}), options.timeout);
|
||||
}
|
||||
async ariaSnapshot(options) {
|
||||
const result = await this._frame._channel.ariaSnapshot({
|
||||
...options,
|
||||
id: options === null || options === void 0 ? void 0 : options._id,
|
||||
mode: options === null || options === void 0 ? void 0 : options._mode,
|
||||
selector: this._selector
|
||||
});
|
||||
return result.snapshot;
|
||||
}
|
||||
async scrollIntoViewIfNeeded(options = {}) {
|
||||
return await this._withElement((h, timeout) => h.scrollIntoViewIfNeeded({
|
||||
...options,
|
||||
timeout
|
||||
}), options.timeout);
|
||||
}
|
||||
async selectOption(values, options = {}) {
|
||||
return await this._frame.selectOption(this._selector, values, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async selectText(options = {}) {
|
||||
return await this._withElement((h, timeout) => h.selectText({
|
||||
...options,
|
||||
timeout
|
||||
}), options.timeout);
|
||||
}
|
||||
async setChecked(checked, options) {
|
||||
if (checked) await this.check(options);else await this.uncheck(options);
|
||||
}
|
||||
async setInputFiles(files, options = {}) {
|
||||
return await this._frame.setInputFiles(this._selector, files, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async tap(options = {}) {
|
||||
return await this._frame.tap(this._selector, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async textContent(options) {
|
||||
return await this._frame.textContent(this._selector, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async type(text, options = {}) {
|
||||
return await this._frame.type(this._selector, text, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async pressSequentially(text, options = {}) {
|
||||
return await this.type(text, options);
|
||||
}
|
||||
async uncheck(options = {}) {
|
||||
return await this._frame.uncheck(this._selector, {
|
||||
strict: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async all() {
|
||||
return new Array(await this.count()).fill(0).map((e, i) => this.nth(i));
|
||||
}
|
||||
async allInnerTexts() {
|
||||
return await this._frame.$$eval(this._selector, ee => ee.map(e => e.innerText));
|
||||
}
|
||||
async allTextContents() {
|
||||
return await this._frame.$$eval(this._selector, ee => ee.map(e => e.textContent || ''));
|
||||
}
|
||||
async waitFor(options) {
|
||||
await this._frame._channel.waitForSelector({
|
||||
selector: this._selector,
|
||||
strict: true,
|
||||
omitReturnValue: true,
|
||||
...options
|
||||
});
|
||||
}
|
||||
async _expect(expression, options) {
|
||||
const params = {
|
||||
selector: this._selector,
|
||||
expression,
|
||||
...options,
|
||||
isNot: !!options.isNot
|
||||
};
|
||||
params.expectedValue = (0, _jsHandle.serializeArgument)(options.expectedValue);
|
||||
const result = await this._frame._channel.expect(params);
|
||||
if (result.received !== undefined) result.received = (0, _jsHandle.parseResult)(result.received);
|
||||
return result;
|
||||
}
|
||||
_inspect() {
|
||||
return this.toString();
|
||||
}
|
||||
toString() {
|
||||
return (0, _locatorGenerators.asLocator)('javascript', this._selector);
|
||||
}
|
||||
}
|
||||
exports.Locator = Locator;
|
||||
class FrameLocator {
|
||||
constructor(frame, selector) {
|
||||
this._frame = void 0;
|
||||
this._frameSelector = void 0;
|
||||
this._frame = frame;
|
||||
this._frameSelector = selector;
|
||||
}
|
||||
locator(selectorOrLocator, options) {
|
||||
if ((0, _rtti.isString)(selectorOrLocator)) return new Locator(this._frame, this._frameSelector + ' >> internal:control=enter-frame >> ' + selectorOrLocator, options);
|
||||
if (selectorOrLocator._frame !== this._frame) throw new Error(`Locators must belong to the same frame.`);
|
||||
return new Locator(this._frame, this._frameSelector + ' >> internal:control=enter-frame >> ' + selectorOrLocator._selector, options);
|
||||
}
|
||||
getByTestId(testId) {
|
||||
return this.locator((0, _locatorUtils.getByTestIdSelector)(testIdAttributeName(), testId));
|
||||
}
|
||||
getByAltText(text, options) {
|
||||
return this.locator((0, _locatorUtils.getByAltTextSelector)(text, options));
|
||||
}
|
||||
getByLabel(text, options) {
|
||||
return this.locator((0, _locatorUtils.getByLabelSelector)(text, options));
|
||||
}
|
||||
getByPlaceholder(text, options) {
|
||||
return this.locator((0, _locatorUtils.getByPlaceholderSelector)(text, options));
|
||||
}
|
||||
getByText(text, options) {
|
||||
return this.locator((0, _locatorUtils.getByTextSelector)(text, options));
|
||||
}
|
||||
getByTitle(text, options) {
|
||||
return this.locator((0, _locatorUtils.getByTitleSelector)(text, options));
|
||||
}
|
||||
getByRole(role, options = {}) {
|
||||
return this.locator((0, _locatorUtils.getByRoleSelector)(role, options));
|
||||
}
|
||||
owner() {
|
||||
return new Locator(this._frame, this._frameSelector);
|
||||
}
|
||||
frameLocator(selector) {
|
||||
return new FrameLocator(this._frame, this._frameSelector + ' >> internal:control=enter-frame >> ' + selector);
|
||||
}
|
||||
first() {
|
||||
return new FrameLocator(this._frame, this._frameSelector + ' >> nth=0');
|
||||
}
|
||||
last() {
|
||||
return new FrameLocator(this._frame, this._frameSelector + ` >> nth=-1`);
|
||||
}
|
||||
nth(index) {
|
||||
return new FrameLocator(this._frame, this._frameSelector + ` >> nth=${index}`);
|
||||
}
|
||||
}
|
||||
exports.FrameLocator = FrameLocator;
|
||||
let _testIdAttributeName = 'data-testid';
|
||||
function testIdAttributeName() {
|
||||
return _testIdAttributeName;
|
||||
}
|
||||
function setTestIdAttribute(attributeName) {
|
||||
_testIdAttributeName = attributeName;
|
||||
}
|
||||
769
node_modules/playwright-core/lib/client/network.js
generated
vendored
Normal file
769
node_modules/playwright-core/lib/client/network.js
generated
vendored
Normal file
@@ -0,0 +1,769 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.WebSocketRouteHandler = exports.WebSocketRoute = exports.WebSocket = exports.RouteHandler = exports.Route = exports.Response = exports.Request = exports.RawHeaders = void 0;
|
||||
exports.validateHeaders = validateHeaders;
|
||||
var _channelOwner = require("./channelOwner");
|
||||
var _errors = require("./errors");
|
||||
var _events = require("./events");
|
||||
var _fetch = require("./fetch");
|
||||
var _frame = require("./frame");
|
||||
var _waiter = require("./waiter");
|
||||
var _worker = require("./worker");
|
||||
var _assert = require("../utils/isomorphic/assert");
|
||||
var _headers = require("../utils/isomorphic/headers");
|
||||
var _urlMatch = require("../utils/isomorphic/urlMatch");
|
||||
var _manualPromise = require("../utils/isomorphic/manualPromise");
|
||||
var _multimap = require("../utils/isomorphic/multimap");
|
||||
var _rtti = require("../utils/isomorphic/rtti");
|
||||
var _stackTrace = require("../utils/isomorphic/stackTrace");
|
||||
var _mimeType = require("../utils/isomorphic/mimeType");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Request extends _channelOwner.ChannelOwner {
|
||||
static from(request) {
|
||||
return request._object;
|
||||
}
|
||||
static fromNullable(request) {
|
||||
return request ? Request.from(request) : null;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._redirectedFrom = null;
|
||||
this._redirectedTo = null;
|
||||
this._failureText = null;
|
||||
this._provisionalHeaders = void 0;
|
||||
this._actualHeadersPromise = void 0;
|
||||
this._timing = void 0;
|
||||
this._fallbackOverrides = {};
|
||||
this.markAsInternalType();
|
||||
this._redirectedFrom = Request.fromNullable(initializer.redirectedFrom);
|
||||
if (this._redirectedFrom) this._redirectedFrom._redirectedTo = this;
|
||||
this._provisionalHeaders = new RawHeaders(initializer.headers);
|
||||
this._timing = {
|
||||
startTime: 0,
|
||||
domainLookupStart: -1,
|
||||
domainLookupEnd: -1,
|
||||
connectStart: -1,
|
||||
secureConnectionStart: -1,
|
||||
connectEnd: -1,
|
||||
requestStart: -1,
|
||||
responseStart: -1,
|
||||
responseEnd: -1
|
||||
};
|
||||
}
|
||||
url() {
|
||||
return this._fallbackOverrides.url || this._initializer.url;
|
||||
}
|
||||
resourceType() {
|
||||
return this._initializer.resourceType;
|
||||
}
|
||||
method() {
|
||||
return this._fallbackOverrides.method || this._initializer.method;
|
||||
}
|
||||
postData() {
|
||||
var _ref;
|
||||
return ((_ref = this._fallbackOverrides.postDataBuffer || this._initializer.postData) === null || _ref === void 0 ? void 0 : _ref.toString('utf-8')) || null;
|
||||
}
|
||||
postDataBuffer() {
|
||||
return this._fallbackOverrides.postDataBuffer || this._initializer.postData || null;
|
||||
}
|
||||
postDataJSON() {
|
||||
const postData = this.postData();
|
||||
if (!postData) return null;
|
||||
const contentType = this.headers()['content-type'];
|
||||
if (contentType !== null && contentType !== void 0 && contentType.includes('application/x-www-form-urlencoded')) {
|
||||
const entries = {};
|
||||
const parsed = new URLSearchParams(postData);
|
||||
for (const [k, v] of parsed.entries()) entries[k] = v;
|
||||
return entries;
|
||||
}
|
||||
try {
|
||||
return JSON.parse(postData);
|
||||
} catch (e) {
|
||||
throw new Error('POST data is not a valid JSON object: ' + postData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
headers() {
|
||||
if (this._fallbackOverrides.headers) return RawHeaders._fromHeadersObjectLossy(this._fallbackOverrides.headers).headers();
|
||||
return this._provisionalHeaders.headers();
|
||||
}
|
||||
async _actualHeaders() {
|
||||
if (this._fallbackOverrides.headers) return RawHeaders._fromHeadersObjectLossy(this._fallbackOverrides.headers);
|
||||
if (!this._actualHeadersPromise) {
|
||||
this._actualHeadersPromise = this._wrapApiCall(async () => {
|
||||
return new RawHeaders((await this._channel.rawRequestHeaders()).headers);
|
||||
});
|
||||
}
|
||||
return await this._actualHeadersPromise;
|
||||
}
|
||||
async allHeaders() {
|
||||
return (await this._actualHeaders()).headers();
|
||||
}
|
||||
async headersArray() {
|
||||
return (await this._actualHeaders()).headersArray();
|
||||
}
|
||||
async headerValue(name) {
|
||||
return (await this._actualHeaders()).get(name);
|
||||
}
|
||||
async response() {
|
||||
return Response.fromNullable((await this._channel.response()).response);
|
||||
}
|
||||
async _internalResponse() {
|
||||
return await this._wrapApiCall(async () => {
|
||||
return Response.fromNullable((await this._channel.response()).response);
|
||||
}, true);
|
||||
}
|
||||
frame() {
|
||||
if (!this._initializer.frame) {
|
||||
(0, _assert.assert)(this.serviceWorker());
|
||||
throw new Error('Service Worker requests do not have an associated frame.');
|
||||
}
|
||||
const frame = _frame.Frame.from(this._initializer.frame);
|
||||
if (!frame._page) {
|
||||
throw new Error(['Frame for this navigation request is not available, because the request', 'was issued before the frame is created. You can check whether the request', 'is a navigation request by calling isNavigationRequest() method.'].join('\n'));
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
_safePage() {
|
||||
var _Frame$fromNullable;
|
||||
return ((_Frame$fromNullable = _frame.Frame.fromNullable(this._initializer.frame)) === null || _Frame$fromNullable === void 0 ? void 0 : _Frame$fromNullable._page) || null;
|
||||
}
|
||||
serviceWorker() {
|
||||
return this._initializer.serviceWorker ? _worker.Worker.from(this._initializer.serviceWorker) : null;
|
||||
}
|
||||
isNavigationRequest() {
|
||||
return this._initializer.isNavigationRequest;
|
||||
}
|
||||
redirectedFrom() {
|
||||
return this._redirectedFrom;
|
||||
}
|
||||
redirectedTo() {
|
||||
return this._redirectedTo;
|
||||
}
|
||||
failure() {
|
||||
if (this._failureText === null) return null;
|
||||
return {
|
||||
errorText: this._failureText
|
||||
};
|
||||
}
|
||||
timing() {
|
||||
return this._timing;
|
||||
}
|
||||
async sizes() {
|
||||
const response = await this.response();
|
||||
if (!response) throw new Error('Unable to fetch sizes for failed request');
|
||||
return (await response._channel.sizes()).sizes;
|
||||
}
|
||||
_setResponseEndTiming(responseEndTiming) {
|
||||
this._timing.responseEnd = responseEndTiming;
|
||||
if (this._timing.responseStart === -1) this._timing.responseStart = responseEndTiming;
|
||||
}
|
||||
_finalRequest() {
|
||||
return this._redirectedTo ? this._redirectedTo._finalRequest() : this;
|
||||
}
|
||||
_applyFallbackOverrides(overrides) {
|
||||
if (overrides.url) this._fallbackOverrides.url = overrides.url;
|
||||
if (overrides.method) this._fallbackOverrides.method = overrides.method;
|
||||
if (overrides.headers) this._fallbackOverrides.headers = overrides.headers;
|
||||
if ((0, _rtti.isString)(overrides.postData)) this._fallbackOverrides.postDataBuffer = Buffer.from(overrides.postData, 'utf-8');else if (overrides.postData instanceof Buffer) this._fallbackOverrides.postDataBuffer = overrides.postData;else if (overrides.postData) this._fallbackOverrides.postDataBuffer = Buffer.from(JSON.stringify(overrides.postData), 'utf-8');
|
||||
}
|
||||
_fallbackOverridesForContinue() {
|
||||
return this._fallbackOverrides;
|
||||
}
|
||||
_targetClosedScope() {
|
||||
var _this$serviceWorker, _this$_safePage;
|
||||
return ((_this$serviceWorker = this.serviceWorker()) === null || _this$serviceWorker === void 0 ? void 0 : _this$serviceWorker._closedScope) || ((_this$_safePage = this._safePage()) === null || _this$_safePage === void 0 ? void 0 : _this$_safePage._closedOrCrashedScope) || new _manualPromise.LongStandingScope();
|
||||
}
|
||||
}
|
||||
exports.Request = Request;
|
||||
class Route extends _channelOwner.ChannelOwner {
|
||||
static from(route) {
|
||||
return route._object;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._handlingPromise = null;
|
||||
this._context = void 0;
|
||||
this._didThrow = false;
|
||||
this.markAsInternalType();
|
||||
}
|
||||
request() {
|
||||
return Request.from(this._initializer.request);
|
||||
}
|
||||
async _raceWithTargetClose(promise) {
|
||||
// When page closes or crashes, we catch any potential rejects from this Route.
|
||||
// Note that page could be missing when routing popup's initial request that
|
||||
// does not have a Page initialized just yet.
|
||||
return await this.request()._targetClosedScope().safeRace(promise);
|
||||
}
|
||||
async _startHandling() {
|
||||
this._handlingPromise = new _manualPromise.ManualPromise();
|
||||
return await this._handlingPromise;
|
||||
}
|
||||
async fallback(options = {}) {
|
||||
this._checkNotHandled();
|
||||
this.request()._applyFallbackOverrides(options);
|
||||
this._reportHandled(false);
|
||||
}
|
||||
async abort(errorCode) {
|
||||
await this._handleRoute(async () => {
|
||||
await this._raceWithTargetClose(this._channel.abort({
|
||||
errorCode
|
||||
}));
|
||||
});
|
||||
}
|
||||
async _redirectNavigationRequest(url) {
|
||||
await this._handleRoute(async () => {
|
||||
await this._raceWithTargetClose(this._channel.redirectNavigationRequest({
|
||||
url
|
||||
}));
|
||||
});
|
||||
}
|
||||
async fetch(options = {}) {
|
||||
return await this._wrapApiCall(async () => {
|
||||
return await this._context.request._innerFetch({
|
||||
request: this.request(),
|
||||
data: options.postData,
|
||||
...options
|
||||
});
|
||||
});
|
||||
}
|
||||
async fulfill(options = {}) {
|
||||
await this._handleRoute(async () => {
|
||||
await this._wrapApiCall(async () => {
|
||||
await this._innerFulfill(options);
|
||||
});
|
||||
});
|
||||
}
|
||||
async _handleRoute(callback) {
|
||||
this._checkNotHandled();
|
||||
try {
|
||||
await callback();
|
||||
this._reportHandled(true);
|
||||
} catch (e) {
|
||||
this._didThrow = true;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
async _innerFulfill(options = {}) {
|
||||
let fetchResponseUid;
|
||||
let {
|
||||
status: statusOption,
|
||||
headers: headersOption,
|
||||
body
|
||||
} = options;
|
||||
if (options.json !== undefined) {
|
||||
(0, _assert.assert)(options.body === undefined, 'Can specify either body or json parameters');
|
||||
body = JSON.stringify(options.json);
|
||||
}
|
||||
if (options.response instanceof _fetch.APIResponse) {
|
||||
statusOption !== null && statusOption !== void 0 ? statusOption : statusOption = options.response.status();
|
||||
headersOption !== null && headersOption !== void 0 ? headersOption : headersOption = options.response.headers();
|
||||
if (body === undefined && options.path === undefined) {
|
||||
if (options.response._request._connection === this._connection) fetchResponseUid = options.response._fetchUid();else body = await options.response.body();
|
||||
}
|
||||
}
|
||||
let isBase64 = false;
|
||||
let length = 0;
|
||||
if (options.path) {
|
||||
const buffer = await this._platform.fs().promises.readFile(options.path);
|
||||
body = buffer.toString('base64');
|
||||
isBase64 = true;
|
||||
length = buffer.length;
|
||||
} else if ((0, _rtti.isString)(body)) {
|
||||
isBase64 = false;
|
||||
length = Buffer.byteLength(body);
|
||||
} else if (body) {
|
||||
length = body.length;
|
||||
body = body.toString('base64');
|
||||
isBase64 = true;
|
||||
}
|
||||
const headers = {};
|
||||
for (const header of Object.keys(headersOption || {})) headers[header.toLowerCase()] = String(headersOption[header]);
|
||||
if (options.contentType) headers['content-type'] = String(options.contentType);else if (options.json) headers['content-type'] = 'application/json';else if (options.path) headers['content-type'] = (0, _mimeType.getMimeTypeForPath)(options.path) || 'application/octet-stream';
|
||||
if (length && !('content-length' in headers)) headers['content-length'] = String(length);
|
||||
await this._raceWithTargetClose(this._channel.fulfill({
|
||||
status: statusOption || 200,
|
||||
headers: (0, _headers.headersObjectToArray)(headers),
|
||||
body,
|
||||
isBase64,
|
||||
fetchResponseUid
|
||||
}));
|
||||
}
|
||||
async continue(options = {}) {
|
||||
await this._handleRoute(async () => {
|
||||
this.request()._applyFallbackOverrides(options);
|
||||
await this._innerContinue(false /* isFallback */);
|
||||
});
|
||||
}
|
||||
_checkNotHandled() {
|
||||
if (!this._handlingPromise) throw new Error('Route is already handled!');
|
||||
}
|
||||
_reportHandled(done) {
|
||||
const chain = this._handlingPromise;
|
||||
this._handlingPromise = null;
|
||||
chain.resolve(done);
|
||||
}
|
||||
async _innerContinue(isFallback) {
|
||||
const options = this.request()._fallbackOverridesForContinue();
|
||||
return await this._raceWithTargetClose(this._channel.continue({
|
||||
url: options.url,
|
||||
method: options.method,
|
||||
headers: options.headers ? (0, _headers.headersObjectToArray)(options.headers) : undefined,
|
||||
postData: options.postDataBuffer,
|
||||
isFallback
|
||||
}));
|
||||
}
|
||||
}
|
||||
exports.Route = Route;
|
||||
class WebSocketRoute extends _channelOwner.ChannelOwner {
|
||||
static from(route) {
|
||||
return route._object;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._onPageMessage = void 0;
|
||||
this._onPageClose = void 0;
|
||||
this._onServerMessage = void 0;
|
||||
this._onServerClose = void 0;
|
||||
this._server = void 0;
|
||||
this._connected = false;
|
||||
this.markAsInternalType();
|
||||
this._server = {
|
||||
onMessage: handler => {
|
||||
this._onServerMessage = handler;
|
||||
},
|
||||
onClose: handler => {
|
||||
this._onServerClose = handler;
|
||||
},
|
||||
connectToServer: () => {
|
||||
throw new Error(`connectToServer must be called on the page-side WebSocketRoute`);
|
||||
},
|
||||
url: () => {
|
||||
return this._initializer.url;
|
||||
},
|
||||
close: async (options = {}) => {
|
||||
await this._channel.closeServer({
|
||||
...options,
|
||||
wasClean: true
|
||||
}).catch(() => {});
|
||||
},
|
||||
send: message => {
|
||||
if ((0, _rtti.isString)(message)) this._channel.sendToServer({
|
||||
message,
|
||||
isBase64: false
|
||||
}).catch(() => {});else this._channel.sendToServer({
|
||||
message: message.toString('base64'),
|
||||
isBase64: true
|
||||
}).catch(() => {});
|
||||
},
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.close();
|
||||
}
|
||||
};
|
||||
this._channel.on('messageFromPage', ({
|
||||
message,
|
||||
isBase64
|
||||
}) => {
|
||||
if (this._onPageMessage) this._onPageMessage(isBase64 ? Buffer.from(message, 'base64') : message);else if (this._connected) this._channel.sendToServer({
|
||||
message,
|
||||
isBase64
|
||||
}).catch(() => {});
|
||||
});
|
||||
this._channel.on('messageFromServer', ({
|
||||
message,
|
||||
isBase64
|
||||
}) => {
|
||||
if (this._onServerMessage) this._onServerMessage(isBase64 ? Buffer.from(message, 'base64') : message);else this._channel.sendToPage({
|
||||
message,
|
||||
isBase64
|
||||
}).catch(() => {});
|
||||
});
|
||||
this._channel.on('closePage', ({
|
||||
code,
|
||||
reason,
|
||||
wasClean
|
||||
}) => {
|
||||
if (this._onPageClose) this._onPageClose(code, reason);else this._channel.closeServer({
|
||||
code,
|
||||
reason,
|
||||
wasClean
|
||||
}).catch(() => {});
|
||||
});
|
||||
this._channel.on('closeServer', ({
|
||||
code,
|
||||
reason,
|
||||
wasClean
|
||||
}) => {
|
||||
if (this._onServerClose) this._onServerClose(code, reason);else this._channel.closePage({
|
||||
code,
|
||||
reason,
|
||||
wasClean
|
||||
}).catch(() => {});
|
||||
});
|
||||
}
|
||||
url() {
|
||||
return this._initializer.url;
|
||||
}
|
||||
async close(options = {}) {
|
||||
await this._channel.closePage({
|
||||
...options,
|
||||
wasClean: true
|
||||
}).catch(() => {});
|
||||
}
|
||||
connectToServer() {
|
||||
if (this._connected) throw new Error('Already connected to the server');
|
||||
this._connected = true;
|
||||
this._channel.connect().catch(() => {});
|
||||
return this._server;
|
||||
}
|
||||
send(message) {
|
||||
if ((0, _rtti.isString)(message)) this._channel.sendToPage({
|
||||
message,
|
||||
isBase64: false
|
||||
}).catch(() => {});else this._channel.sendToPage({
|
||||
message: message.toString('base64'),
|
||||
isBase64: true
|
||||
}).catch(() => {});
|
||||
}
|
||||
onMessage(handler) {
|
||||
this._onPageMessage = handler;
|
||||
}
|
||||
onClose(handler) {
|
||||
this._onPageClose = handler;
|
||||
}
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.close();
|
||||
}
|
||||
async _afterHandle() {
|
||||
if (this._connected) return;
|
||||
// Ensure that websocket is "open" and can send messages without an actual server connection.
|
||||
await this._channel.ensureOpened();
|
||||
}
|
||||
}
|
||||
exports.WebSocketRoute = WebSocketRoute;
|
||||
class WebSocketRouteHandler {
|
||||
constructor(baseURL, url, handler) {
|
||||
this._baseURL = void 0;
|
||||
this.url = void 0;
|
||||
this.handler = void 0;
|
||||
this._baseURL = baseURL;
|
||||
this.url = url;
|
||||
this.handler = handler;
|
||||
}
|
||||
static prepareInterceptionPatterns(handlers) {
|
||||
const patterns = [];
|
||||
let all = false;
|
||||
for (const handler of handlers) {
|
||||
if ((0, _rtti.isString)(handler.url)) patterns.push({
|
||||
glob: handler.url
|
||||
});else if ((0, _rtti.isRegExp)(handler.url)) patterns.push({
|
||||
regexSource: handler.url.source,
|
||||
regexFlags: handler.url.flags
|
||||
});else all = true;
|
||||
}
|
||||
if (all) return [{
|
||||
glob: '**/*'
|
||||
}];
|
||||
return patterns;
|
||||
}
|
||||
matches(wsURL) {
|
||||
return (0, _urlMatch.urlMatches)(this._baseURL, wsURL, this.url);
|
||||
}
|
||||
async handle(webSocketRoute) {
|
||||
const handler = this.handler;
|
||||
await handler(webSocketRoute);
|
||||
await webSocketRoute._afterHandle();
|
||||
}
|
||||
}
|
||||
exports.WebSocketRouteHandler = WebSocketRouteHandler;
|
||||
class Response extends _channelOwner.ChannelOwner {
|
||||
static from(response) {
|
||||
return response._object;
|
||||
}
|
||||
static fromNullable(response) {
|
||||
return response ? Response.from(response) : null;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._provisionalHeaders = void 0;
|
||||
this._actualHeadersPromise = void 0;
|
||||
this._request = void 0;
|
||||
this._finishedPromise = new _manualPromise.ManualPromise();
|
||||
this.markAsInternalType();
|
||||
this._provisionalHeaders = new RawHeaders(initializer.headers);
|
||||
this._request = Request.from(this._initializer.request);
|
||||
Object.assign(this._request._timing, this._initializer.timing);
|
||||
}
|
||||
url() {
|
||||
return this._initializer.url;
|
||||
}
|
||||
ok() {
|
||||
// Status 0 is for file:// URLs
|
||||
return this._initializer.status === 0 || this._initializer.status >= 200 && this._initializer.status <= 299;
|
||||
}
|
||||
status() {
|
||||
return this._initializer.status;
|
||||
}
|
||||
statusText() {
|
||||
return this._initializer.statusText;
|
||||
}
|
||||
fromServiceWorker() {
|
||||
return this._initializer.fromServiceWorker;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
headers() {
|
||||
return this._provisionalHeaders.headers();
|
||||
}
|
||||
async _actualHeaders() {
|
||||
if (!this._actualHeadersPromise) {
|
||||
this._actualHeadersPromise = (async () => {
|
||||
return new RawHeaders((await this._channel.rawResponseHeaders()).headers);
|
||||
})();
|
||||
}
|
||||
return await this._actualHeadersPromise;
|
||||
}
|
||||
async allHeaders() {
|
||||
return (await this._actualHeaders()).headers();
|
||||
}
|
||||
async headersArray() {
|
||||
return (await this._actualHeaders()).headersArray().slice();
|
||||
}
|
||||
async headerValue(name) {
|
||||
return (await this._actualHeaders()).get(name);
|
||||
}
|
||||
async headerValues(name) {
|
||||
return (await this._actualHeaders()).getAll(name);
|
||||
}
|
||||
async finished() {
|
||||
return await this.request()._targetClosedScope().race(this._finishedPromise);
|
||||
}
|
||||
async body() {
|
||||
return (await this._channel.body()).binary;
|
||||
}
|
||||
async text() {
|
||||
const content = await this.body();
|
||||
return content.toString('utf8');
|
||||
}
|
||||
async json() {
|
||||
const content = await this.text();
|
||||
return JSON.parse(content);
|
||||
}
|
||||
request() {
|
||||
return this._request;
|
||||
}
|
||||
frame() {
|
||||
return this._request.frame();
|
||||
}
|
||||
async serverAddr() {
|
||||
return (await this._channel.serverAddr()).value || null;
|
||||
}
|
||||
async securityDetails() {
|
||||
return (await this._channel.securityDetails()).value || null;
|
||||
}
|
||||
}
|
||||
exports.Response = Response;
|
||||
class WebSocket extends _channelOwner.ChannelOwner {
|
||||
static from(webSocket) {
|
||||
return webSocket._object;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._page = void 0;
|
||||
this._isClosed = void 0;
|
||||
this._isClosed = false;
|
||||
this._page = parent;
|
||||
this._channel.on('frameSent', event => {
|
||||
if (event.opcode === 1) this.emit(_events.Events.WebSocket.FrameSent, {
|
||||
payload: event.data
|
||||
});else if (event.opcode === 2) this.emit(_events.Events.WebSocket.FrameSent, {
|
||||
payload: Buffer.from(event.data, 'base64')
|
||||
});
|
||||
});
|
||||
this._channel.on('frameReceived', event => {
|
||||
if (event.opcode === 1) this.emit(_events.Events.WebSocket.FrameReceived, {
|
||||
payload: event.data
|
||||
});else if (event.opcode === 2) this.emit(_events.Events.WebSocket.FrameReceived, {
|
||||
payload: Buffer.from(event.data, 'base64')
|
||||
});
|
||||
});
|
||||
this._channel.on('socketError', ({
|
||||
error
|
||||
}) => this.emit(_events.Events.WebSocket.Error, error));
|
||||
this._channel.on('close', () => {
|
||||
this._isClosed = true;
|
||||
this.emit(_events.Events.WebSocket.Close, this);
|
||||
});
|
||||
}
|
||||
url() {
|
||||
return this._initializer.url;
|
||||
}
|
||||
isClosed() {
|
||||
return this._isClosed;
|
||||
}
|
||||
async waitForEvent(event, optionsOrPredicate = {}) {
|
||||
return await this._wrapApiCall(async () => {
|
||||
const timeout = this._page._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
||||
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
|
||||
const waiter = _waiter.Waiter.createForEvent(this, event);
|
||||
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
|
||||
if (event !== _events.Events.WebSocket.Error) waiter.rejectOnEvent(this, _events.Events.WebSocket.Error, new Error('Socket error'));
|
||||
if (event !== _events.Events.WebSocket.Close) waiter.rejectOnEvent(this, _events.Events.WebSocket.Close, new Error('Socket closed'));
|
||||
waiter.rejectOnEvent(this._page, _events.Events.Page.Close, () => this._page._closeErrorWithReason());
|
||||
const result = await waiter.waitForEvent(this, event, predicate);
|
||||
waiter.dispose();
|
||||
return result;
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.WebSocket = WebSocket;
|
||||
function validateHeaders(headers) {
|
||||
for (const key of Object.keys(headers)) {
|
||||
const value = headers[key];
|
||||
if (!Object.is(value, undefined) && !(0, _rtti.isString)(value)) throw new Error(`Expected value of header "${key}" to be String, but "${typeof value}" is found.`);
|
||||
}
|
||||
}
|
||||
class RouteHandler {
|
||||
constructor(platform, baseURL, url, handler, times = Number.MAX_SAFE_INTEGER) {
|
||||
this.handledCount = 0;
|
||||
this._baseURL = void 0;
|
||||
this._times = void 0;
|
||||
this.url = void 0;
|
||||
this.handler = void 0;
|
||||
this._ignoreException = false;
|
||||
this._activeInvocations = new Set();
|
||||
this._savedZone = void 0;
|
||||
this._baseURL = baseURL;
|
||||
this._times = times;
|
||||
this.url = url;
|
||||
this.handler = handler;
|
||||
this._savedZone = platform.zones.current().pop();
|
||||
}
|
||||
static prepareInterceptionPatterns(handlers) {
|
||||
const patterns = [];
|
||||
let all = false;
|
||||
for (const handler of handlers) {
|
||||
if ((0, _rtti.isString)(handler.url)) patterns.push({
|
||||
glob: handler.url
|
||||
});else if ((0, _rtti.isRegExp)(handler.url)) patterns.push({
|
||||
regexSource: handler.url.source,
|
||||
regexFlags: handler.url.flags
|
||||
});else all = true;
|
||||
}
|
||||
if (all) return [{
|
||||
glob: '**/*'
|
||||
}];
|
||||
return patterns;
|
||||
}
|
||||
matches(requestURL) {
|
||||
return (0, _urlMatch.urlMatches)(this._baseURL, requestURL, this.url);
|
||||
}
|
||||
async handle(route) {
|
||||
return await this._savedZone.run(async () => this._handleImpl(route));
|
||||
}
|
||||
async _handleImpl(route) {
|
||||
const handlerInvocation = {
|
||||
complete: new _manualPromise.ManualPromise(),
|
||||
route
|
||||
};
|
||||
this._activeInvocations.add(handlerInvocation);
|
||||
try {
|
||||
return await this._handleInternal(route);
|
||||
} catch (e) {
|
||||
// If the handler was stopped (without waiting for completion), we ignore all exceptions.
|
||||
if (this._ignoreException) return false;
|
||||
if ((0, _errors.isTargetClosedError)(e)) {
|
||||
// We are failing in the handler because the target close closed.
|
||||
// Give user a hint!
|
||||
(0, _stackTrace.rewriteErrorMessage)(e, `"${e.message}" while running route callback.\nConsider awaiting \`await page.unrouteAll({ behavior: 'ignoreErrors' })\`\nbefore the end of the test to ignore remaining routes in flight.`);
|
||||
}
|
||||
throw e;
|
||||
} finally {
|
||||
handlerInvocation.complete.resolve();
|
||||
this._activeInvocations.delete(handlerInvocation);
|
||||
}
|
||||
}
|
||||
async stop(behavior) {
|
||||
// When a handler is manually unrouted or its page/context is closed we either
|
||||
// - wait for the current handler invocations to finish
|
||||
// - or do not wait, if the user opted out of it, but swallow all exceptions
|
||||
// that happen after the unroute/close.
|
||||
if (behavior === 'ignoreErrors') {
|
||||
this._ignoreException = true;
|
||||
} else {
|
||||
const promises = [];
|
||||
for (const activation of this._activeInvocations) {
|
||||
if (!activation.route._didThrow) promises.push(activation.complete);
|
||||
}
|
||||
await Promise.all(promises);
|
||||
}
|
||||
}
|
||||
async _handleInternal(route) {
|
||||
++this.handledCount;
|
||||
const handledPromise = route._startHandling();
|
||||
// Extract handler into a variable to avoid [RouteHandler.handler] in the stack.
|
||||
const handler = this.handler;
|
||||
const [handled] = await Promise.all([handledPromise, handler(route, route.request())]);
|
||||
return handled;
|
||||
}
|
||||
willExpire() {
|
||||
return this.handledCount + 1 >= this._times;
|
||||
}
|
||||
}
|
||||
exports.RouteHandler = RouteHandler;
|
||||
class RawHeaders {
|
||||
static _fromHeadersObjectLossy(headers) {
|
||||
const headersArray = Object.entries(headers).map(([name, value]) => ({
|
||||
name,
|
||||
value
|
||||
})).filter(header => header.value !== undefined);
|
||||
return new RawHeaders(headersArray);
|
||||
}
|
||||
constructor(headers) {
|
||||
this._headersArray = void 0;
|
||||
this._headersMap = new _multimap.MultiMap();
|
||||
this._headersArray = headers;
|
||||
for (const header of headers) this._headersMap.set(header.name.toLowerCase(), header.value);
|
||||
}
|
||||
get(name) {
|
||||
const values = this.getAll(name);
|
||||
if (!values || !values.length) return null;
|
||||
return values.join(name.toLowerCase() === 'set-cookie' ? '\n' : ', ');
|
||||
}
|
||||
getAll(name) {
|
||||
return [...this._headersMap.get(name.toLowerCase())];
|
||||
}
|
||||
headers() {
|
||||
const result = {};
|
||||
for (const name of this._headersMap.keys()) result[name] = this.get(name);
|
||||
return result;
|
||||
}
|
||||
headersArray() {
|
||||
return this._headersArray;
|
||||
}
|
||||
}
|
||||
exports.RawHeaders = RawHeaders;
|
||||
755
node_modules/playwright-core/lib/client/page.js
generated
vendored
Normal file
755
node_modules/playwright-core/lib/client/page.js
generated
vendored
Normal file
@@ -0,0 +1,755 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Page = exports.BindingCall = void 0;
|
||||
var _accessibility = require("./accessibility");
|
||||
var _artifact = require("./artifact");
|
||||
var _channelOwner = require("./channelOwner");
|
||||
var _clientHelper = require("./clientHelper");
|
||||
var _coverage = require("./coverage");
|
||||
var _download = require("./download");
|
||||
var _elementHandle = require("./elementHandle");
|
||||
var _errors = require("./errors");
|
||||
var _events = require("./events");
|
||||
var _fileChooser = require("./fileChooser");
|
||||
var _frame = require("./frame");
|
||||
var _harRouter = require("./harRouter");
|
||||
var _input = require("./input");
|
||||
var _jsHandle = require("./jsHandle");
|
||||
var _network = require("./network");
|
||||
var _video = require("./video");
|
||||
var _waiter = require("./waiter");
|
||||
var _worker = require("./worker");
|
||||
var _timeoutSettings = require("./timeoutSettings");
|
||||
var _assert = require("../utils/isomorphic/assert");
|
||||
var _fileUtils = require("./fileUtils");
|
||||
var _headers = require("../utils/isomorphic/headers");
|
||||
var _stringUtils = require("../utils/isomorphic/stringUtils");
|
||||
var _urlMatch = require("../utils/isomorphic/urlMatch");
|
||||
var _manualPromise = require("../utils/isomorphic/manualPromise");
|
||||
var _rtti = require("../utils/isomorphic/rtti");
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Page extends _channelOwner.ChannelOwner {
|
||||
static from(page) {
|
||||
return page._object;
|
||||
}
|
||||
static fromNullable(page) {
|
||||
return page ? Page.from(page) : null;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._browserContext = void 0;
|
||||
this._ownedContext = void 0;
|
||||
this._mainFrame = void 0;
|
||||
this._frames = new Set();
|
||||
this._workers = new Set();
|
||||
this._closed = false;
|
||||
this._closedOrCrashedScope = new _manualPromise.LongStandingScope();
|
||||
this._viewportSize = void 0;
|
||||
this._routes = [];
|
||||
this._webSocketRoutes = [];
|
||||
this.accessibility = void 0;
|
||||
this.coverage = void 0;
|
||||
this.keyboard = void 0;
|
||||
this.mouse = void 0;
|
||||
this.request = void 0;
|
||||
this.touchscreen = void 0;
|
||||
this.clock = void 0;
|
||||
this._bindings = new Map();
|
||||
this._timeoutSettings = void 0;
|
||||
this._video = null;
|
||||
this._opener = void 0;
|
||||
this._closeReason = void 0;
|
||||
this._closeWasCalled = false;
|
||||
this._harRouters = [];
|
||||
this._locatorHandlers = new Map();
|
||||
this._browserContext = parent;
|
||||
this._timeoutSettings = new _timeoutSettings.TimeoutSettings(this._platform, this._browserContext._timeoutSettings);
|
||||
this.accessibility = new _accessibility.Accessibility(this._channel);
|
||||
this.keyboard = new _input.Keyboard(this);
|
||||
this.mouse = new _input.Mouse(this);
|
||||
this.request = this._browserContext.request;
|
||||
this.touchscreen = new _input.Touchscreen(this);
|
||||
this.clock = this._browserContext.clock;
|
||||
this._mainFrame = _frame.Frame.from(initializer.mainFrame);
|
||||
this._mainFrame._page = this;
|
||||
this._frames.add(this._mainFrame);
|
||||
this._viewportSize = initializer.viewportSize || null;
|
||||
this._closed = initializer.isClosed;
|
||||
this._opener = Page.fromNullable(initializer.opener);
|
||||
this._channel.on('bindingCall', ({
|
||||
binding
|
||||
}) => this._onBinding(BindingCall.from(binding)));
|
||||
this._channel.on('close', () => this._onClose());
|
||||
this._channel.on('crash', () => this._onCrash());
|
||||
this._channel.on('download', ({
|
||||
url,
|
||||
suggestedFilename,
|
||||
artifact
|
||||
}) => {
|
||||
const artifactObject = _artifact.Artifact.from(artifact);
|
||||
this.emit(_events.Events.Page.Download, new _download.Download(this, url, suggestedFilename, artifactObject));
|
||||
});
|
||||
this._channel.on('fileChooser', ({
|
||||
element,
|
||||
isMultiple
|
||||
}) => this.emit(_events.Events.Page.FileChooser, new _fileChooser.FileChooser(this, _elementHandle.ElementHandle.from(element), isMultiple)));
|
||||
this._channel.on('frameAttached', ({
|
||||
frame
|
||||
}) => this._onFrameAttached(_frame.Frame.from(frame)));
|
||||
this._channel.on('frameDetached', ({
|
||||
frame
|
||||
}) => this._onFrameDetached(_frame.Frame.from(frame)));
|
||||
this._channel.on('locatorHandlerTriggered', ({
|
||||
uid
|
||||
}) => this._onLocatorHandlerTriggered(uid));
|
||||
this._channel.on('route', ({
|
||||
route
|
||||
}) => this._onRoute(_network.Route.from(route)));
|
||||
this._channel.on('webSocketRoute', ({
|
||||
webSocketRoute
|
||||
}) => this._onWebSocketRoute(_network.WebSocketRoute.from(webSocketRoute)));
|
||||
this._channel.on('video', ({
|
||||
artifact
|
||||
}) => {
|
||||
const artifactObject = _artifact.Artifact.from(artifact);
|
||||
this._forceVideo()._artifactReady(artifactObject);
|
||||
});
|
||||
this._channel.on('webSocket', ({
|
||||
webSocket
|
||||
}) => this.emit(_events.Events.Page.WebSocket, _network.WebSocket.from(webSocket)));
|
||||
this._channel.on('worker', ({
|
||||
worker
|
||||
}) => this._onWorker(_worker.Worker.from(worker)));
|
||||
this.coverage = new _coverage.Coverage(this._channel);
|
||||
this.once(_events.Events.Page.Close, () => this._closedOrCrashedScope.close(this._closeErrorWithReason()));
|
||||
this.once(_events.Events.Page.Crash, () => this._closedOrCrashedScope.close(new _errors.TargetClosedError()));
|
||||
this._setEventToSubscriptionMapping(new Map([[_events.Events.Page.Console, 'console'], [_events.Events.Page.Dialog, 'dialog'], [_events.Events.Page.Request, 'request'], [_events.Events.Page.Response, 'response'], [_events.Events.Page.RequestFinished, 'requestFinished'], [_events.Events.Page.RequestFailed, 'requestFailed'], [_events.Events.Page.FileChooser, 'fileChooser']]));
|
||||
}
|
||||
_onFrameAttached(frame) {
|
||||
frame._page = this;
|
||||
this._frames.add(frame);
|
||||
if (frame._parentFrame) frame._parentFrame._childFrames.add(frame);
|
||||
this.emit(_events.Events.Page.FrameAttached, frame);
|
||||
}
|
||||
_onFrameDetached(frame) {
|
||||
this._frames.delete(frame);
|
||||
frame._detached = true;
|
||||
if (frame._parentFrame) frame._parentFrame._childFrames.delete(frame);
|
||||
this.emit(_events.Events.Page.FrameDetached, frame);
|
||||
}
|
||||
async _onRoute(route) {
|
||||
route._context = this.context();
|
||||
const routeHandlers = this._routes.slice();
|
||||
for (const routeHandler of routeHandlers) {
|
||||
// If the page was closed we stall all requests right away.
|
||||
if (this._closeWasCalled || this._browserContext._closeWasCalled) return;
|
||||
if (!routeHandler.matches(route.request().url())) continue;
|
||||
const index = this._routes.indexOf(routeHandler);
|
||||
if (index === -1) continue;
|
||||
if (routeHandler.willExpire()) this._routes.splice(index, 1);
|
||||
const handled = await routeHandler.handle(route);
|
||||
if (!this._routes.length) this._wrapApiCall(() => this._updateInterceptionPatterns(), true).catch(() => {});
|
||||
if (handled) return;
|
||||
}
|
||||
await this._browserContext._onRoute(route);
|
||||
}
|
||||
async _onWebSocketRoute(webSocketRoute) {
|
||||
const routeHandler = this._webSocketRoutes.find(route => route.matches(webSocketRoute.url()));
|
||||
if (routeHandler) await routeHandler.handle(webSocketRoute);else await this._browserContext._onWebSocketRoute(webSocketRoute);
|
||||
}
|
||||
async _onBinding(bindingCall) {
|
||||
const func = this._bindings.get(bindingCall._initializer.name);
|
||||
if (func) {
|
||||
await bindingCall.call(func);
|
||||
return;
|
||||
}
|
||||
await this._browserContext._onBinding(bindingCall);
|
||||
}
|
||||
_onWorker(worker) {
|
||||
this._workers.add(worker);
|
||||
worker._page = this;
|
||||
this.emit(_events.Events.Page.Worker, worker);
|
||||
}
|
||||
_onClose() {
|
||||
this._closed = true;
|
||||
this._browserContext._pages.delete(this);
|
||||
this._browserContext._backgroundPages.delete(this);
|
||||
this._disposeHarRouters();
|
||||
this.emit(_events.Events.Page.Close, this);
|
||||
}
|
||||
_onCrash() {
|
||||
this.emit(_events.Events.Page.Crash, this);
|
||||
}
|
||||
context() {
|
||||
return this._browserContext;
|
||||
}
|
||||
async opener() {
|
||||
if (!this._opener || this._opener.isClosed()) return null;
|
||||
return this._opener;
|
||||
}
|
||||
mainFrame() {
|
||||
return this._mainFrame;
|
||||
}
|
||||
frame(frameSelector) {
|
||||
const name = (0, _rtti.isString)(frameSelector) ? frameSelector : frameSelector.name;
|
||||
const url = (0, _rtti.isObject)(frameSelector) ? frameSelector.url : undefined;
|
||||
(0, _assert.assert)(name || url, 'Either name or url matcher should be specified');
|
||||
return this.frames().find(f => {
|
||||
if (name) return f.name() === name;
|
||||
return (0, _urlMatch.urlMatches)(this._browserContext._options.baseURL, f.url(), url);
|
||||
}) || null;
|
||||
}
|
||||
frames() {
|
||||
return [...this._frames];
|
||||
}
|
||||
setDefaultNavigationTimeout(timeout) {
|
||||
this._timeoutSettings.setDefaultNavigationTimeout(timeout);
|
||||
this._wrapApiCall(async () => {
|
||||
await this._channel.setDefaultNavigationTimeoutNoReply({
|
||||
timeout
|
||||
});
|
||||
}, true).catch(() => {});
|
||||
}
|
||||
setDefaultTimeout(timeout) {
|
||||
this._timeoutSettings.setDefaultTimeout(timeout);
|
||||
this._wrapApiCall(async () => {
|
||||
await this._channel.setDefaultTimeoutNoReply({
|
||||
timeout
|
||||
});
|
||||
}, true).catch(() => {});
|
||||
}
|
||||
_forceVideo() {
|
||||
if (!this._video) this._video = new _video.Video(this, this._connection);
|
||||
return this._video;
|
||||
}
|
||||
video() {
|
||||
// Note: we are creating Video object lazily, because we do not know
|
||||
// BrowserContextOptions when constructing the page - it is assigned
|
||||
// too late during launchPersistentContext.
|
||||
if (!this._browserContext._options.recordVideo) return null;
|
||||
return this._forceVideo();
|
||||
}
|
||||
async $(selector, options) {
|
||||
return await this._mainFrame.$(selector, options);
|
||||
}
|
||||
async waitForSelector(selector, options) {
|
||||
return await this._mainFrame.waitForSelector(selector, options);
|
||||
}
|
||||
async dispatchEvent(selector, type, eventInit, options) {
|
||||
return await this._mainFrame.dispatchEvent(selector, type, eventInit, options);
|
||||
}
|
||||
async evaluateHandle(pageFunction, arg) {
|
||||
(0, _jsHandle.assertMaxArguments)(arguments.length, 2);
|
||||
return await this._mainFrame.evaluateHandle(pageFunction, arg);
|
||||
}
|
||||
async $eval(selector, pageFunction, arg) {
|
||||
(0, _jsHandle.assertMaxArguments)(arguments.length, 3);
|
||||
return await this._mainFrame.$eval(selector, pageFunction, arg);
|
||||
}
|
||||
async $$eval(selector, pageFunction, arg) {
|
||||
(0, _jsHandle.assertMaxArguments)(arguments.length, 3);
|
||||
return await this._mainFrame.$$eval(selector, pageFunction, arg);
|
||||
}
|
||||
async $$(selector) {
|
||||
return await this._mainFrame.$$(selector);
|
||||
}
|
||||
async addScriptTag(options = {}) {
|
||||
return await this._mainFrame.addScriptTag(options);
|
||||
}
|
||||
async addStyleTag(options = {}) {
|
||||
return await this._mainFrame.addStyleTag(options);
|
||||
}
|
||||
async exposeFunction(name, callback) {
|
||||
await this._channel.exposeBinding({
|
||||
name
|
||||
});
|
||||
const binding = (source, ...args) => callback(...args);
|
||||
this._bindings.set(name, binding);
|
||||
}
|
||||
async exposeBinding(name, callback, options = {}) {
|
||||
await this._channel.exposeBinding({
|
||||
name,
|
||||
needsHandle: options.handle
|
||||
});
|
||||
this._bindings.set(name, callback);
|
||||
}
|
||||
async setExtraHTTPHeaders(headers) {
|
||||
(0, _network.validateHeaders)(headers);
|
||||
await this._channel.setExtraHTTPHeaders({
|
||||
headers: (0, _headers.headersObjectToArray)(headers)
|
||||
});
|
||||
}
|
||||
url() {
|
||||
return this._mainFrame.url();
|
||||
}
|
||||
async content() {
|
||||
return await this._mainFrame.content();
|
||||
}
|
||||
async setContent(html, options) {
|
||||
return await this._mainFrame.setContent(html, options);
|
||||
}
|
||||
async goto(url, options) {
|
||||
return await this._mainFrame.goto(url, options);
|
||||
}
|
||||
async reload(options = {}) {
|
||||
const waitUntil = (0, _frame.verifyLoadState)('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
||||
return _network.Response.fromNullable((await this._channel.reload({
|
||||
...options,
|
||||
waitUntil
|
||||
})).response);
|
||||
}
|
||||
async addLocatorHandler(locator, handler, options = {}) {
|
||||
if (locator._frame !== this._mainFrame) throw new Error(`Locator must belong to the main frame of this page`);
|
||||
if (options.times === 0) return;
|
||||
const {
|
||||
uid
|
||||
} = await this._channel.registerLocatorHandler({
|
||||
selector: locator._selector,
|
||||
noWaitAfter: options.noWaitAfter
|
||||
});
|
||||
this._locatorHandlers.set(uid, {
|
||||
locator,
|
||||
handler,
|
||||
times: options.times
|
||||
});
|
||||
}
|
||||
async _onLocatorHandlerTriggered(uid) {
|
||||
let remove = false;
|
||||
try {
|
||||
const handler = this._locatorHandlers.get(uid);
|
||||
if (handler && handler.times !== 0) {
|
||||
if (handler.times !== undefined) handler.times--;
|
||||
await handler.handler(handler.locator);
|
||||
}
|
||||
remove = (handler === null || handler === void 0 ? void 0 : handler.times) === 0;
|
||||
} finally {
|
||||
if (remove) this._locatorHandlers.delete(uid);
|
||||
this._wrapApiCall(() => this._channel.resolveLocatorHandlerNoReply({
|
||||
uid,
|
||||
remove
|
||||
}), true).catch(() => {});
|
||||
}
|
||||
}
|
||||
async removeLocatorHandler(locator) {
|
||||
for (const [uid, data] of this._locatorHandlers) {
|
||||
if (data.locator._equals(locator)) {
|
||||
this._locatorHandlers.delete(uid);
|
||||
await this._channel.unregisterLocatorHandler({
|
||||
uid
|
||||
}).catch(() => {});
|
||||
}
|
||||
}
|
||||
}
|
||||
async waitForLoadState(state, options) {
|
||||
return await this._mainFrame.waitForLoadState(state, options);
|
||||
}
|
||||
async waitForNavigation(options) {
|
||||
return await this._mainFrame.waitForNavigation(options);
|
||||
}
|
||||
async waitForURL(url, options) {
|
||||
return await this._mainFrame.waitForURL(url, options);
|
||||
}
|
||||
async waitForRequest(urlOrPredicate, options = {}) {
|
||||
const predicate = async request => {
|
||||
if ((0, _rtti.isString)(urlOrPredicate) || (0, _rtti.isRegExp)(urlOrPredicate)) return (0, _urlMatch.urlMatches)(this._browserContext._options.baseURL, request.url(), urlOrPredicate);
|
||||
return await urlOrPredicate(request);
|
||||
};
|
||||
const trimmedUrl = trimUrl(urlOrPredicate);
|
||||
const logLine = trimmedUrl ? `waiting for request ${trimmedUrl}` : undefined;
|
||||
return await this._waitForEvent(_events.Events.Page.Request, {
|
||||
predicate,
|
||||
timeout: options.timeout
|
||||
}, logLine);
|
||||
}
|
||||
async waitForResponse(urlOrPredicate, options = {}) {
|
||||
const predicate = async response => {
|
||||
if ((0, _rtti.isString)(urlOrPredicate) || (0, _rtti.isRegExp)(urlOrPredicate)) return (0, _urlMatch.urlMatches)(this._browserContext._options.baseURL, response.url(), urlOrPredicate);
|
||||
return await urlOrPredicate(response);
|
||||
};
|
||||
const trimmedUrl = trimUrl(urlOrPredicate);
|
||||
const logLine = trimmedUrl ? `waiting for response ${trimmedUrl}` : undefined;
|
||||
return await this._waitForEvent(_events.Events.Page.Response, {
|
||||
predicate,
|
||||
timeout: options.timeout
|
||||
}, logLine);
|
||||
}
|
||||
async waitForEvent(event, optionsOrPredicate = {}) {
|
||||
return await this._waitForEvent(event, optionsOrPredicate, `waiting for event "${event}"`);
|
||||
}
|
||||
_closeErrorWithReason() {
|
||||
return new _errors.TargetClosedError(this._closeReason || this._browserContext._effectiveCloseReason());
|
||||
}
|
||||
async _waitForEvent(event, optionsOrPredicate, logLine) {
|
||||
return await this._wrapApiCall(async () => {
|
||||
const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
|
||||
const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
|
||||
const waiter = _waiter.Waiter.createForEvent(this, event);
|
||||
if (logLine) waiter.log(logLine);
|
||||
waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
|
||||
if (event !== _events.Events.Page.Crash) waiter.rejectOnEvent(this, _events.Events.Page.Crash, new Error('Page crashed'));
|
||||
if (event !== _events.Events.Page.Close) waiter.rejectOnEvent(this, _events.Events.Page.Close, () => this._closeErrorWithReason());
|
||||
const result = await waiter.waitForEvent(this, event, predicate);
|
||||
waiter.dispose();
|
||||
return result;
|
||||
});
|
||||
}
|
||||
async goBack(options = {}) {
|
||||
const waitUntil = (0, _frame.verifyLoadState)('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
||||
return _network.Response.fromNullable((await this._channel.goBack({
|
||||
...options,
|
||||
waitUntil
|
||||
})).response);
|
||||
}
|
||||
async goForward(options = {}) {
|
||||
const waitUntil = (0, _frame.verifyLoadState)('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
||||
return _network.Response.fromNullable((await this._channel.goForward({
|
||||
...options,
|
||||
waitUntil
|
||||
})).response);
|
||||
}
|
||||
async requestGC() {
|
||||
await this._channel.requestGC();
|
||||
}
|
||||
async emulateMedia(options = {}) {
|
||||
await this._channel.emulateMedia({
|
||||
media: options.media === null ? 'no-override' : options.media,
|
||||
colorScheme: options.colorScheme === null ? 'no-override' : options.colorScheme,
|
||||
reducedMotion: options.reducedMotion === null ? 'no-override' : options.reducedMotion,
|
||||
forcedColors: options.forcedColors === null ? 'no-override' : options.forcedColors,
|
||||
contrast: options.contrast === null ? 'no-override' : options.contrast
|
||||
});
|
||||
}
|
||||
async setViewportSize(viewportSize) {
|
||||
this._viewportSize = viewportSize;
|
||||
await this._channel.setViewportSize({
|
||||
viewportSize
|
||||
});
|
||||
}
|
||||
viewportSize() {
|
||||
return this._viewportSize;
|
||||
}
|
||||
async evaluate(pageFunction, arg) {
|
||||
(0, _jsHandle.assertMaxArguments)(arguments.length, 2);
|
||||
return await this._mainFrame.evaluate(pageFunction, arg);
|
||||
}
|
||||
async addInitScript(script, arg) {
|
||||
const source = await (0, _clientHelper.evaluationScript)(this._platform, script, arg);
|
||||
await this._channel.addInitScript({
|
||||
source
|
||||
});
|
||||
}
|
||||
async route(url, handler, options = {}) {
|
||||
this._routes.unshift(new _network.RouteHandler(this._platform, this._browserContext._options.baseURL, url, handler, options.times));
|
||||
await this._updateInterceptionPatterns();
|
||||
}
|
||||
async routeFromHAR(har, options = {}) {
|
||||
const localUtils = this._connection.localUtils();
|
||||
if (!localUtils) throw new Error('Route from har is not supported in thin clients');
|
||||
if (options.update) {
|
||||
await this._browserContext._recordIntoHAR(har, this, options);
|
||||
return;
|
||||
}
|
||||
const harRouter = await _harRouter.HarRouter.create(localUtils, har, options.notFound || 'abort', {
|
||||
urlMatch: options.url
|
||||
});
|
||||
this._harRouters.push(harRouter);
|
||||
await harRouter.addPageRoute(this);
|
||||
}
|
||||
async routeWebSocket(url, handler) {
|
||||
this._webSocketRoutes.unshift(new _network.WebSocketRouteHandler(this._browserContext._options.baseURL, url, handler));
|
||||
await this._updateWebSocketInterceptionPatterns();
|
||||
}
|
||||
_disposeHarRouters() {
|
||||
this._harRouters.forEach(router => router.dispose());
|
||||
this._harRouters = [];
|
||||
}
|
||||
async unrouteAll(options) {
|
||||
await this._unrouteInternal(this._routes, [], options === null || options === void 0 ? void 0 : options.behavior);
|
||||
this._disposeHarRouters();
|
||||
}
|
||||
async unroute(url, handler) {
|
||||
const removed = [];
|
||||
const remaining = [];
|
||||
for (const route of this._routes) {
|
||||
if ((0, _urlMatch.urlMatchesEqual)(route.url, url) && (!handler || route.handler === handler)) removed.push(route);else remaining.push(route);
|
||||
}
|
||||
await this._unrouteInternal(removed, remaining, 'default');
|
||||
}
|
||||
async _unrouteInternal(removed, remaining, behavior) {
|
||||
this._routes = remaining;
|
||||
await this._updateInterceptionPatterns();
|
||||
if (!behavior || behavior === 'default') return;
|
||||
const promises = removed.map(routeHandler => routeHandler.stop(behavior));
|
||||
await Promise.all(promises);
|
||||
}
|
||||
async _updateInterceptionPatterns() {
|
||||
const patterns = _network.RouteHandler.prepareInterceptionPatterns(this._routes);
|
||||
await this._channel.setNetworkInterceptionPatterns({
|
||||
patterns
|
||||
});
|
||||
}
|
||||
async _updateWebSocketInterceptionPatterns() {
|
||||
const patterns = _network.WebSocketRouteHandler.prepareInterceptionPatterns(this._webSocketRoutes);
|
||||
await this._channel.setWebSocketInterceptionPatterns({
|
||||
patterns
|
||||
});
|
||||
}
|
||||
async screenshot(options = {}) {
|
||||
const mask = options.mask;
|
||||
const copy = {
|
||||
...options,
|
||||
mask: undefined
|
||||
};
|
||||
if (!copy.type) copy.type = (0, _elementHandle.determineScreenshotType)(options);
|
||||
if (mask) {
|
||||
copy.mask = mask.map(locator => ({
|
||||
frame: locator._frame._channel,
|
||||
selector: locator._selector
|
||||
}));
|
||||
}
|
||||
const result = await this._channel.screenshot(copy);
|
||||
if (options.path) {
|
||||
await (0, _fileUtils.mkdirIfNeeded)(this._platform, options.path);
|
||||
await this._platform.fs().promises.writeFile(options.path, result.binary);
|
||||
}
|
||||
return result.binary;
|
||||
}
|
||||
async _expectScreenshot(options) {
|
||||
const mask = options !== null && options !== void 0 && options.mask ? options === null || options === void 0 ? void 0 : options.mask.map(locator => ({
|
||||
frame: locator._frame._channel,
|
||||
selector: locator._selector
|
||||
})) : undefined;
|
||||
const locator = options.locator ? {
|
||||
frame: options.locator._frame._channel,
|
||||
selector: options.locator._selector
|
||||
} : undefined;
|
||||
return await this._channel.expectScreenshot({
|
||||
...options,
|
||||
isNot: !!options.isNot,
|
||||
locator,
|
||||
mask
|
||||
});
|
||||
}
|
||||
async title() {
|
||||
return await this._mainFrame.title();
|
||||
}
|
||||
async bringToFront() {
|
||||
await this._channel.bringToFront();
|
||||
}
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.close();
|
||||
}
|
||||
async close(options = {}) {
|
||||
this._closeReason = options.reason;
|
||||
this._closeWasCalled = true;
|
||||
try {
|
||||
if (this._ownedContext) await this._ownedContext.close();else await this._channel.close(options);
|
||||
} catch (e) {
|
||||
if ((0, _errors.isTargetClosedError)(e) && !options.runBeforeUnload) return;
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
isClosed() {
|
||||
return this._closed;
|
||||
}
|
||||
async click(selector, options) {
|
||||
return await this._mainFrame.click(selector, options);
|
||||
}
|
||||
async dragAndDrop(source, target, options) {
|
||||
return await this._mainFrame.dragAndDrop(source, target, options);
|
||||
}
|
||||
async dblclick(selector, options) {
|
||||
return await this._mainFrame.dblclick(selector, options);
|
||||
}
|
||||
async tap(selector, options) {
|
||||
return await this._mainFrame.tap(selector, options);
|
||||
}
|
||||
async fill(selector, value, options) {
|
||||
return await this._mainFrame.fill(selector, value, options);
|
||||
}
|
||||
locator(selector, options) {
|
||||
return this.mainFrame().locator(selector, options);
|
||||
}
|
||||
getByTestId(testId) {
|
||||
return this.mainFrame().getByTestId(testId);
|
||||
}
|
||||
getByAltText(text, options) {
|
||||
return this.mainFrame().getByAltText(text, options);
|
||||
}
|
||||
getByLabel(text, options) {
|
||||
return this.mainFrame().getByLabel(text, options);
|
||||
}
|
||||
getByPlaceholder(text, options) {
|
||||
return this.mainFrame().getByPlaceholder(text, options);
|
||||
}
|
||||
getByText(text, options) {
|
||||
return this.mainFrame().getByText(text, options);
|
||||
}
|
||||
getByTitle(text, options) {
|
||||
return this.mainFrame().getByTitle(text, options);
|
||||
}
|
||||
getByRole(role, options = {}) {
|
||||
return this.mainFrame().getByRole(role, options);
|
||||
}
|
||||
frameLocator(selector) {
|
||||
return this.mainFrame().frameLocator(selector);
|
||||
}
|
||||
async focus(selector, options) {
|
||||
return await this._mainFrame.focus(selector, options);
|
||||
}
|
||||
async textContent(selector, options) {
|
||||
return await this._mainFrame.textContent(selector, options);
|
||||
}
|
||||
async innerText(selector, options) {
|
||||
return await this._mainFrame.innerText(selector, options);
|
||||
}
|
||||
async innerHTML(selector, options) {
|
||||
return await this._mainFrame.innerHTML(selector, options);
|
||||
}
|
||||
async getAttribute(selector, name, options) {
|
||||
return await this._mainFrame.getAttribute(selector, name, options);
|
||||
}
|
||||
async inputValue(selector, options) {
|
||||
return await this._mainFrame.inputValue(selector, options);
|
||||
}
|
||||
async isChecked(selector, options) {
|
||||
return await this._mainFrame.isChecked(selector, options);
|
||||
}
|
||||
async isDisabled(selector, options) {
|
||||
return await this._mainFrame.isDisabled(selector, options);
|
||||
}
|
||||
async isEditable(selector, options) {
|
||||
return await this._mainFrame.isEditable(selector, options);
|
||||
}
|
||||
async isEnabled(selector, options) {
|
||||
return await this._mainFrame.isEnabled(selector, options);
|
||||
}
|
||||
async isHidden(selector, options) {
|
||||
return await this._mainFrame.isHidden(selector, options);
|
||||
}
|
||||
async isVisible(selector, options) {
|
||||
return await this._mainFrame.isVisible(selector, options);
|
||||
}
|
||||
async hover(selector, options) {
|
||||
return await this._mainFrame.hover(selector, options);
|
||||
}
|
||||
async selectOption(selector, values, options) {
|
||||
return await this._mainFrame.selectOption(selector, values, options);
|
||||
}
|
||||
async setInputFiles(selector, files, options) {
|
||||
return await this._mainFrame.setInputFiles(selector, files, options);
|
||||
}
|
||||
async type(selector, text, options) {
|
||||
return await this._mainFrame.type(selector, text, options);
|
||||
}
|
||||
async press(selector, key, options) {
|
||||
return await this._mainFrame.press(selector, key, options);
|
||||
}
|
||||
async check(selector, options) {
|
||||
return await this._mainFrame.check(selector, options);
|
||||
}
|
||||
async uncheck(selector, options) {
|
||||
return await this._mainFrame.uncheck(selector, options);
|
||||
}
|
||||
async setChecked(selector, checked, options) {
|
||||
return await this._mainFrame.setChecked(selector, checked, options);
|
||||
}
|
||||
async waitForTimeout(timeout) {
|
||||
return await this._mainFrame.waitForTimeout(timeout);
|
||||
}
|
||||
async waitForFunction(pageFunction, arg, options) {
|
||||
return await this._mainFrame.waitForFunction(pageFunction, arg, options);
|
||||
}
|
||||
workers() {
|
||||
return [...this._workers];
|
||||
}
|
||||
async pause(_options) {
|
||||
var _this$_instrumentatio;
|
||||
if (this._platform.isJSDebuggerAttached()) return;
|
||||
const defaultNavigationTimeout = this._browserContext._timeoutSettings.defaultNavigationTimeout();
|
||||
const defaultTimeout = this._browserContext._timeoutSettings.defaultTimeout();
|
||||
this._browserContext.setDefaultNavigationTimeout(0);
|
||||
this._browserContext.setDefaultTimeout(0);
|
||||
(_this$_instrumentatio = this._instrumentation) === null || _this$_instrumentatio === void 0 || _this$_instrumentatio.onWillPause({
|
||||
keepTestTimeout: !!(_options !== null && _options !== void 0 && _options.__testHookKeepTestTimeout)
|
||||
});
|
||||
await this._closedOrCrashedScope.safeRace(this.context()._channel.pause());
|
||||
this._browserContext.setDefaultNavigationTimeout(defaultNavigationTimeout);
|
||||
this._browserContext.setDefaultTimeout(defaultTimeout);
|
||||
}
|
||||
async pdf(options = {}) {
|
||||
const transportOptions = {
|
||||
...options
|
||||
};
|
||||
if (transportOptions.margin) transportOptions.margin = {
|
||||
...transportOptions.margin
|
||||
};
|
||||
if (typeof options.width === 'number') transportOptions.width = options.width + 'px';
|
||||
if (typeof options.height === 'number') transportOptions.height = options.height + 'px';
|
||||
for (const margin of ['top', 'right', 'bottom', 'left']) {
|
||||
const index = margin;
|
||||
if (options.margin && typeof options.margin[index] === 'number') transportOptions.margin[index] = transportOptions.margin[index] + 'px';
|
||||
}
|
||||
const result = await this._channel.pdf(transportOptions);
|
||||
if (options.path) {
|
||||
const platform = this._platform;
|
||||
await platform.fs().promises.mkdir(platform.path().dirname(options.path), {
|
||||
recursive: true
|
||||
});
|
||||
await platform.fs().promises.writeFile(options.path, result.pdf);
|
||||
}
|
||||
return result.pdf;
|
||||
}
|
||||
}
|
||||
exports.Page = Page;
|
||||
class BindingCall extends _channelOwner.ChannelOwner {
|
||||
static from(channel) {
|
||||
return channel._object;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
}
|
||||
async call(func) {
|
||||
try {
|
||||
const frame = _frame.Frame.from(this._initializer.frame);
|
||||
const source = {
|
||||
context: frame._page.context(),
|
||||
page: frame._page,
|
||||
frame
|
||||
};
|
||||
let result;
|
||||
if (this._initializer.handle) result = await func(source, _jsHandle.JSHandle.from(this._initializer.handle));else result = await func(source, ...this._initializer.args.map(_jsHandle.parseResult));
|
||||
this._channel.resolve({
|
||||
result: (0, _jsHandle.serializeArgument)(result)
|
||||
}).catch(() => {});
|
||||
} catch (e) {
|
||||
this._channel.reject({
|
||||
error: (0, _errors.serializeError)(e)
|
||||
}).catch(() => {});
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.BindingCall = BindingCall;
|
||||
function trimUrl(param) {
|
||||
if ((0, _rtti.isRegExp)(param)) return `/${(0, _stringUtils.trimStringWithEllipsis)(param.source, 50)}/${param.flags}`;
|
||||
if ((0, _rtti.isString)(param)) return `"${(0, _stringUtils.trimStringWithEllipsis)(param, 50)}"`;
|
||||
}
|
||||
71
node_modules/playwright-core/lib/client/platform.js
generated
vendored
Normal file
71
node_modules/playwright-core/lib/client/platform.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.emptyPlatform = void 0;
|
||||
var _colors = require("../utils/isomorphic/colors");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const noopZone = {
|
||||
push: () => noopZone,
|
||||
pop: () => noopZone,
|
||||
run: func => func(),
|
||||
data: () => undefined
|
||||
};
|
||||
const emptyPlatform = exports.emptyPlatform = {
|
||||
name: 'empty',
|
||||
boxedStackPrefixes: () => [],
|
||||
calculateSha1: async () => {
|
||||
throw new Error('Not implemented');
|
||||
},
|
||||
colors: _colors.webColors,
|
||||
createGuid: () => {
|
||||
throw new Error('Not implemented');
|
||||
},
|
||||
defaultMaxListeners: () => 10,
|
||||
env: {},
|
||||
fs: () => {
|
||||
throw new Error('Not implemented');
|
||||
},
|
||||
inspectCustom: undefined,
|
||||
isDebugMode: () => false,
|
||||
isJSDebuggerAttached: () => false,
|
||||
isLogEnabled(name) {
|
||||
return false;
|
||||
},
|
||||
isUnderTest: () => false,
|
||||
log(name, message) {},
|
||||
path: () => {
|
||||
throw new Error('Function not implemented.');
|
||||
},
|
||||
pathSeparator: '/',
|
||||
showInternalStackFrames: () => false,
|
||||
streamFile(path, writable) {
|
||||
throw new Error('Streams are not available');
|
||||
},
|
||||
streamReadable: channel => {
|
||||
throw new Error('Streams are not available');
|
||||
},
|
||||
streamWritable: channel => {
|
||||
throw new Error('Streams are not available');
|
||||
},
|
||||
zones: {
|
||||
empty: noopZone,
|
||||
current: () => noopZone
|
||||
}
|
||||
};
|
||||
100
node_modules/playwright-core/lib/client/playwright.js
generated
vendored
Normal file
100
node_modules/playwright-core/lib/client/playwright.js
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Playwright = void 0;
|
||||
var _android = require("./android");
|
||||
var _browser = require("./browser");
|
||||
var _browserType = require("./browserType");
|
||||
var _channelOwner = require("./channelOwner");
|
||||
var _electron = require("./electron");
|
||||
var _errors = require("./errors");
|
||||
var _fetch = require("./fetch");
|
||||
var _selectors = require("./selectors");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Playwright extends _channelOwner.ChannelOwner {
|
||||
constructor(parent, type, guid, initializer) {
|
||||
var _this$_connection$loc, _this$_connection$loc2;
|
||||
super(parent, type, guid, initializer);
|
||||
this._android = void 0;
|
||||
this._electron = void 0;
|
||||
this._bidiChromium = void 0;
|
||||
this._bidiFirefox = void 0;
|
||||
this.chromium = void 0;
|
||||
this.firefox = void 0;
|
||||
this.webkit = void 0;
|
||||
this.devices = void 0;
|
||||
this.selectors = void 0;
|
||||
this.request = void 0;
|
||||
this.errors = void 0;
|
||||
// Instrumentation.
|
||||
this._defaultLaunchOptions = void 0;
|
||||
this._defaultContextOptions = void 0;
|
||||
this._defaultContextTimeout = void 0;
|
||||
this._defaultContextNavigationTimeout = void 0;
|
||||
this.request = new _fetch.APIRequest(this);
|
||||
this.chromium = _browserType.BrowserType.from(initializer.chromium);
|
||||
this.chromium._playwright = this;
|
||||
this.firefox = _browserType.BrowserType.from(initializer.firefox);
|
||||
this.firefox._playwright = this;
|
||||
this.webkit = _browserType.BrowserType.from(initializer.webkit);
|
||||
this.webkit._playwright = this;
|
||||
this._android = _android.Android.from(initializer.android);
|
||||
this._electron = _electron.Electron.from(initializer.electron);
|
||||
this._bidiChromium = _browserType.BrowserType.from(initializer.bidiChromium);
|
||||
this._bidiChromium._playwright = this;
|
||||
this._bidiFirefox = _browserType.BrowserType.from(initializer.bidiFirefox);
|
||||
this._bidiFirefox._playwright = this;
|
||||
this.devices = (_this$_connection$loc = (_this$_connection$loc2 = this._connection.localUtils()) === null || _this$_connection$loc2 === void 0 ? void 0 : _this$_connection$loc2.devices) !== null && _this$_connection$loc !== void 0 ? _this$_connection$loc : {};
|
||||
this.selectors = new _selectors.Selectors();
|
||||
this.errors = {
|
||||
TimeoutError: _errors.TimeoutError
|
||||
};
|
||||
const selectorsOwner = _selectors.SelectorsOwner.from(initializer.selectors);
|
||||
this.selectors._addChannel(selectorsOwner);
|
||||
this._connection.on('close', () => {
|
||||
this.selectors._removeChannel(selectorsOwner);
|
||||
});
|
||||
global._playwrightInstance = this;
|
||||
}
|
||||
_setSelectors(selectors) {
|
||||
const selectorsOwner = _selectors.SelectorsOwner.from(this._initializer.selectors);
|
||||
this.selectors._removeChannel(selectorsOwner);
|
||||
this.selectors = selectors;
|
||||
this.selectors._addChannel(selectorsOwner);
|
||||
}
|
||||
static from(channel) {
|
||||
return channel._object;
|
||||
}
|
||||
_browserTypes() {
|
||||
return [this.chromium, this.firefox, this.webkit, this._bidiChromium, this._bidiFirefox];
|
||||
}
|
||||
_preLaunchedBrowser() {
|
||||
const browser = _browser.Browser.from(this._initializer.preLaunchedBrowser);
|
||||
browser._browserType = this[browser._name];
|
||||
return browser;
|
||||
}
|
||||
_allContexts() {
|
||||
return this._browserTypes().flatMap(type => [...type._contexts]);
|
||||
}
|
||||
_allPages() {
|
||||
return this._allContexts().flatMap(context => context.pages());
|
||||
}
|
||||
}
|
||||
exports.Playwright = Playwright;
|
||||
73
node_modules/playwright-core/lib/client/selectors.js
generated
vendored
Normal file
73
node_modules/playwright-core/lib/client/selectors.js
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.SelectorsOwner = exports.Selectors = void 0;
|
||||
exports.setPlatformForSelectors = setPlatformForSelectors;
|
||||
var _channelOwner = require("./channelOwner");
|
||||
var _clientHelper = require("./clientHelper");
|
||||
var _locator = require("./locator");
|
||||
var _platform = require("./platform");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
let platform = _platform.emptyPlatform;
|
||||
function setPlatformForSelectors(p) {
|
||||
platform = p;
|
||||
}
|
||||
class Selectors {
|
||||
constructor() {
|
||||
this._channels = new Set();
|
||||
this._registrations = [];
|
||||
}
|
||||
async register(name, script, options = {}) {
|
||||
const source = await (0, _clientHelper.evaluationScript)(platform, script, undefined, false);
|
||||
const params = {
|
||||
...options,
|
||||
name,
|
||||
source
|
||||
};
|
||||
for (const channel of this._channels) await channel._channel.register(params);
|
||||
this._registrations.push(params);
|
||||
}
|
||||
setTestIdAttribute(attributeName) {
|
||||
(0, _locator.setTestIdAttribute)(attributeName);
|
||||
for (const channel of this._channels) channel._channel.setTestIdAttributeName({
|
||||
testIdAttributeName: attributeName
|
||||
}).catch(() => {});
|
||||
}
|
||||
_addChannel(channel) {
|
||||
this._channels.add(channel);
|
||||
for (const params of this._registrations) {
|
||||
// This should not fail except for connection closure, but just in case we catch.
|
||||
channel._channel.register(params).catch(() => {});
|
||||
channel._channel.setTestIdAttributeName({
|
||||
testIdAttributeName: (0, _locator.testIdAttributeName)()
|
||||
}).catch(() => {});
|
||||
}
|
||||
}
|
||||
_removeChannel(channel) {
|
||||
this._channels.delete(channel);
|
||||
}
|
||||
}
|
||||
exports.Selectors = Selectors;
|
||||
class SelectorsOwner extends _channelOwner.ChannelOwner {
|
||||
static from(browser) {
|
||||
return browser._object;
|
||||
}
|
||||
}
|
||||
exports.SelectorsOwner = SelectorsOwner;
|
||||
35
node_modules/playwright-core/lib/client/stream.js
generated
vendored
Normal file
35
node_modules/playwright-core/lib/client/stream.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Stream = void 0;
|
||||
var _channelOwner = require("./channelOwner");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Stream extends _channelOwner.ChannelOwner {
|
||||
static from(Stream) {
|
||||
return Stream._object;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
}
|
||||
stream() {
|
||||
return this._platform.streamReadable(this._channel);
|
||||
}
|
||||
}
|
||||
exports.Stream = Stream;
|
||||
65
node_modules/playwright-core/lib/client/timeoutSettings.js
generated
vendored
Normal file
65
node_modules/playwright-core/lib/client/timeoutSettings.js
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.TimeoutSettings = exports.DEFAULT_TIMEOUT = exports.DEFAULT_LAUNCH_TIMEOUT = void 0;
|
||||
/**
|
||||
* Copyright 2019 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Keep in sync with server.
|
||||
const DEFAULT_TIMEOUT = exports.DEFAULT_TIMEOUT = 30000;
|
||||
const DEFAULT_LAUNCH_TIMEOUT = exports.DEFAULT_LAUNCH_TIMEOUT = 3 * 60 * 1000; // 3 minutes
|
||||
|
||||
class TimeoutSettings {
|
||||
constructor(platform, parent) {
|
||||
this._parent = void 0;
|
||||
this._defaultTimeout = void 0;
|
||||
this._defaultNavigationTimeout = void 0;
|
||||
this._platform = void 0;
|
||||
this._parent = parent;
|
||||
this._platform = platform;
|
||||
}
|
||||
setDefaultTimeout(timeout) {
|
||||
this._defaultTimeout = timeout;
|
||||
}
|
||||
setDefaultNavigationTimeout(timeout) {
|
||||
this._defaultNavigationTimeout = timeout;
|
||||
}
|
||||
defaultNavigationTimeout() {
|
||||
return this._defaultNavigationTimeout;
|
||||
}
|
||||
defaultTimeout() {
|
||||
return this._defaultTimeout;
|
||||
}
|
||||
navigationTimeout(options) {
|
||||
if (typeof options.timeout === 'number') return options.timeout;
|
||||
if (this._defaultNavigationTimeout !== undefined) return this._defaultNavigationTimeout;
|
||||
if (this._platform.isDebugMode()) return 0;
|
||||
if (this._defaultTimeout !== undefined) return this._defaultTimeout;
|
||||
if (this._parent) return this._parent.navigationTimeout(options);
|
||||
return DEFAULT_TIMEOUT;
|
||||
}
|
||||
timeout(options) {
|
||||
if (typeof options.timeout === 'number') return options.timeout;
|
||||
if (this._platform.isDebugMode()) return 0;
|
||||
if (this._defaultTimeout !== undefined) return this._defaultTimeout;
|
||||
if (this._parent) return this._parent.timeout(options);
|
||||
return DEFAULT_TIMEOUT;
|
||||
}
|
||||
}
|
||||
exports.TimeoutSettings = TimeoutSettings;
|
||||
150
node_modules/playwright-core/lib/client/tracing.js
generated
vendored
Normal file
150
node_modules/playwright-core/lib/client/tracing.js
generated
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Tracing = void 0;
|
||||
var _artifact = require("./artifact");
|
||||
var _channelOwner = require("./channelOwner");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Tracing extends _channelOwner.ChannelOwner {
|
||||
static from(channel) {
|
||||
return channel._object;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._includeSources = false;
|
||||
this._tracesDir = void 0;
|
||||
this._stacksId = void 0;
|
||||
this._isTracing = false;
|
||||
this.markAsInternalType();
|
||||
}
|
||||
async start(options = {}) {
|
||||
this._includeSources = !!options.sources;
|
||||
await this._channel.tracingStart({
|
||||
name: options.name,
|
||||
snapshots: options.snapshots,
|
||||
screenshots: options.screenshots,
|
||||
live: options._live
|
||||
});
|
||||
const {
|
||||
traceName
|
||||
} = await this._channel.tracingStartChunk({
|
||||
name: options.name,
|
||||
title: options.title
|
||||
});
|
||||
await this._startCollectingStacks(traceName);
|
||||
}
|
||||
async startChunk(options = {}) {
|
||||
const {
|
||||
traceName
|
||||
} = await this._channel.tracingStartChunk(options);
|
||||
await this._startCollectingStacks(traceName);
|
||||
}
|
||||
async group(name, options = {}) {
|
||||
await this._wrapApiCall(async () => {
|
||||
await this._channel.tracingGroup({
|
||||
name,
|
||||
location: options.location
|
||||
});
|
||||
}, false);
|
||||
}
|
||||
async groupEnd() {
|
||||
await this._wrapApiCall(async () => {
|
||||
await this._channel.tracingGroupEnd();
|
||||
}, false);
|
||||
}
|
||||
async _startCollectingStacks(traceName) {
|
||||
var _this$_connection$loc;
|
||||
if (!this._isTracing) {
|
||||
this._isTracing = true;
|
||||
this._connection.setIsTracing(true);
|
||||
}
|
||||
const result = await ((_this$_connection$loc = this._connection.localUtils()) === null || _this$_connection$loc === void 0 ? void 0 : _this$_connection$loc.tracingStarted({
|
||||
tracesDir: this._tracesDir,
|
||||
traceName
|
||||
}));
|
||||
this._stacksId = result === null || result === void 0 ? void 0 : result.stacksId;
|
||||
}
|
||||
async stopChunk(options = {}) {
|
||||
await this._doStopChunk(options.path);
|
||||
}
|
||||
async stop(options = {}) {
|
||||
await this._doStopChunk(options.path);
|
||||
await this._channel.tracingStop();
|
||||
}
|
||||
async _doStopChunk(filePath) {
|
||||
this._resetStackCounter();
|
||||
if (!filePath) {
|
||||
// Not interested in artifacts.
|
||||
await this._channel.tracingStopChunk({
|
||||
mode: 'discard'
|
||||
});
|
||||
if (this._stacksId) await this._connection.localUtils().traceDiscarded({
|
||||
stacksId: this._stacksId
|
||||
});
|
||||
return;
|
||||
}
|
||||
const localUtils = this._connection.localUtils();
|
||||
if (!localUtils) throw new Error('Cannot save trace in thin clients');
|
||||
const isLocal = !this._connection.isRemote();
|
||||
if (isLocal) {
|
||||
const result = await this._channel.tracingStopChunk({
|
||||
mode: 'entries'
|
||||
});
|
||||
await localUtils.zip({
|
||||
zipFile: filePath,
|
||||
entries: result.entries,
|
||||
mode: 'write',
|
||||
stacksId: this._stacksId,
|
||||
includeSources: this._includeSources
|
||||
});
|
||||
return;
|
||||
}
|
||||
const result = await this._channel.tracingStopChunk({
|
||||
mode: 'archive'
|
||||
});
|
||||
|
||||
// The artifact may be missing if the browser closed while stopping tracing.
|
||||
if (!result.artifact) {
|
||||
if (this._stacksId) await localUtils.traceDiscarded({
|
||||
stacksId: this._stacksId
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Save trace to the final local file.
|
||||
const artifact = _artifact.Artifact.from(result.artifact);
|
||||
await artifact.saveAs(filePath);
|
||||
await artifact.delete();
|
||||
await localUtils.zip({
|
||||
zipFile: filePath,
|
||||
entries: [],
|
||||
mode: 'append',
|
||||
stacksId: this._stacksId,
|
||||
includeSources: this._includeSources
|
||||
});
|
||||
}
|
||||
_resetStackCounter() {
|
||||
if (this._isTracing) {
|
||||
this._isTracing = false;
|
||||
this._connection.setIsTracing(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.Tracing = Tracing;
|
||||
24
node_modules/playwright-core/lib/client/types.js
generated
vendored
Normal file
24
node_modules/playwright-core/lib/client/types.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.kLifecycleEvents = void 0;
|
||||
/**
|
||||
* Copyright 2018 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const kLifecycleEvents = exports.kLifecycleEvents = new Set(['load', 'domcontentloaded', 'networkidle', 'commit']);
|
||||
51
node_modules/playwright-core/lib/client/video.js
generated
vendored
Normal file
51
node_modules/playwright-core/lib/client/video.js
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Video = void 0;
|
||||
var _manualPromise = require("../utils/isomorphic/manualPromise");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Video {
|
||||
constructor(page, connection) {
|
||||
this._artifact = null;
|
||||
this._artifactReadyPromise = new _manualPromise.ManualPromise();
|
||||
this._isRemote = false;
|
||||
this._isRemote = connection.isRemote();
|
||||
this._artifact = page._closedOrCrashedScope.safeRace(this._artifactReadyPromise);
|
||||
}
|
||||
_artifactReady(artifact) {
|
||||
this._artifactReadyPromise.resolve(artifact);
|
||||
}
|
||||
async path() {
|
||||
if (this._isRemote) throw new Error(`Path is not available when connecting remotely. Use saveAs() to save a local copy.`);
|
||||
const artifact = await this._artifact;
|
||||
if (!artifact) throw new Error('Page did not produce any video frames');
|
||||
return artifact._initializer.absolutePath;
|
||||
}
|
||||
async saveAs(path) {
|
||||
const artifact = await this._artifact;
|
||||
if (!artifact) throw new Error('Page did not produce any video frames');
|
||||
return await artifact.saveAs(path);
|
||||
}
|
||||
async delete() {
|
||||
const artifact = await this._artifact;
|
||||
if (artifact) await artifact.delete();
|
||||
}
|
||||
}
|
||||
exports.Video = Video;
|
||||
161
node_modules/playwright-core/lib/client/waiter.js
generated
vendored
Normal file
161
node_modules/playwright-core/lib/client/waiter.js
generated
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Waiter = void 0;
|
||||
var _errors = require("./errors");
|
||||
var _stackTrace = require("../utils/isomorphic/stackTrace");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Waiter {
|
||||
constructor(channelOwner, event) {
|
||||
this._dispose = void 0;
|
||||
this._failures = [];
|
||||
this._immediateError = void 0;
|
||||
this._logs = [];
|
||||
this._channelOwner = void 0;
|
||||
this._waitId = void 0;
|
||||
this._error = void 0;
|
||||
this._savedZone = void 0;
|
||||
this._waitId = channelOwner._platform.createGuid();
|
||||
this._channelOwner = channelOwner;
|
||||
this._savedZone = channelOwner._platform.zones.current().pop();
|
||||
this._channelOwner._channel.waitForEventInfo({
|
||||
info: {
|
||||
waitId: this._waitId,
|
||||
phase: 'before',
|
||||
event
|
||||
}
|
||||
}).catch(() => {});
|
||||
this._dispose = [() => this._channelOwner._wrapApiCall(async () => {
|
||||
await this._channelOwner._channel.waitForEventInfo({
|
||||
info: {
|
||||
waitId: this._waitId,
|
||||
phase: 'after',
|
||||
error: this._error
|
||||
}
|
||||
});
|
||||
}, true).catch(() => {})];
|
||||
}
|
||||
static createForEvent(channelOwner, event) {
|
||||
return new Waiter(channelOwner, event);
|
||||
}
|
||||
async waitForEvent(emitter, event, predicate) {
|
||||
const {
|
||||
promise,
|
||||
dispose
|
||||
} = waitForEvent(emitter, event, this._savedZone, predicate);
|
||||
return await this.waitForPromise(promise, dispose);
|
||||
}
|
||||
rejectOnEvent(emitter, event, error, predicate) {
|
||||
const {
|
||||
promise,
|
||||
dispose
|
||||
} = waitForEvent(emitter, event, this._savedZone, predicate);
|
||||
this._rejectOn(promise.then(() => {
|
||||
throw typeof error === 'function' ? error() : error;
|
||||
}), dispose);
|
||||
}
|
||||
rejectOnTimeout(timeout, message) {
|
||||
if (!timeout) return;
|
||||
const {
|
||||
promise,
|
||||
dispose
|
||||
} = waitForTimeout(timeout);
|
||||
this._rejectOn(promise.then(() => {
|
||||
throw new _errors.TimeoutError(message);
|
||||
}), dispose);
|
||||
}
|
||||
rejectImmediately(error) {
|
||||
this._immediateError = error;
|
||||
}
|
||||
dispose() {
|
||||
for (const dispose of this._dispose) dispose();
|
||||
}
|
||||
async waitForPromise(promise, dispose) {
|
||||
try {
|
||||
if (this._immediateError) throw this._immediateError;
|
||||
const result = await Promise.race([promise, ...this._failures]);
|
||||
if (dispose) dispose();
|
||||
return result;
|
||||
} catch (e) {
|
||||
if (dispose) dispose();
|
||||
this._error = e.message;
|
||||
this.dispose();
|
||||
(0, _stackTrace.rewriteErrorMessage)(e, e.message + formatLogRecording(this._logs));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
log(s) {
|
||||
this._logs.push(s);
|
||||
this._channelOwner._wrapApiCall(async () => {
|
||||
await this._channelOwner._channel.waitForEventInfo({
|
||||
info: {
|
||||
waitId: this._waitId,
|
||||
phase: 'log',
|
||||
message: s
|
||||
}
|
||||
});
|
||||
}, true).catch(() => {});
|
||||
}
|
||||
_rejectOn(promise, dispose) {
|
||||
this._failures.push(promise);
|
||||
if (dispose) this._dispose.push(dispose);
|
||||
}
|
||||
}
|
||||
exports.Waiter = Waiter;
|
||||
function waitForEvent(emitter, event, savedZone, predicate) {
|
||||
let listener;
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
listener = async eventArg => {
|
||||
await savedZone.run(async () => {
|
||||
try {
|
||||
if (predicate && !(await predicate(eventArg))) return;
|
||||
emitter.removeListener(event, listener);
|
||||
resolve(eventArg);
|
||||
} catch (e) {
|
||||
emitter.removeListener(event, listener);
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
emitter.addListener(event, listener);
|
||||
});
|
||||
const dispose = () => emitter.removeListener(event, listener);
|
||||
return {
|
||||
promise,
|
||||
dispose
|
||||
};
|
||||
}
|
||||
function waitForTimeout(timeout) {
|
||||
let timeoutId;
|
||||
const promise = new Promise(resolve => timeoutId = setTimeout(resolve, timeout));
|
||||
const dispose = () => clearTimeout(timeoutId);
|
||||
return {
|
||||
promise,
|
||||
dispose
|
||||
};
|
||||
}
|
||||
function formatLogRecording(log) {
|
||||
if (!log.length) return '';
|
||||
const header = ` logs `;
|
||||
const headerLength = 60;
|
||||
const leftLength = (headerLength - header.length) / 2;
|
||||
const rightLength = headerLength - header.length - leftLength;
|
||||
return `\n${'='.repeat(leftLength)}${header}${'='.repeat(rightLength)}\n${log.join('\n')}\n${'='.repeat(headerLength)}`;
|
||||
}
|
||||
37
node_modules/playwright-core/lib/client/webError.js
generated
vendored
Normal file
37
node_modules/playwright-core/lib/client/webError.js
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.WebError = void 0;
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class WebError {
|
||||
constructor(page, error) {
|
||||
this._page = void 0;
|
||||
this._error = void 0;
|
||||
this._page = page;
|
||||
this._error = error;
|
||||
}
|
||||
page() {
|
||||
return this._page;
|
||||
}
|
||||
error() {
|
||||
return this._error;
|
||||
}
|
||||
}
|
||||
exports.WebError = WebError;
|
||||
106
node_modules/playwright-core/lib/client/webSocket.js
generated
vendored
Normal file
106
node_modules/playwright-core/lib/client/webSocket.js
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.connectOverWebSocket = connectOverWebSocket;
|
||||
var _connection = require("./connection");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
async function connectOverWebSocket(parentConnection, params) {
|
||||
const localUtils = parentConnection.localUtils();
|
||||
const transport = localUtils ? new JsonPipeTransport(localUtils) : new WebSocketTransport();
|
||||
const connectHeaders = await transport.connect(params);
|
||||
const connection = new _connection.Connection(parentConnection._platform, localUtils, parentConnection._instrumentation, connectHeaders);
|
||||
connection.markAsRemote();
|
||||
connection.on('close', () => transport.close());
|
||||
let closeError;
|
||||
const onTransportClosed = reason => {
|
||||
connection.close(reason || closeError);
|
||||
};
|
||||
transport.onClose(reason => onTransportClosed(reason));
|
||||
connection.onmessage = message => transport.send(message).catch(() => onTransportClosed());
|
||||
transport.onMessage(message => {
|
||||
try {
|
||||
connection.dispatch(message);
|
||||
} catch (e) {
|
||||
closeError = String(e);
|
||||
transport.close().catch(() => {});
|
||||
}
|
||||
});
|
||||
return connection;
|
||||
}
|
||||
class JsonPipeTransport {
|
||||
constructor(owner) {
|
||||
this._pipe = void 0;
|
||||
this._owner = void 0;
|
||||
this._owner = owner;
|
||||
}
|
||||
async connect(params) {
|
||||
const {
|
||||
pipe,
|
||||
headers: connectHeaders
|
||||
} = await this._owner._wrapApiCall(async () => {
|
||||
return await this._owner._channel.connect(params);
|
||||
}, /* isInternal */true);
|
||||
this._pipe = pipe;
|
||||
return connectHeaders;
|
||||
}
|
||||
async send(message) {
|
||||
await this._owner._wrapApiCall(async () => {
|
||||
await this._pipe.send({
|
||||
message
|
||||
});
|
||||
}, /* isInternal */true);
|
||||
}
|
||||
onMessage(callback) {
|
||||
this._pipe.on('message', ({
|
||||
message
|
||||
}) => callback(message));
|
||||
}
|
||||
onClose(callback) {
|
||||
this._pipe.on('closed', ({
|
||||
reason
|
||||
}) => callback(reason));
|
||||
}
|
||||
async close() {
|
||||
await this._owner._wrapApiCall(async () => {
|
||||
await this._pipe.close().catch(() => {});
|
||||
}, /* isInternal */true);
|
||||
}
|
||||
}
|
||||
class WebSocketTransport {
|
||||
constructor() {
|
||||
this._ws = void 0;
|
||||
}
|
||||
async connect(params) {
|
||||
this._ws = new window.WebSocket(params.wsEndpoint);
|
||||
return [];
|
||||
}
|
||||
async send(message) {
|
||||
this._ws.send(JSON.stringify(message));
|
||||
}
|
||||
onMessage(callback) {
|
||||
this._ws.addEventListener('message', event => callback(JSON.parse(event.data)));
|
||||
}
|
||||
onClose(callback) {
|
||||
this._ws.addEventListener('close', () => callback());
|
||||
}
|
||||
async close() {
|
||||
this._ws.close();
|
||||
}
|
||||
}
|
||||
71
node_modules/playwright-core/lib/client/worker.js
generated
vendored
Normal file
71
node_modules/playwright-core/lib/client/worker.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Worker = void 0;
|
||||
var _channelOwner = require("./channelOwner");
|
||||
var _errors = require("./errors");
|
||||
var _events = require("./events");
|
||||
var _jsHandle = require("./jsHandle");
|
||||
var _manualPromise = require("../utils/isomorphic/manualPromise");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Worker extends _channelOwner.ChannelOwner {
|
||||
static from(worker) {
|
||||
return worker._object;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
this._page = void 0;
|
||||
// Set for web workers.
|
||||
this._context = void 0;
|
||||
// Set for service workers.
|
||||
this._closedScope = new _manualPromise.LongStandingScope();
|
||||
this._channel.on('close', () => {
|
||||
if (this._page) this._page._workers.delete(this);
|
||||
if (this._context) this._context._serviceWorkers.delete(this);
|
||||
this.emit(_events.Events.Worker.Close, this);
|
||||
});
|
||||
this.once(_events.Events.Worker.Close, () => {
|
||||
var _this$_page;
|
||||
return this._closedScope.close(((_this$_page = this._page) === null || _this$_page === void 0 ? void 0 : _this$_page._closeErrorWithReason()) || new _errors.TargetClosedError());
|
||||
});
|
||||
}
|
||||
url() {
|
||||
return this._initializer.url;
|
||||
}
|
||||
async evaluate(pageFunction, arg) {
|
||||
(0, _jsHandle.assertMaxArguments)(arguments.length, 2);
|
||||
const result = await this._channel.evaluateExpression({
|
||||
expression: String(pageFunction),
|
||||
isFunction: typeof pageFunction === 'function',
|
||||
arg: (0, _jsHandle.serializeArgument)(arg)
|
||||
});
|
||||
return (0, _jsHandle.parseResult)(result.value);
|
||||
}
|
||||
async evaluateHandle(pageFunction, arg) {
|
||||
(0, _jsHandle.assertMaxArguments)(arguments.length, 2);
|
||||
const result = await this._channel.evaluateExpressionHandle({
|
||||
expression: String(pageFunction),
|
||||
isFunction: typeof pageFunction === 'function',
|
||||
arg: (0, _jsHandle.serializeArgument)(arg)
|
||||
});
|
||||
return _jsHandle.JSHandle.from(result.handle);
|
||||
}
|
||||
}
|
||||
exports.Worker = Worker;
|
||||
35
node_modules/playwright-core/lib/client/writableStream.js
generated
vendored
Normal file
35
node_modules/playwright-core/lib/client/writableStream.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.WritableStream = void 0;
|
||||
var _channelOwner = require("./channelOwner");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class WritableStream extends _channelOwner.ChannelOwner {
|
||||
static from(Stream) {
|
||||
return Stream._object;
|
||||
}
|
||||
constructor(parent, type, guid, initializer) {
|
||||
super(parent, type, guid, initializer);
|
||||
}
|
||||
stream() {
|
||||
return this._platform.streamWritable(this._channel);
|
||||
}
|
||||
}
|
||||
exports.WritableStream = WritableStream;
|
||||
7
node_modules/playwright-core/lib/generated/clockSource.js
generated
vendored
Normal file
7
node_modules/playwright-core/lib/generated/clockSource.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
7
node_modules/playwright-core/lib/generated/consoleApiSource.js
generated
vendored
Normal file
7
node_modules/playwright-core/lib/generated/consoleApiSource.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
7
node_modules/playwright-core/lib/generated/injectedScriptSource.js
generated
vendored
Normal file
7
node_modules/playwright-core/lib/generated/injectedScriptSource.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
7
node_modules/playwright-core/lib/generated/pollingRecorderSource.js
generated
vendored
Normal file
7
node_modules/playwright-core/lib/generated/pollingRecorderSource.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
7
node_modules/playwright-core/lib/generated/utilityScriptSource.js
generated
vendored
Normal file
7
node_modules/playwright-core/lib/generated/utilityScriptSource.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
7
node_modules/playwright-core/lib/generated/webSocketMockSource.js
generated
vendored
Normal file
7
node_modules/playwright-core/lib/generated/webSocketMockSource.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
59
node_modules/playwright-core/lib/inProcessFactory.js
generated
vendored
Normal file
59
node_modules/playwright-core/lib/inProcessFactory.js
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.createInProcessPlaywright = createInProcessPlaywright;
|
||||
var _androidServerImpl = require("./androidServerImpl");
|
||||
var _browserServerImpl = require("./browserServerImpl");
|
||||
var _server = require("./server");
|
||||
var _nodePlatform = require("./server/utils/nodePlatform");
|
||||
var _connection = require("./client/connection");
|
||||
var _selectors = require("./client/selectors");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
function createInProcessPlaywright() {
|
||||
const playwright = (0, _server.createPlaywright)({
|
||||
sdkLanguage: process.env.PW_LANG_NAME || 'javascript'
|
||||
});
|
||||
(0, _selectors.setPlatformForSelectors)(_nodePlatform.nodePlatform);
|
||||
const clientConnection = new _connection.Connection(_nodePlatform.nodePlatform);
|
||||
clientConnection.useRawBuffers();
|
||||
const dispatcherConnection = new _server.DispatcherConnection(true /* local */);
|
||||
|
||||
// Dispatch synchronously at first.
|
||||
dispatcherConnection.onmessage = message => clientConnection.dispatch(message);
|
||||
clientConnection.onmessage = message => dispatcherConnection.dispatch(message);
|
||||
const rootScope = new _server.RootDispatcher(dispatcherConnection);
|
||||
|
||||
// Initialize Playwright channel.
|
||||
new _server.PlaywrightDispatcher(rootScope, playwright);
|
||||
const playwrightAPI = clientConnection.getObjectWithKnownName('Playwright');
|
||||
playwrightAPI.chromium._serverLauncher = new _browserServerImpl.BrowserServerLauncherImpl('chromium');
|
||||
playwrightAPI.firefox._serverLauncher = new _browserServerImpl.BrowserServerLauncherImpl('firefox');
|
||||
playwrightAPI.webkit._serverLauncher = new _browserServerImpl.BrowserServerLauncherImpl('webkit');
|
||||
playwrightAPI._android._serverLauncher = new _androidServerImpl.AndroidServerLauncherImpl();
|
||||
playwrightAPI._bidiChromium._serverLauncher = new _browserServerImpl.BrowserServerLauncherImpl('bidiChromium');
|
||||
playwrightAPI._bidiFirefox._serverLauncher = new _browserServerImpl.BrowserServerLauncherImpl('bidiFirefox');
|
||||
|
||||
// Switch to async dispatch after we got Playwright object.
|
||||
dispatcherConnection.onmessage = message => setImmediate(() => clientConnection.dispatch(message));
|
||||
clientConnection.onmessage = message => setImmediate(() => dispatcherConnection.dispatch(message));
|
||||
clientConnection.toImpl = x => x ? dispatcherConnection._dispatchers.get(x._guid)._object : dispatcherConnection._dispatchers.get('');
|
||||
playwrightAPI._toImpl = clientConnection.toImpl;
|
||||
return playwrightAPI;
|
||||
}
|
||||
20
node_modules/playwright-core/lib/inprocess.js
generated
vendored
Normal file
20
node_modules/playwright-core/lib/inprocess.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
"use strict";
|
||||
|
||||
var _inProcessFactory = require("./inProcessFactory");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
module.exports = (0, _inProcessFactory.createInProcessPlaywright)();
|
||||
71
node_modules/playwright-core/lib/outofprocess.js
generated
vendored
Normal file
71
node_modules/playwright-core/lib/outofprocess.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.start = start;
|
||||
var childProcess = _interopRequireWildcard(require("child_process"));
|
||||
var _path = _interopRequireDefault(require("path"));
|
||||
var _connection = require("./client/connection");
|
||||
var _pipeTransport = require("./server/utils/pipeTransport");
|
||||
var _manualPromise = require("./utils/isomorphic/manualPromise");
|
||||
var _nodePlatform = require("./server/utils/nodePlatform");
|
||||
var _selectors = require("./client/selectors");
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
async function start(env = {}) {
|
||||
(0, _selectors.setPlatformForSelectors)(_nodePlatform.nodePlatform);
|
||||
const client = new PlaywrightClient(env);
|
||||
const playwright = await client._playwright;
|
||||
playwright.driverProcess = client._driverProcess;
|
||||
return {
|
||||
playwright,
|
||||
stop: () => client.stop()
|
||||
};
|
||||
}
|
||||
class PlaywrightClient {
|
||||
constructor(env) {
|
||||
this._playwright = void 0;
|
||||
this._driverProcess = void 0;
|
||||
this._closePromise = new _manualPromise.ManualPromise();
|
||||
this._driverProcess = childProcess.fork(_path.default.join(__dirname, '..', 'cli.js'), ['run-driver'], {
|
||||
stdio: 'pipe',
|
||||
detached: true,
|
||||
env: {
|
||||
...process.env,
|
||||
...env
|
||||
}
|
||||
});
|
||||
this._driverProcess.unref();
|
||||
this._driverProcess.stderr.on('data', data => process.stderr.write(data));
|
||||
const connection = new _connection.Connection(_nodePlatform.nodePlatform);
|
||||
const transport = new _pipeTransport.PipeTransport(this._driverProcess.stdin, this._driverProcess.stdout);
|
||||
connection.onmessage = message => transport.send(JSON.stringify(message));
|
||||
transport.onmessage = message => connection.dispatch(JSON.parse(message));
|
||||
transport.onclose = () => this._closePromise.resolve();
|
||||
this._playwright = connection.initializePlaywright();
|
||||
}
|
||||
async stop() {
|
||||
this._driverProcess.stdin.destroy();
|
||||
this._driverProcess.stdout.destroy();
|
||||
this._driverProcess.stderr.destroy();
|
||||
await this._closePromise;
|
||||
}
|
||||
}
|
||||
27
node_modules/playwright-core/lib/protocol/debug.js
generated
vendored
Normal file
27
node_modules/playwright-core/lib/protocol/debug.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.slowMoActions = exports.pausesBeforeInputActions = exports.commandsWithTracingSnapshots = void 0;
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// This file is generated by generate_channels.js, do not edit manually.
|
||||
|
||||
const slowMoActions = exports.slowMoActions = new Set(['Page.goBack', 'Page.goForward', 'Page.reload', 'Page.keyboardDown', 'Page.keyboardUp', 'Page.keyboardInsertText', 'Page.keyboardType', 'Page.keyboardPress', 'Page.mouseMove', 'Page.mouseDown', 'Page.mouseUp', 'Page.mouseClick', 'Page.mouseWheel', 'Page.touchscreenTap', 'Frame.blur', 'Frame.check', 'Frame.click', 'Frame.dragAndDrop', 'Frame.dblclick', 'Frame.dispatchEvent', 'Frame.fill', 'Frame.focus', 'Frame.goto', 'Frame.hover', 'Frame.press', 'Frame.selectOption', 'Frame.setInputFiles', 'Frame.tap', 'Frame.type', 'Frame.uncheck', 'ElementHandle.check', 'ElementHandle.click', 'ElementHandle.dblclick', 'ElementHandle.dispatchEvent', 'ElementHandle.fill', 'ElementHandle.focus', 'ElementHandle.hover', 'ElementHandle.press', 'ElementHandle.scrollIntoViewIfNeeded', 'ElementHandle.selectOption', 'ElementHandle.selectText', 'ElementHandle.setInputFiles', 'ElementHandle.tap', 'ElementHandle.type', 'ElementHandle.uncheck']);
|
||||
const commandsWithTracingSnapshots = exports.commandsWithTracingSnapshots = new Set(['EventTarget.waitForEventInfo', 'BrowserContext.waitForEventInfo', 'Page.waitForEventInfo', 'WebSocket.waitForEventInfo', 'ElectronApplication.waitForEventInfo', 'AndroidDevice.waitForEventInfo', 'Page.emulateMedia', 'Page.goBack', 'Page.goForward', 'Page.reload', 'Page.expectScreenshot', 'Page.screenshot', 'Page.setViewportSize', 'Page.keyboardDown', 'Page.keyboardUp', 'Page.keyboardInsertText', 'Page.keyboardType', 'Page.keyboardPress', 'Page.mouseMove', 'Page.mouseDown', 'Page.mouseUp', 'Page.mouseClick', 'Page.mouseWheel', 'Page.touchscreenTap', 'Page.accessibilitySnapshot', 'Frame.evalOnSelector', 'Frame.evalOnSelectorAll', 'Frame.addScriptTag', 'Frame.addStyleTag', 'Frame.ariaSnapshot', 'Frame.blur', 'Frame.check', 'Frame.click', 'Frame.content', 'Frame.dragAndDrop', 'Frame.dblclick', 'Frame.dispatchEvent', 'Frame.evaluateExpression', 'Frame.evaluateExpressionHandle', 'Frame.fill', 'Frame.focus', 'Frame.getAttribute', 'Frame.goto', 'Frame.hover', 'Frame.innerHTML', 'Frame.innerText', 'Frame.inputValue', 'Frame.isChecked', 'Frame.isDisabled', 'Frame.isEnabled', 'Frame.isHidden', 'Frame.isVisible', 'Frame.isEditable', 'Frame.press', 'Frame.querySelector', 'Frame.querySelectorAll', 'Frame.queryCount', 'Frame.selectOption', 'Frame.setContent', 'Frame.setInputFiles', 'Frame.tap', 'Frame.textContent', 'Frame.type', 'Frame.uncheck', 'Frame.waitForTimeout', 'Frame.waitForFunction', 'Frame.waitForSelector', 'Frame.expect', 'JSHandle.evaluateExpression', 'ElementHandle.evaluateExpression', 'JSHandle.evaluateExpressionHandle', 'ElementHandle.evaluateExpressionHandle', 'ElementHandle.evalOnSelector', 'ElementHandle.evalOnSelectorAll', 'ElementHandle.boundingBox', 'ElementHandle.check', 'ElementHandle.click', 'ElementHandle.contentFrame', 'ElementHandle.dblclick', 'ElementHandle.dispatchEvent', 'ElementHandle.fill', 'ElementHandle.focus', 'ElementHandle.hover', 'ElementHandle.innerHTML', 'ElementHandle.innerText', 'ElementHandle.inputValue', 'ElementHandle.isChecked', 'ElementHandle.isDisabled', 'ElementHandle.isEditable', 'ElementHandle.isEnabled', 'ElementHandle.isHidden', 'ElementHandle.isVisible', 'ElementHandle.press', 'ElementHandle.querySelector', 'ElementHandle.querySelectorAll', 'ElementHandle.screenshot', 'ElementHandle.scrollIntoViewIfNeeded', 'ElementHandle.selectOption', 'ElementHandle.selectText', 'ElementHandle.setInputFiles', 'ElementHandle.tap', 'ElementHandle.textContent', 'ElementHandle.type', 'ElementHandle.uncheck', 'ElementHandle.waitForElementState', 'ElementHandle.waitForSelector']);
|
||||
const pausesBeforeInputActions = exports.pausesBeforeInputActions = new Set(['Frame.check', 'Frame.click', 'Frame.dragAndDrop', 'Frame.dblclick', 'Frame.fill', 'Frame.hover', 'Frame.press', 'Frame.selectOption', 'Frame.setInputFiles', 'Frame.tap', 'Frame.type', 'Frame.uncheck', 'ElementHandle.check', 'ElementHandle.click', 'ElementHandle.dblclick', 'ElementHandle.fill', 'ElementHandle.hover', 'ElementHandle.press', 'ElementHandle.selectOption', 'ElementHandle.setInputFiles', 'ElementHandle.tap', 'ElementHandle.type', 'ElementHandle.uncheck']);
|
||||
173
node_modules/playwright-core/lib/protocol/serializers.js
generated
vendored
Normal file
173
node_modules/playwright-core/lib/protocol/serializers.js
generated
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.parseSerializedValue = parseSerializedValue;
|
||||
exports.serializeValue = serializeValue;
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
function parseSerializedValue(value, handles) {
|
||||
return innerParseSerializedValue(value, handles, new Map());
|
||||
}
|
||||
function innerParseSerializedValue(value, handles, refs) {
|
||||
if (value.ref !== undefined) return refs.get(value.ref);
|
||||
if (value.n !== undefined) return value.n;
|
||||
if (value.s !== undefined) return value.s;
|
||||
if (value.b !== undefined) return value.b;
|
||||
if (value.v !== undefined) {
|
||||
if (value.v === 'undefined') return undefined;
|
||||
if (value.v === 'null') return null;
|
||||
if (value.v === 'NaN') return NaN;
|
||||
if (value.v === 'Infinity') return Infinity;
|
||||
if (value.v === '-Infinity') return -Infinity;
|
||||
if (value.v === '-0') return -0;
|
||||
}
|
||||
if (value.d !== undefined) return new Date(value.d);
|
||||
if (value.u !== undefined) return new URL(value.u);
|
||||
if (value.bi !== undefined) return BigInt(value.bi);
|
||||
if (value.e !== undefined) {
|
||||
const error = new Error(value.e.m);
|
||||
error.name = value.e.n;
|
||||
error.stack = value.e.s;
|
||||
return error;
|
||||
}
|
||||
if (value.r !== undefined) return new RegExp(value.r.p, value.r.f);
|
||||
if (value.a !== undefined) {
|
||||
const result = [];
|
||||
refs.set(value.id, result);
|
||||
for (const v of value.a) result.push(innerParseSerializedValue(v, handles, refs));
|
||||
return result;
|
||||
}
|
||||
if (value.o !== undefined) {
|
||||
const result = {};
|
||||
refs.set(value.id, result);
|
||||
for (const {
|
||||
k,
|
||||
v
|
||||
} of value.o) result[k] = innerParseSerializedValue(v, handles, refs);
|
||||
return result;
|
||||
}
|
||||
if (value.h !== undefined) {
|
||||
if (handles === undefined) throw new Error('Unexpected handle');
|
||||
return handles[value.h];
|
||||
}
|
||||
throw new Error('Unexpected value');
|
||||
}
|
||||
function serializeValue(value, handleSerializer) {
|
||||
return innerSerializeValue(value, handleSerializer, {
|
||||
lastId: 0,
|
||||
visited: new Map()
|
||||
});
|
||||
}
|
||||
function innerSerializeValue(value, handleSerializer, visitorInfo) {
|
||||
const handle = handleSerializer(value);
|
||||
if ('fallThrough' in handle) value = handle.fallThrough;else return handle;
|
||||
if (typeof value === 'symbol') return {
|
||||
v: 'undefined'
|
||||
};
|
||||
if (Object.is(value, undefined)) return {
|
||||
v: 'undefined'
|
||||
};
|
||||
if (Object.is(value, null)) return {
|
||||
v: 'null'
|
||||
};
|
||||
if (Object.is(value, NaN)) return {
|
||||
v: 'NaN'
|
||||
};
|
||||
if (Object.is(value, Infinity)) return {
|
||||
v: 'Infinity'
|
||||
};
|
||||
if (Object.is(value, -Infinity)) return {
|
||||
v: '-Infinity'
|
||||
};
|
||||
if (Object.is(value, -0)) return {
|
||||
v: '-0'
|
||||
};
|
||||
if (typeof value === 'boolean') return {
|
||||
b: value
|
||||
};
|
||||
if (typeof value === 'number') return {
|
||||
n: value
|
||||
};
|
||||
if (typeof value === 'string') return {
|
||||
s: value
|
||||
};
|
||||
if (typeof value === 'bigint') return {
|
||||
bi: value.toString()
|
||||
};
|
||||
if (isError(value)) return {
|
||||
e: {
|
||||
n: value.name,
|
||||
m: value.message,
|
||||
s: value.stack || ''
|
||||
}
|
||||
};
|
||||
if (isDate(value)) return {
|
||||
d: value.toJSON()
|
||||
};
|
||||
if (isURL(value)) return {
|
||||
u: value.toJSON()
|
||||
};
|
||||
if (isRegExp(value)) return {
|
||||
r: {
|
||||
p: value.source,
|
||||
f: value.flags
|
||||
}
|
||||
};
|
||||
const id = visitorInfo.visited.get(value);
|
||||
if (id) return {
|
||||
ref: id
|
||||
};
|
||||
if (Array.isArray(value)) {
|
||||
const a = [];
|
||||
const id = ++visitorInfo.lastId;
|
||||
visitorInfo.visited.set(value, id);
|
||||
for (let i = 0; i < value.length; ++i) a.push(innerSerializeValue(value[i], handleSerializer, visitorInfo));
|
||||
return {
|
||||
a,
|
||||
id
|
||||
};
|
||||
}
|
||||
if (typeof value === 'object') {
|
||||
const o = [];
|
||||
const id = ++visitorInfo.lastId;
|
||||
visitorInfo.visited.set(value, id);
|
||||
for (const name of Object.keys(value)) o.push({
|
||||
k: name,
|
||||
v: innerSerializeValue(value[name], handleSerializer, visitorInfo)
|
||||
});
|
||||
return {
|
||||
o,
|
||||
id
|
||||
};
|
||||
}
|
||||
throw new Error('Unexpected value');
|
||||
}
|
||||
function isRegExp(obj) {
|
||||
return obj instanceof RegExp || Object.prototype.toString.call(obj) === '[object RegExp]';
|
||||
}
|
||||
function isDate(obj) {
|
||||
return obj instanceof Date || Object.prototype.toString.call(obj) === '[object Date]';
|
||||
}
|
||||
function isURL(obj) {
|
||||
return obj instanceof URL || Object.prototype.toString.call(obj) === '[object URL]';
|
||||
}
|
||||
function isError(obj) {
|
||||
const proto = obj ? Object.getPrototypeOf(obj) : null;
|
||||
return obj instanceof Error || (proto === null || proto === void 0 ? void 0 : proto.name) === 'Error' || proto && isError(proto);
|
||||
}
|
||||
2825
node_modules/playwright-core/lib/protocol/validator.js
generated
vendored
Normal file
2825
node_modules/playwright-core/lib/protocol/validator.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
138
node_modules/playwright-core/lib/protocol/validatorPrimitives.js
generated
vendored
Normal file
138
node_modules/playwright-core/lib/protocol/validatorPrimitives.js
generated
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.ValidationError = void 0;
|
||||
exports.createMetadataValidator = createMetadataValidator;
|
||||
exports.findValidator = findValidator;
|
||||
exports.maybeFindValidator = maybeFindValidator;
|
||||
exports.tUndefined = exports.tType = exports.tString = exports.tOptional = exports.tObject = exports.tNumber = exports.tEnum = exports.tChannel = exports.tBoolean = exports.tBinary = exports.tArray = exports.tAny = exports.scheme = void 0;
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class ValidationError extends Error {}
|
||||
exports.ValidationError = ValidationError;
|
||||
const scheme = exports.scheme = {};
|
||||
function findValidator(type, method, kind) {
|
||||
const validator = maybeFindValidator(type, method, kind);
|
||||
if (!validator) throw new ValidationError(`Unknown scheme for ${kind}: ${type}.${method}`);
|
||||
return validator;
|
||||
}
|
||||
function maybeFindValidator(type, method, kind) {
|
||||
const schemeName = type + (kind === 'Initializer' ? '' : method[0].toUpperCase() + method.substring(1)) + kind;
|
||||
return scheme[schemeName];
|
||||
}
|
||||
function createMetadataValidator() {
|
||||
return tOptional(scheme['Metadata']);
|
||||
}
|
||||
const tNumber = (arg, path, context) => {
|
||||
if (arg instanceof Number) return arg.valueOf();
|
||||
if (typeof arg === 'number') return arg;
|
||||
throw new ValidationError(`${path}: expected number, got ${typeof arg}`);
|
||||
};
|
||||
exports.tNumber = tNumber;
|
||||
const tBoolean = (arg, path, context) => {
|
||||
if (arg instanceof Boolean) return arg.valueOf();
|
||||
if (typeof arg === 'boolean') return arg;
|
||||
throw new ValidationError(`${path}: expected boolean, got ${typeof arg}`);
|
||||
};
|
||||
exports.tBoolean = tBoolean;
|
||||
const tString = (arg, path, context) => {
|
||||
if (arg instanceof String) return arg.valueOf();
|
||||
if (typeof arg === 'string') return arg;
|
||||
throw new ValidationError(`${path}: expected string, got ${typeof arg}`);
|
||||
};
|
||||
exports.tString = tString;
|
||||
const tBinary = (arg, path, context) => {
|
||||
if (context.binary === 'fromBase64') {
|
||||
if (arg instanceof String) return Buffer.from(arg.valueOf(), 'base64');
|
||||
if (typeof arg === 'string') return Buffer.from(arg, 'base64');
|
||||
throw new ValidationError(`${path}: expected base64-encoded buffer, got ${typeof arg}`);
|
||||
}
|
||||
if (context.binary === 'toBase64') {
|
||||
if (!(arg instanceof Buffer)) throw new ValidationError(`${path}: expected Buffer, got ${typeof arg}`);
|
||||
return arg.toString('base64');
|
||||
}
|
||||
if (context.binary === 'buffer') {
|
||||
if (!(arg instanceof Buffer)) throw new ValidationError(`${path}: expected Buffer, got ${typeof arg}`);
|
||||
return arg;
|
||||
}
|
||||
throw new ValidationError(`Unsupported binary behavior "${context.binary}"`);
|
||||
};
|
||||
exports.tBinary = tBinary;
|
||||
const tUndefined = (arg, path, context) => {
|
||||
if (Object.is(arg, undefined)) return arg;
|
||||
throw new ValidationError(`${path}: expected undefined, got ${typeof arg}`);
|
||||
};
|
||||
exports.tUndefined = tUndefined;
|
||||
const tAny = (arg, path, context) => {
|
||||
return arg;
|
||||
};
|
||||
exports.tAny = tAny;
|
||||
const tOptional = v => {
|
||||
return (arg, path, context) => {
|
||||
if (Object.is(arg, undefined)) return arg;
|
||||
return v(arg, path, context);
|
||||
};
|
||||
};
|
||||
exports.tOptional = tOptional;
|
||||
const tArray = v => {
|
||||
return (arg, path, context) => {
|
||||
if (!Array.isArray(arg)) throw new ValidationError(`${path}: expected array, got ${typeof arg}`);
|
||||
return arg.map((x, index) => v(x, path + '[' + index + ']', context));
|
||||
};
|
||||
};
|
||||
exports.tArray = tArray;
|
||||
const tObject = s => {
|
||||
return (arg, path, context) => {
|
||||
if (Object.is(arg, null)) throw new ValidationError(`${path}: expected object, got null`);
|
||||
if (typeof arg !== 'object') throw new ValidationError(`${path}: expected object, got ${typeof arg}`);
|
||||
const result = {};
|
||||
for (const [key, v] of Object.entries(s)) {
|
||||
const value = v(arg[key], path ? path + '.' + key : key, context);
|
||||
if (!Object.is(value, undefined)) result[key] = value;
|
||||
}
|
||||
if (context.isUnderTest()) {
|
||||
for (const [key, value] of Object.entries(arg)) {
|
||||
if (key.startsWith('__testHook')) result[key] = value;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
};
|
||||
exports.tObject = tObject;
|
||||
const tEnum = e => {
|
||||
return (arg, path, context) => {
|
||||
if (!e.includes(arg)) throw new ValidationError(`${path}: expected one of (${e.join('|')})`);
|
||||
return arg;
|
||||
};
|
||||
};
|
||||
exports.tEnum = tEnum;
|
||||
const tChannel = names => {
|
||||
return (arg, path, context) => {
|
||||
return context.tChannelImpl(names, arg, path, context);
|
||||
};
|
||||
};
|
||||
exports.tChannel = tChannel;
|
||||
const tType = name => {
|
||||
return (arg, path, context) => {
|
||||
const v = scheme[name];
|
||||
if (!v) throw new ValidationError(path + ': unknown type "' + name + '"');
|
||||
return v(arg, path, context);
|
||||
};
|
||||
};
|
||||
exports.tType = tType;
|
||||
283
node_modules/playwright-core/lib/remote/playwrightConnection.js
generated
vendored
Normal file
283
node_modules/playwright-core/lib/remote/playwrightConnection.js
generated
vendored
Normal file
@@ -0,0 +1,283 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.PlaywrightConnection = void 0;
|
||||
var _socksProxy = require("../server/utils/socksProxy");
|
||||
var _server = require("../server");
|
||||
var _android = require("../server/android/android");
|
||||
var _browser = require("../server/browser");
|
||||
var _debugControllerDispatcher = require("../server/dispatchers/debugControllerDispatcher");
|
||||
var _instrumentation = require("../server/instrumentation");
|
||||
var _assert = require("../utils/isomorphic/assert");
|
||||
var _debug = require("../server/utils/debug");
|
||||
var _profiler = require("../server/utils/profiler");
|
||||
var _utils = require("../utils");
|
||||
var _debugLogger = require("../server/utils/debugLogger");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class PlaywrightConnection {
|
||||
constructor(lock, clientType, ws, options, preLaunched, id, onClose) {
|
||||
this._ws = void 0;
|
||||
this._onClose = void 0;
|
||||
this._dispatcherConnection = void 0;
|
||||
this._cleanups = [];
|
||||
this._id = void 0;
|
||||
this._disconnected = false;
|
||||
this._preLaunched = void 0;
|
||||
this._options = void 0;
|
||||
this._root = void 0;
|
||||
this._profileName = void 0;
|
||||
this._ws = ws;
|
||||
this._preLaunched = preLaunched;
|
||||
this._options = options;
|
||||
options.launchOptions = filterLaunchOptions(options.launchOptions, options.allowFSPaths);
|
||||
if (clientType === 'reuse-browser' || clientType === 'pre-launched-browser-or-android') (0, _assert.assert)(preLaunched.playwright);
|
||||
if (clientType === 'pre-launched-browser-or-android') (0, _assert.assert)(preLaunched.browser || preLaunched.androidDevice);
|
||||
this._onClose = onClose;
|
||||
this._id = id;
|
||||
this._profileName = `${new Date().toISOString()}-${clientType}`;
|
||||
this._dispatcherConnection = new _server.DispatcherConnection();
|
||||
this._dispatcherConnection.onmessage = async message => {
|
||||
await lock;
|
||||
if (ws.readyState !== ws.CLOSING) {
|
||||
const messageString = JSON.stringify(message);
|
||||
if (_debugLogger.debugLogger.isEnabled('server:channel')) _debugLogger.debugLogger.log('server:channel', `[${this._id}] ${(0, _utils.monotonicTime)() * 1000} SEND ► ${messageString}`);
|
||||
if (_debugLogger.debugLogger.isEnabled('server:metadata')) this.logServerMetadata(message, messageString, 'SEND');
|
||||
ws.send(messageString);
|
||||
}
|
||||
};
|
||||
ws.on('message', async message => {
|
||||
await lock;
|
||||
const messageString = Buffer.from(message).toString();
|
||||
const jsonMessage = JSON.parse(messageString);
|
||||
if (_debugLogger.debugLogger.isEnabled('server:channel')) _debugLogger.debugLogger.log('server:channel', `[${this._id}] ${(0, _utils.monotonicTime)() * 1000} ◀ RECV ${messageString}`);
|
||||
if (_debugLogger.debugLogger.isEnabled('server:metadata')) this.logServerMetadata(jsonMessage, messageString, 'RECV');
|
||||
this._dispatcherConnection.dispatch(jsonMessage);
|
||||
});
|
||||
ws.on('close', () => this._onDisconnect());
|
||||
ws.on('error', error => this._onDisconnect(error));
|
||||
if (clientType === 'controller') {
|
||||
this._root = this._initDebugControllerMode();
|
||||
return;
|
||||
}
|
||||
this._root = new _server.RootDispatcher(this._dispatcherConnection, async (scope, options) => {
|
||||
await (0, _profiler.startProfiling)();
|
||||
if (clientType === 'reuse-browser') return await this._initReuseBrowsersMode(scope);
|
||||
if (clientType === 'pre-launched-browser-or-android') return this._preLaunched.browser ? await this._initPreLaunchedBrowserMode(scope) : await this._initPreLaunchedAndroidMode(scope);
|
||||
if (clientType === 'launch-browser') return await this._initLaunchBrowserMode(scope, options);
|
||||
throw new Error('Unsupported client type: ' + clientType);
|
||||
});
|
||||
}
|
||||
async _initLaunchBrowserMode(scope, options) {
|
||||
_debugLogger.debugLogger.log('server', `[${this._id}] engaged launch mode for "${this._options.browserName}"`);
|
||||
const playwright = (0, _server.createPlaywright)({
|
||||
sdkLanguage: options.sdkLanguage,
|
||||
isServer: true
|
||||
});
|
||||
const ownedSocksProxy = await this._createOwnedSocksProxy(playwright);
|
||||
let browserName = this._options.browserName;
|
||||
if ('bidi' === browserName) {
|
||||
var _this$_options$launch;
|
||||
if ((_this$_options$launch = this._options.launchOptions) !== null && _this$_options$launch !== void 0 && (_this$_options$launch = _this$_options$launch.channel) !== null && _this$_options$launch !== void 0 && _this$_options$launch.toLocaleLowerCase().includes('firefox')) browserName = 'bidiFirefox';else browserName = 'bidiChromium';
|
||||
}
|
||||
const browser = await playwright[browserName].launch((0, _instrumentation.serverSideCallMetadata)(), this._options.launchOptions);
|
||||
this._cleanups.push(async () => {
|
||||
for (const browser of playwright.allBrowsers()) await browser.close({
|
||||
reason: 'Connection terminated'
|
||||
});
|
||||
});
|
||||
browser.on(_browser.Browser.Events.Disconnected, () => {
|
||||
// Underlying browser did close for some reason - force disconnect the client.
|
||||
this.close({
|
||||
code: 1001,
|
||||
reason: 'Browser closed'
|
||||
});
|
||||
});
|
||||
return new _server.PlaywrightDispatcher(scope, playwright, ownedSocksProxy, browser);
|
||||
}
|
||||
async _initPreLaunchedBrowserMode(scope) {
|
||||
var _this$_preLaunched$so;
|
||||
_debugLogger.debugLogger.log('server', `[${this._id}] engaged pre-launched (browser) mode`);
|
||||
const playwright = this._preLaunched.playwright;
|
||||
|
||||
// Note: connected client owns the socks proxy and configures the pattern.
|
||||
(_this$_preLaunched$so = this._preLaunched.socksProxy) === null || _this$_preLaunched$so === void 0 || _this$_preLaunched$so.setPattern(this._options.socksProxyPattern);
|
||||
const browser = this._preLaunched.browser;
|
||||
browser.on(_browser.Browser.Events.Disconnected, () => {
|
||||
// Underlying browser did close for some reason - force disconnect the client.
|
||||
this.close({
|
||||
code: 1001,
|
||||
reason: 'Browser closed'
|
||||
});
|
||||
});
|
||||
const playwrightDispatcher = new _server.PlaywrightDispatcher(scope, playwright, this._preLaunched.socksProxy, browser);
|
||||
// In pre-launched mode, keep only the pre-launched browser.
|
||||
for (const b of playwright.allBrowsers()) {
|
||||
if (b !== browser) await b.close({
|
||||
reason: 'Connection terminated'
|
||||
});
|
||||
}
|
||||
this._cleanups.push(() => playwrightDispatcher.cleanup());
|
||||
return playwrightDispatcher;
|
||||
}
|
||||
async _initPreLaunchedAndroidMode(scope) {
|
||||
_debugLogger.debugLogger.log('server', `[${this._id}] engaged pre-launched (Android) mode`);
|
||||
const playwright = this._preLaunched.playwright;
|
||||
const androidDevice = this._preLaunched.androidDevice;
|
||||
androidDevice.on(_android.AndroidDevice.Events.Close, () => {
|
||||
// Underlying browser did close for some reason - force disconnect the client.
|
||||
this.close({
|
||||
code: 1001,
|
||||
reason: 'Android device disconnected'
|
||||
});
|
||||
});
|
||||
const playwrightDispatcher = new _server.PlaywrightDispatcher(scope, playwright, undefined, undefined, androidDevice);
|
||||
this._cleanups.push(() => playwrightDispatcher.cleanup());
|
||||
return playwrightDispatcher;
|
||||
}
|
||||
_initDebugControllerMode() {
|
||||
_debugLogger.debugLogger.log('server', `[${this._id}] engaged reuse controller mode`);
|
||||
const playwright = this._preLaunched.playwright;
|
||||
// Always create new instance based on the reused Playwright instance.
|
||||
return new _debugControllerDispatcher.DebugControllerDispatcher(this._dispatcherConnection, playwright.debugController);
|
||||
}
|
||||
async _initReuseBrowsersMode(scope) {
|
||||
// Note: reuse browser mode does not support socks proxy, because
|
||||
// clients come and go, while the browser stays the same.
|
||||
|
||||
_debugLogger.debugLogger.log('server', `[${this._id}] engaged reuse browsers mode for ${this._options.browserName}`);
|
||||
const playwright = this._preLaunched.playwright;
|
||||
const requestedOptions = launchOptionsHash(this._options.launchOptions);
|
||||
let browser = playwright.allBrowsers().find(b => {
|
||||
if (b.options.name !== this._options.browserName) return false;
|
||||
const existingOptions = launchOptionsHash(b.options.originalLaunchOptions);
|
||||
return existingOptions === requestedOptions;
|
||||
});
|
||||
|
||||
// Close remaining browsers of this type+channel. Keep different browser types for the speed.
|
||||
for (const b of playwright.allBrowsers()) {
|
||||
if (b === browser) continue;
|
||||
if (b.options.name === this._options.browserName && b.options.channel === this._options.launchOptions.channel) await b.close({
|
||||
reason: 'Connection terminated'
|
||||
});
|
||||
}
|
||||
if (!browser) {
|
||||
browser = await playwright[this._options.browserName || 'chromium'].launch((0, _instrumentation.serverSideCallMetadata)(), {
|
||||
...this._options.launchOptions,
|
||||
headless: !!process.env.PW_DEBUG_CONTROLLER_HEADLESS
|
||||
});
|
||||
browser.on(_browser.Browser.Events.Disconnected, () => {
|
||||
// Underlying browser did close for some reason - force disconnect the client.
|
||||
this.close({
|
||||
code: 1001,
|
||||
reason: 'Browser closed'
|
||||
});
|
||||
});
|
||||
}
|
||||
this._cleanups.push(async () => {
|
||||
// Don't close the pages so that user could debug them,
|
||||
// but close all the empty browsers and contexts to clean up.
|
||||
for (const browser of playwright.allBrowsers()) {
|
||||
for (const context of browser.contexts()) {
|
||||
if (!context.pages().length) await context.close({
|
||||
reason: 'Connection terminated'
|
||||
});else await context.stopPendingOperations('Connection closed');
|
||||
}
|
||||
if (!browser.contexts()) await browser.close({
|
||||
reason: 'Connection terminated'
|
||||
});
|
||||
}
|
||||
});
|
||||
const playwrightDispatcher = new _server.PlaywrightDispatcher(scope, playwright, undefined, browser);
|
||||
return playwrightDispatcher;
|
||||
}
|
||||
async _createOwnedSocksProxy(playwright) {
|
||||
if (!this._options.socksProxyPattern) return;
|
||||
const socksProxy = new _socksProxy.SocksProxy();
|
||||
socksProxy.setPattern(this._options.socksProxyPattern);
|
||||
playwright.options.socksProxyPort = await socksProxy.listen(0);
|
||||
_debugLogger.debugLogger.log('server', `[${this._id}] started socks proxy on port ${playwright.options.socksProxyPort}`);
|
||||
this._cleanups.push(() => socksProxy.close());
|
||||
return socksProxy;
|
||||
}
|
||||
async _onDisconnect(error) {
|
||||
this._disconnected = true;
|
||||
_debugLogger.debugLogger.log('server', `[${this._id}] disconnected. error: ${error}`);
|
||||
this._root._dispose();
|
||||
_debugLogger.debugLogger.log('server', `[${this._id}] starting cleanup`);
|
||||
for (const cleanup of this._cleanups) await cleanup().catch(() => {});
|
||||
await (0, _profiler.stopProfiling)(this._profileName);
|
||||
this._onClose();
|
||||
_debugLogger.debugLogger.log('server', `[${this._id}] finished cleanup`);
|
||||
}
|
||||
logServerMetadata(message, messageString, direction) {
|
||||
const serverLogMetadata = {
|
||||
wallTime: Date.now(),
|
||||
id: message.id,
|
||||
guid: message.guid,
|
||||
method: message.method,
|
||||
payloadSizeInBytes: Buffer.byteLength(messageString, 'utf-8')
|
||||
};
|
||||
_debugLogger.debugLogger.log('server:metadata', (direction === 'SEND' ? 'SEND ► ' : '◀ RECV ') + JSON.stringify(serverLogMetadata));
|
||||
}
|
||||
async close(reason) {
|
||||
if (this._disconnected) return;
|
||||
_debugLogger.debugLogger.log('server', `[${this._id}] force closing connection: ${(reason === null || reason === void 0 ? void 0 : reason.reason) || ''} (${(reason === null || reason === void 0 ? void 0 : reason.code) || 0})`);
|
||||
try {
|
||||
this._ws.close(reason === null || reason === void 0 ? void 0 : reason.code, reason === null || reason === void 0 ? void 0 : reason.reason);
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
exports.PlaywrightConnection = PlaywrightConnection;
|
||||
function launchOptionsHash(options) {
|
||||
const copy = {
|
||||
...options
|
||||
};
|
||||
for (const k of Object.keys(copy)) {
|
||||
const key = k;
|
||||
if (copy[key] === defaultLaunchOptions[key]) delete copy[key];
|
||||
}
|
||||
for (const key of optionsThatAllowBrowserReuse) delete copy[key];
|
||||
return JSON.stringify(copy);
|
||||
}
|
||||
function filterLaunchOptions(options, allowFSPaths) {
|
||||
return {
|
||||
channel: options.channel,
|
||||
args: options.args,
|
||||
ignoreAllDefaultArgs: options.ignoreAllDefaultArgs,
|
||||
ignoreDefaultArgs: options.ignoreDefaultArgs,
|
||||
timeout: options.timeout,
|
||||
headless: options.headless,
|
||||
proxy: options.proxy,
|
||||
chromiumSandbox: options.chromiumSandbox,
|
||||
firefoxUserPrefs: options.firefoxUserPrefs,
|
||||
slowMo: options.slowMo,
|
||||
executablePath: (0, _debug.isUnderTest)() || allowFSPaths ? options.executablePath : undefined,
|
||||
downloadsPath: allowFSPaths ? options.downloadsPath : undefined
|
||||
};
|
||||
}
|
||||
const defaultLaunchOptions = {
|
||||
ignoreAllDefaultArgs: false,
|
||||
handleSIGINT: false,
|
||||
handleSIGTERM: false,
|
||||
handleSIGHUP: false,
|
||||
headless: true,
|
||||
devtools: false
|
||||
};
|
||||
const optionsThatAllowBrowserReuse = ['headless', 'tracesDir'];
|
||||
124
node_modules/playwright-core/lib/remote/playwrightServer.js
generated
vendored
Normal file
124
node_modules/playwright-core/lib/remote/playwrightServer.js
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.PlaywrightServer = void 0;
|
||||
var _playwrightConnection = require("./playwrightConnection");
|
||||
var _playwright = require("../server/playwright");
|
||||
var _debugLogger = require("../server/utils/debugLogger");
|
||||
var _semaphore = require("../utils/isomorphic/semaphore");
|
||||
var _wsServer = require("../server/utils/wsServer");
|
||||
var _ascii = require("../server/utils/ascii");
|
||||
var _userAgent = require("../server/utils/userAgent");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class PlaywrightServer {
|
||||
constructor(options) {
|
||||
this._preLaunchedPlaywright = void 0;
|
||||
this._options = void 0;
|
||||
this._wsServer = void 0;
|
||||
this._options = options;
|
||||
if (options.preLaunchedBrowser) this._preLaunchedPlaywright = options.preLaunchedBrowser.attribution.playwright;
|
||||
if (options.preLaunchedAndroidDevice) this._preLaunchedPlaywright = options.preLaunchedAndroidDevice._android.attribution.playwright;
|
||||
const browserSemaphore = new _semaphore.Semaphore(this._options.maxConnections);
|
||||
const controllerSemaphore = new _semaphore.Semaphore(1);
|
||||
const reuseBrowserSemaphore = new _semaphore.Semaphore(1);
|
||||
this._wsServer = new _wsServer.WSServer({
|
||||
onUpgrade: (request, socket) => {
|
||||
const uaError = userAgentVersionMatchesErrorMessage(request.headers['user-agent'] || '');
|
||||
if (uaError) return {
|
||||
error: `HTTP/${request.httpVersion} 428 Precondition Required\r\n\r\n${uaError}`
|
||||
};
|
||||
},
|
||||
onHeaders: headers => {
|
||||
if (process.env.PWTEST_SERVER_WS_HEADERS) headers.push(process.env.PWTEST_SERVER_WS_HEADERS);
|
||||
},
|
||||
onConnection: (request, url, ws, id) => {
|
||||
const browserHeader = request.headers['x-playwright-browser'];
|
||||
const browserName = url.searchParams.get('browser') || (Array.isArray(browserHeader) ? browserHeader[0] : browserHeader) || null;
|
||||
const proxyHeader = request.headers['x-playwright-proxy'];
|
||||
const proxyValue = url.searchParams.get('proxy') || (Array.isArray(proxyHeader) ? proxyHeader[0] : proxyHeader);
|
||||
const launchOptionsHeader = request.headers['x-playwright-launch-options'] || '';
|
||||
const launchOptionsHeaderValue = Array.isArray(launchOptionsHeader) ? launchOptionsHeader[0] : launchOptionsHeader;
|
||||
const launchOptionsParam = url.searchParams.get('launch-options');
|
||||
let launchOptions = {};
|
||||
try {
|
||||
launchOptions = JSON.parse(launchOptionsParam || launchOptionsHeaderValue);
|
||||
} catch (e) {}
|
||||
|
||||
// Instantiate playwright for the extension modes.
|
||||
const isExtension = this._options.mode === 'extension';
|
||||
if (isExtension) {
|
||||
if (!this._preLaunchedPlaywright) this._preLaunchedPlaywright = (0, _playwright.createPlaywright)({
|
||||
sdkLanguage: 'javascript',
|
||||
isServer: true
|
||||
});
|
||||
}
|
||||
let clientType = 'launch-browser';
|
||||
let semaphore = browserSemaphore;
|
||||
if (isExtension && url.searchParams.has('debug-controller')) {
|
||||
clientType = 'controller';
|
||||
semaphore = controllerSemaphore;
|
||||
} else if (isExtension) {
|
||||
clientType = 'reuse-browser';
|
||||
semaphore = reuseBrowserSemaphore;
|
||||
} else if (this._options.mode === 'launchServer') {
|
||||
clientType = 'pre-launched-browser-or-android';
|
||||
semaphore = browserSemaphore;
|
||||
}
|
||||
return new _playwrightConnection.PlaywrightConnection(semaphore.acquire(), clientType, ws, {
|
||||
socksProxyPattern: proxyValue,
|
||||
browserName,
|
||||
launchOptions,
|
||||
allowFSPaths: this._options.mode === 'extension'
|
||||
}, {
|
||||
playwright: this._preLaunchedPlaywright,
|
||||
browser: this._options.preLaunchedBrowser,
|
||||
androidDevice: this._options.preLaunchedAndroidDevice,
|
||||
socksProxy: this._options.preLaunchedSocksProxy
|
||||
}, id, () => semaphore.release());
|
||||
},
|
||||
onClose: async () => {
|
||||
_debugLogger.debugLogger.log('server', 'closing browsers');
|
||||
if (this._preLaunchedPlaywright) await Promise.all(this._preLaunchedPlaywright.allBrowsers().map(browser => browser.close({
|
||||
reason: 'Playwright Server stopped'
|
||||
})));
|
||||
_debugLogger.debugLogger.log('server', 'closed browsers');
|
||||
}
|
||||
});
|
||||
}
|
||||
async listen(port = 0, hostname) {
|
||||
return this._wsServer.listen(port, hostname, this._options.path);
|
||||
}
|
||||
async close() {
|
||||
await this._wsServer.close();
|
||||
}
|
||||
}
|
||||
exports.PlaywrightServer = PlaywrightServer;
|
||||
function userAgentVersionMatchesErrorMessage(userAgent) {
|
||||
const match = userAgent.match(/^Playwright\/(\d+\.\d+\.\d+)/);
|
||||
if (!match) {
|
||||
// Cannot parse user agent - be lax.
|
||||
return;
|
||||
}
|
||||
const received = match[1].split('.').slice(0, 2).join('.');
|
||||
const expected = (0, _userAgent.getPlaywrightVersion)(true);
|
||||
if (received !== expected) {
|
||||
return (0, _ascii.wrapInASCIIBox)([`Playwright version mismatch:`, ` - server version: v${expected}`, ` - client version: v${received}`, ``, `If you are using VSCode extension, restart VSCode.`, ``, `If you are connecting to a remote service,`, `keep your local Playwright version in sync`, `with the remote service version.`, ``, `<3 Playwright Team`].join('\n'), 1);
|
||||
}
|
||||
}
|
||||
62
node_modules/playwright-core/lib/server/accessibility.js
generated
vendored
Normal file
62
node_modules/playwright-core/lib/server/accessibility.js
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Accessibility = void 0;
|
||||
/**
|
||||
* Copyright 2018 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Accessibility {
|
||||
constructor(getAXTree) {
|
||||
this._getAXTree = void 0;
|
||||
this._getAXTree = getAXTree;
|
||||
}
|
||||
async snapshot(options = {}) {
|
||||
const {
|
||||
interestingOnly = true,
|
||||
root = null
|
||||
} = options;
|
||||
const {
|
||||
tree,
|
||||
needle
|
||||
} = await this._getAXTree(root || undefined);
|
||||
if (!interestingOnly) {
|
||||
if (root) return needle && serializeTree(needle)[0];
|
||||
return serializeTree(tree)[0];
|
||||
}
|
||||
const interestingNodes = new Set();
|
||||
collectInterestingNodes(interestingNodes, tree, false);
|
||||
if (root && (!needle || !interestingNodes.has(needle))) return null;
|
||||
return serializeTree(needle || tree, interestingNodes)[0];
|
||||
}
|
||||
}
|
||||
exports.Accessibility = Accessibility;
|
||||
function collectInterestingNodes(collection, node, insideControl) {
|
||||
if (node.isInteresting(insideControl)) collection.add(node);
|
||||
if (node.isLeafNode()) return;
|
||||
insideControl = insideControl || node.isControl();
|
||||
for (const child of node.children()) collectInterestingNodes(collection, child, insideControl);
|
||||
}
|
||||
function serializeTree(node, whitelistedNodes) {
|
||||
const children = [];
|
||||
for (const child of node.children()) children.push(...serializeTree(child, whitelistedNodes));
|
||||
if (whitelistedNodes && !whitelistedNodes.has(node)) return children;
|
||||
const serializedNode = node.serialize();
|
||||
if (children.length) serializedNode.children = children;
|
||||
return [serializedNode];
|
||||
}
|
||||
444
node_modules/playwright-core/lib/server/android/android.js
generated
vendored
Normal file
444
node_modules/playwright-core/lib/server/android/android.js
generated
vendored
Normal file
@@ -0,0 +1,444 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.AndroidDevice = exports.Android = void 0;
|
||||
var _events = require("events");
|
||||
var _fs = _interopRequireDefault(require("fs"));
|
||||
var _os = _interopRequireDefault(require("os"));
|
||||
var _path = _interopRequireDefault(require("path"));
|
||||
var _timeoutSettings = require("../timeoutSettings");
|
||||
var _pipeTransport = require("../utils/pipeTransport");
|
||||
var _crypto = require("../utils/crypto");
|
||||
var _debug = require("../utils/debug");
|
||||
var _env = require("../utils/env");
|
||||
var _task = require("../utils/task");
|
||||
var _debugLogger = require("../utils/debugLogger");
|
||||
var _utilsBundle = require("../../utilsBundle");
|
||||
var _browserContext = require("../browserContext");
|
||||
var _chromiumSwitches = require("../chromium/chromiumSwitches");
|
||||
var _crBrowser = require("../chromium/crBrowser");
|
||||
var _fileUtils = require("../utils/fileUtils");
|
||||
var _helper = require("../helper");
|
||||
var _instrumentation = require("../instrumentation");
|
||||
var _processLauncher = require("../utils/processLauncher");
|
||||
var _progress = require("../progress");
|
||||
var _registry = require("../registry");
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
/**
|
||||
* Copyright Microsoft Corporation. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const ARTIFACTS_FOLDER = _path.default.join(_os.default.tmpdir(), 'playwright-artifacts-');
|
||||
class Android extends _instrumentation.SdkObject {
|
||||
constructor(parent, backend) {
|
||||
super(parent, 'android');
|
||||
this._backend = void 0;
|
||||
this._devices = new Map();
|
||||
this._timeoutSettings = void 0;
|
||||
this._backend = backend;
|
||||
this._timeoutSettings = new _timeoutSettings.TimeoutSettings();
|
||||
}
|
||||
setDefaultTimeout(timeout) {
|
||||
this._timeoutSettings.setDefaultTimeout(timeout);
|
||||
}
|
||||
async devices(options) {
|
||||
const devices = (await this._backend.devices(options)).filter(d => d.status === 'device');
|
||||
const newSerials = new Set();
|
||||
for (const d of devices) {
|
||||
newSerials.add(d.serial);
|
||||
if (this._devices.has(d.serial)) continue;
|
||||
const device = await AndroidDevice.create(this, d, options);
|
||||
this._devices.set(d.serial, device);
|
||||
}
|
||||
for (const d of this._devices.keys()) {
|
||||
if (!newSerials.has(d)) this._devices.delete(d);
|
||||
}
|
||||
return [...this._devices.values()];
|
||||
}
|
||||
_deviceClosed(device) {
|
||||
this._devices.delete(device.serial);
|
||||
}
|
||||
}
|
||||
exports.Android = Android;
|
||||
class AndroidDevice extends _instrumentation.SdkObject {
|
||||
constructor(android, backend, model, options) {
|
||||
super(android, 'android-device');
|
||||
this._backend = void 0;
|
||||
this.model = void 0;
|
||||
this.serial = void 0;
|
||||
this._options = void 0;
|
||||
this._driverPromise = void 0;
|
||||
this._lastId = 0;
|
||||
this._callbacks = new Map();
|
||||
this._pollingWebViews = void 0;
|
||||
this._timeoutSettings = void 0;
|
||||
this._webViews = new Map();
|
||||
this._browserConnections = new Set();
|
||||
this._android = void 0;
|
||||
this._isClosed = false;
|
||||
this._android = android;
|
||||
this._backend = backend;
|
||||
this.model = model;
|
||||
this.serial = backend.serial;
|
||||
this._options = options;
|
||||
this._timeoutSettings = new _timeoutSettings.TimeoutSettings(android._timeoutSettings);
|
||||
}
|
||||
static async create(android, backend, options) {
|
||||
await backend.init();
|
||||
const model = await backend.runCommand('shell:getprop ro.product.model');
|
||||
const device = new AndroidDevice(android, backend, model.toString().trim(), options);
|
||||
await device._init();
|
||||
return device;
|
||||
}
|
||||
async _init() {
|
||||
await this._refreshWebViews();
|
||||
const poll = () => {
|
||||
this._pollingWebViews = setTimeout(() => this._refreshWebViews().then(poll).catch(() => {
|
||||
this.close().catch(() => {});
|
||||
}), 500);
|
||||
};
|
||||
poll();
|
||||
}
|
||||
setDefaultTimeout(timeout) {
|
||||
this._timeoutSettings.setDefaultTimeout(timeout);
|
||||
}
|
||||
async shell(command) {
|
||||
const result = await this._backend.runCommand(`shell:${command}`);
|
||||
await this._refreshWebViews();
|
||||
return result;
|
||||
}
|
||||
async open(command) {
|
||||
return await this._backend.open(`${command}`);
|
||||
}
|
||||
async screenshot() {
|
||||
return await this._backend.runCommand(`shell:screencap -p`);
|
||||
}
|
||||
async _driver() {
|
||||
if (this._isClosed) return;
|
||||
if (!this._driverPromise) this._driverPromise = this._installDriver();
|
||||
return this._driverPromise;
|
||||
}
|
||||
async _installDriver() {
|
||||
(0, _utilsBundle.debug)('pw:android')('Stopping the old driver');
|
||||
await this.shell(`am force-stop com.microsoft.playwright.androiddriver`);
|
||||
|
||||
// uninstall and install driver on every execution
|
||||
if (!this._options.omitDriverInstall) {
|
||||
(0, _utilsBundle.debug)('pw:android')('Uninstalling the old driver');
|
||||
await this.shell(`cmd package uninstall com.microsoft.playwright.androiddriver`);
|
||||
await this.shell(`cmd package uninstall com.microsoft.playwright.androiddriver.test`);
|
||||
(0, _utilsBundle.debug)('pw:android')('Installing the new driver');
|
||||
const executable = _registry.registry.findExecutable('android');
|
||||
const packageManagerCommand = (0, _env.getPackageManagerExecCommand)();
|
||||
for (const file of ['android-driver.apk', 'android-driver-target.apk']) {
|
||||
const fullName = _path.default.join(executable.directory, file);
|
||||
if (!_fs.default.existsSync(fullName)) throw new Error(`Please install Android driver apk using '${packageManagerCommand} playwright install android'`);
|
||||
await this.installApk(await _fs.default.promises.readFile(fullName));
|
||||
}
|
||||
} else {
|
||||
(0, _utilsBundle.debug)('pw:android')('Skipping the driver installation');
|
||||
}
|
||||
(0, _utilsBundle.debug)('pw:android')('Starting the new driver');
|
||||
this.shell('am instrument -w com.microsoft.playwright.androiddriver.test/androidx.test.runner.AndroidJUnitRunner').catch(e => (0, _utilsBundle.debug)('pw:android')(e));
|
||||
const socket = await this._waitForLocalAbstract('playwright_android_driver_socket');
|
||||
const transport = new _pipeTransport.PipeTransport(socket, socket, socket, 'be');
|
||||
transport.onmessage = message => {
|
||||
const response = JSON.parse(message);
|
||||
const {
|
||||
id,
|
||||
result,
|
||||
error
|
||||
} = response;
|
||||
const callback = this._callbacks.get(id);
|
||||
if (!callback) return;
|
||||
if (error) callback.reject(new Error(error));else callback.fulfill(result);
|
||||
this._callbacks.delete(id);
|
||||
};
|
||||
return transport;
|
||||
}
|
||||
async _waitForLocalAbstract(socketName) {
|
||||
let socket;
|
||||
(0, _utilsBundle.debug)('pw:android')(`Polling the socket localabstract:${socketName}`);
|
||||
while (!socket) {
|
||||
try {
|
||||
socket = await this._backend.open(`localabstract:${socketName}`);
|
||||
} catch (e) {
|
||||
await new Promise(f => setTimeout(f, 250));
|
||||
}
|
||||
}
|
||||
(0, _utilsBundle.debug)('pw:android')(`Connected to localabstract:${socketName}`);
|
||||
return socket;
|
||||
}
|
||||
async send(method, params = {}) {
|
||||
// Patch the timeout in!
|
||||
params.timeout = this._timeoutSettings.timeout(params);
|
||||
const driver = await this._driver();
|
||||
if (!driver) throw new Error('Device is closed');
|
||||
const id = ++this._lastId;
|
||||
const result = new Promise((fulfill, reject) => this._callbacks.set(id, {
|
||||
fulfill,
|
||||
reject
|
||||
}));
|
||||
driver.send(JSON.stringify({
|
||||
id,
|
||||
method,
|
||||
params
|
||||
}));
|
||||
return result;
|
||||
}
|
||||
async close() {
|
||||
if (this._isClosed) return;
|
||||
this._isClosed = true;
|
||||
if (this._pollingWebViews) clearTimeout(this._pollingWebViews);
|
||||
for (const connection of this._browserConnections) await connection.close();
|
||||
if (this._driverPromise) {
|
||||
const driver = await this._driver();
|
||||
driver === null || driver === void 0 || driver.close();
|
||||
}
|
||||
await this._backend.close();
|
||||
this._android._deviceClosed(this);
|
||||
this.emit(AndroidDevice.Events.Close);
|
||||
}
|
||||
async launchBrowser(pkg = 'com.android.chrome', options) {
|
||||
(0, _utilsBundle.debug)('pw:android')('Force-stopping', pkg);
|
||||
await this._backend.runCommand(`shell:am force-stop ${pkg}`);
|
||||
const socketName = (0, _debug.isUnderTest)() ? 'webview_devtools_remote_playwright_test' : 'playwright_' + (0, _crypto.createGuid)() + '_devtools_remote';
|
||||
const commandLine = this._defaultArgs(options, socketName).join(' ');
|
||||
(0, _utilsBundle.debug)('pw:android')('Starting', pkg, commandLine);
|
||||
// encode commandLine to base64 to avoid issues (bash encoding) with special characters
|
||||
await this._backend.runCommand(`shell:echo "${Buffer.from(commandLine).toString('base64')}" | base64 -d > /data/local/tmp/chrome-command-line`);
|
||||
await this._backend.runCommand(`shell:am start -a android.intent.action.VIEW -d about:blank ${pkg}`);
|
||||
const browserContext = await this._connectToBrowser(socketName, options);
|
||||
await this._backend.runCommand(`shell:rm /data/local/tmp/chrome-command-line`);
|
||||
return browserContext;
|
||||
}
|
||||
_defaultArgs(options, socketName) {
|
||||
const chromeArguments = ['_', '--disable-fre', '--no-default-browser-check', `--remote-debugging-socket-name=${socketName}`, ..._chromiumSwitches.chromiumSwitches, ...this._innerDefaultArgs(options)];
|
||||
return chromeArguments;
|
||||
}
|
||||
_innerDefaultArgs(options) {
|
||||
const {
|
||||
args = [],
|
||||
proxy
|
||||
} = options;
|
||||
const chromeArguments = [];
|
||||
if (proxy) {
|
||||
chromeArguments.push(`--proxy-server=${proxy.server}`);
|
||||
const proxyBypassRules = [];
|
||||
if (proxy.bypass) proxyBypassRules.push(...proxy.bypass.split(',').map(t => t.trim()).map(t => t.startsWith('.') ? '*' + t : t));
|
||||
if (!process.env.PLAYWRIGHT_DISABLE_FORCED_CHROMIUM_PROXIED_LOOPBACK && !proxyBypassRules.includes('<-loopback>')) proxyBypassRules.push('<-loopback>');
|
||||
if (proxyBypassRules.length > 0) chromeArguments.push(`--proxy-bypass-list=${proxyBypassRules.join(';')}`);
|
||||
}
|
||||
chromeArguments.push(...args);
|
||||
return chromeArguments;
|
||||
}
|
||||
async connectToWebView(socketName) {
|
||||
const webView = this._webViews.get(socketName);
|
||||
if (!webView) throw new Error('WebView has been closed');
|
||||
return await this._connectToBrowser(socketName);
|
||||
}
|
||||
async _connectToBrowser(socketName, options = {}) {
|
||||
const socket = await this._waitForLocalAbstract(socketName);
|
||||
const androidBrowser = new AndroidBrowser(this, socket);
|
||||
await androidBrowser._init();
|
||||
this._browserConnections.add(androidBrowser);
|
||||
const artifactsDir = await _fs.default.promises.mkdtemp(ARTIFACTS_FOLDER);
|
||||
const cleanupArtifactsDir = async () => {
|
||||
const errors = await (0, _fileUtils.removeFolders)([artifactsDir]);
|
||||
for (let i = 0; i < (errors || []).length; ++i) (0, _utilsBundle.debug)('pw:android')(`exception while removing ${artifactsDir}: ${errors[i]}`);
|
||||
};
|
||||
_processLauncher.gracefullyCloseSet.add(cleanupArtifactsDir);
|
||||
socket.on('close', async () => {
|
||||
_processLauncher.gracefullyCloseSet.delete(cleanupArtifactsDir);
|
||||
cleanupArtifactsDir().catch(e => (0, _utilsBundle.debug)('pw:android')(`could not cleanup artifacts dir: ${e}`));
|
||||
});
|
||||
const browserOptions = {
|
||||
name: 'clank',
|
||||
isChromium: true,
|
||||
slowMo: 0,
|
||||
persistent: {
|
||||
...options,
|
||||
noDefaultViewport: true
|
||||
},
|
||||
artifactsDir,
|
||||
downloadsPath: artifactsDir,
|
||||
tracesDir: artifactsDir,
|
||||
browserProcess: new ClankBrowserProcess(androidBrowser),
|
||||
proxy: options.proxy,
|
||||
protocolLogger: _helper.helper.debugProtocolLogger(),
|
||||
browserLogsCollector: new _debugLogger.RecentLogsCollector(),
|
||||
originalLaunchOptions: {}
|
||||
};
|
||||
(0, _browserContext.validateBrowserContextOptions)(options, browserOptions);
|
||||
const browser = await _crBrowser.CRBrowser.connect(this.attribution.playwright, androidBrowser, browserOptions);
|
||||
const controller = new _progress.ProgressController((0, _instrumentation.serverSideCallMetadata)(), this);
|
||||
const defaultContext = browser._defaultContext;
|
||||
await controller.run(async progress => {
|
||||
await defaultContext._loadDefaultContextAsIs(progress);
|
||||
});
|
||||
return defaultContext;
|
||||
}
|
||||
webViews() {
|
||||
return [...this._webViews.values()];
|
||||
}
|
||||
async installApk(content, options) {
|
||||
const args = options && options.args ? options.args : ['-r', '-t', '-S'];
|
||||
(0, _utilsBundle.debug)('pw:android')('Opening install socket');
|
||||
const installSocket = await this._backend.open(`shell:cmd package install ${args.join(' ')} ${content.length}`);
|
||||
(0, _utilsBundle.debug)('pw:android')('Writing driver bytes: ' + content.length);
|
||||
await installSocket.write(content);
|
||||
const success = await new Promise(f => installSocket.on('data', f));
|
||||
(0, _utilsBundle.debug)('pw:android')('Written driver bytes: ' + success);
|
||||
installSocket.close();
|
||||
}
|
||||
async push(content, path, mode = 0o644) {
|
||||
const socket = await this._backend.open(`sync:`);
|
||||
const sendHeader = async (command, length) => {
|
||||
const buffer = Buffer.alloc(command.length + 4);
|
||||
buffer.write(command, 0);
|
||||
buffer.writeUInt32LE(length, command.length);
|
||||
await socket.write(buffer);
|
||||
};
|
||||
const send = async (command, data) => {
|
||||
await sendHeader(command, data.length);
|
||||
await socket.write(data);
|
||||
};
|
||||
await send('SEND', Buffer.from(`${path},${mode}`));
|
||||
const maxChunk = 65535;
|
||||
for (let i = 0; i < content.length; i += maxChunk) await send('DATA', content.slice(i, i + maxChunk));
|
||||
await sendHeader('DONE', Date.now() / 1000 | 0);
|
||||
const result = await new Promise(f => socket.once('data', f));
|
||||
const code = result.slice(0, 4).toString();
|
||||
if (code !== 'OKAY') throw new Error('Could not push: ' + code);
|
||||
socket.close();
|
||||
}
|
||||
async _refreshWebViews() {
|
||||
// possible socketName, eg: webview_devtools_remote_32327, webview_devtools_remote_32327_zeus, webview_devtools_remote_zeus
|
||||
const sockets = (await this._backend.runCommand(`shell:cat /proc/net/unix | grep webview_devtools_remote`)).toString().split('\n');
|
||||
if (this._isClosed) return;
|
||||
const socketNames = new Set();
|
||||
for (const line of sockets) {
|
||||
const matchSocketName = line.match(/[^@]+@(.*?webview_devtools_remote_?.*)/);
|
||||
if (!matchSocketName) continue;
|
||||
const socketName = matchSocketName[1];
|
||||
socketNames.add(socketName);
|
||||
if (this._webViews.has(socketName)) continue;
|
||||
|
||||
// possible line: 0000000000000000: 00000002 00000000 00010000 0001 01 5841881 @webview_devtools_remote_zeus
|
||||
// the result: match[1] = ''
|
||||
const match = line.match(/[^@]+@.*?webview_devtools_remote_?(\d*)/);
|
||||
let pid = -1;
|
||||
if (match && match[1]) pid = +match[1];
|
||||
const pkg = await this._extractPkg(pid);
|
||||
if (this._isClosed) return;
|
||||
const webView = {
|
||||
pid,
|
||||
pkg,
|
||||
socketName
|
||||
};
|
||||
this._webViews.set(socketName, webView);
|
||||
this.emit(AndroidDevice.Events.WebViewAdded, webView);
|
||||
}
|
||||
for (const p of this._webViews.keys()) {
|
||||
if (!socketNames.has(p)) {
|
||||
this._webViews.delete(p);
|
||||
this.emit(AndroidDevice.Events.WebViewRemoved, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
async _extractPkg(pid) {
|
||||
let pkg = '';
|
||||
if (pid === -1) return pkg;
|
||||
const procs = (await this._backend.runCommand(`shell:ps -A | grep ${pid}`)).toString().split('\n');
|
||||
for (const proc of procs) {
|
||||
const match = proc.match(/[^\s]+\s+(\d+).*$/);
|
||||
if (!match) continue;
|
||||
pkg = proc.substring(proc.lastIndexOf(' ') + 1);
|
||||
}
|
||||
return pkg;
|
||||
}
|
||||
}
|
||||
exports.AndroidDevice = AndroidDevice;
|
||||
AndroidDevice.Events = {
|
||||
WebViewAdded: 'webViewAdded',
|
||||
WebViewRemoved: 'webViewRemoved',
|
||||
Close: 'close'
|
||||
};
|
||||
class AndroidBrowser extends _events.EventEmitter {
|
||||
constructor(device, socket) {
|
||||
super();
|
||||
this.device = void 0;
|
||||
this._socket = void 0;
|
||||
this._receiver = void 0;
|
||||
this._waitForNextTask = (0, _task.makeWaitForNextTask)();
|
||||
this.onmessage = void 0;
|
||||
this.onclose = void 0;
|
||||
this.setMaxListeners(0);
|
||||
this.device = device;
|
||||
this._socket = socket;
|
||||
this._socket.on('close', () => {
|
||||
this._waitForNextTask(() => {
|
||||
if (this.onclose) this.onclose();
|
||||
});
|
||||
});
|
||||
this._receiver = new _utilsBundle.wsReceiver();
|
||||
this._receiver.on('message', message => {
|
||||
this._waitForNextTask(() => {
|
||||
if (this.onmessage) this.onmessage(JSON.parse(message));
|
||||
});
|
||||
});
|
||||
}
|
||||
async _init() {
|
||||
await this._socket.write(Buffer.from(`GET /devtools/browser HTTP/1.1\r
|
||||
Upgrade: WebSocket\r
|
||||
Connection: Upgrade\r
|
||||
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r
|
||||
Sec-WebSocket-Version: 13\r
|
||||
\r
|
||||
`));
|
||||
// HTTP Upgrade response.
|
||||
await new Promise(f => this._socket.once('data', f));
|
||||
|
||||
// Start sending web frame to receiver.
|
||||
this._socket.on('data', data => this._receiver._write(data, 'binary', () => {}));
|
||||
}
|
||||
async send(s) {
|
||||
await this._socket.write(encodeWebFrame(JSON.stringify(s)));
|
||||
}
|
||||
async close() {
|
||||
this._socket.close();
|
||||
}
|
||||
}
|
||||
function encodeWebFrame(data) {
|
||||
return _utilsBundle.wsSender.frame(Buffer.from(data), {
|
||||
opcode: 1,
|
||||
mask: true,
|
||||
fin: true,
|
||||
readOnly: true
|
||||
})[0];
|
||||
}
|
||||
class ClankBrowserProcess {
|
||||
constructor(browser) {
|
||||
this._browser = void 0;
|
||||
this.onclose = void 0;
|
||||
this._browser = browser;
|
||||
}
|
||||
async kill() {}
|
||||
async close() {
|
||||
await this._browser.close();
|
||||
}
|
||||
}
|
||||
172
node_modules/playwright-core/lib/server/android/backendAdb.js
generated
vendored
Normal file
172
node_modules/playwright-core/lib/server/android/backendAdb.js
generated
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.AdbBackend = void 0;
|
||||
var _events = require("events");
|
||||
var _net = _interopRequireDefault(require("net"));
|
||||
var _assert = require("../../utils/isomorphic/assert");
|
||||
var _crypto = require("../utils/crypto");
|
||||
var _utilsBundle = require("../../utilsBundle");
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
/**
|
||||
* Copyright Microsoft Corporation. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class AdbBackend {
|
||||
async devices(options = {}) {
|
||||
const result = await runCommand('host:devices', options.host, options.port);
|
||||
const lines = result.toString().trim().split('\n');
|
||||
return lines.map(line => {
|
||||
const [serial, status] = line.trim().split('\t');
|
||||
return new AdbDevice(serial, status, options.host, options.port);
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.AdbBackend = AdbBackend;
|
||||
class AdbDevice {
|
||||
constructor(serial, status, host, port) {
|
||||
this.serial = void 0;
|
||||
this.status = void 0;
|
||||
this.host = void 0;
|
||||
this.port = void 0;
|
||||
this._closed = false;
|
||||
this.serial = serial;
|
||||
this.status = status;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
}
|
||||
async init() {}
|
||||
async close() {
|
||||
this._closed = true;
|
||||
}
|
||||
runCommand(command) {
|
||||
if (this._closed) throw new Error('Device is closed');
|
||||
return runCommand(command, this.host, this.port, this.serial);
|
||||
}
|
||||
async open(command) {
|
||||
if (this._closed) throw new Error('Device is closed');
|
||||
const result = await open(command, this.host, this.port, this.serial);
|
||||
result.becomeSocket();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
async function runCommand(command, host = '127.0.0.1', port = 5037, serial) {
|
||||
(0, _utilsBundle.debug)('pw:adb:runCommand')(command, serial);
|
||||
const socket = new BufferedSocketWrapper(command, _net.default.createConnection({
|
||||
host,
|
||||
port
|
||||
}));
|
||||
try {
|
||||
if (serial) {
|
||||
await socket.write(encodeMessage(`host:transport:${serial}`));
|
||||
const status = await socket.read(4);
|
||||
(0, _assert.assert)(status.toString() === 'OKAY', status.toString());
|
||||
}
|
||||
await socket.write(encodeMessage(command));
|
||||
const status = await socket.read(4);
|
||||
(0, _assert.assert)(status.toString() === 'OKAY', status.toString());
|
||||
let commandOutput;
|
||||
if (!command.startsWith('shell:')) {
|
||||
const remainingLength = parseInt((await socket.read(4)).toString(), 16);
|
||||
commandOutput = await socket.read(remainingLength);
|
||||
} else {
|
||||
commandOutput = await socket.readAll();
|
||||
}
|
||||
return commandOutput;
|
||||
} finally {
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
async function open(command, host = '127.0.0.1', port = 5037, serial) {
|
||||
const socket = new BufferedSocketWrapper(command, _net.default.createConnection({
|
||||
host,
|
||||
port
|
||||
}));
|
||||
if (serial) {
|
||||
await socket.write(encodeMessage(`host:transport:${serial}`));
|
||||
const status = await socket.read(4);
|
||||
(0, _assert.assert)(status.toString() === 'OKAY', status.toString());
|
||||
}
|
||||
await socket.write(encodeMessage(command));
|
||||
const status = await socket.read(4);
|
||||
(0, _assert.assert)(status.toString() === 'OKAY', status.toString());
|
||||
return socket;
|
||||
}
|
||||
function encodeMessage(message) {
|
||||
let lenHex = message.length.toString(16);
|
||||
lenHex = '0'.repeat(4 - lenHex.length) + lenHex;
|
||||
return Buffer.from(lenHex + message);
|
||||
}
|
||||
class BufferedSocketWrapper extends _events.EventEmitter {
|
||||
constructor(command, socket) {
|
||||
super();
|
||||
this.guid = (0, _crypto.createGuid)();
|
||||
this._socket = void 0;
|
||||
this._buffer = Buffer.from([]);
|
||||
this._isSocket = false;
|
||||
this._notifyReader = void 0;
|
||||
this._connectPromise = void 0;
|
||||
this._isClosed = false;
|
||||
this._command = void 0;
|
||||
this._command = command;
|
||||
this._socket = socket;
|
||||
this._connectPromise = new Promise(f => this._socket.on('connect', f));
|
||||
this._socket.on('data', data => {
|
||||
(0, _utilsBundle.debug)('pw:adb:data')(data.toString());
|
||||
if (this._isSocket) {
|
||||
this.emit('data', data);
|
||||
return;
|
||||
}
|
||||
this._buffer = Buffer.concat([this._buffer, data]);
|
||||
if (this._notifyReader) this._notifyReader();
|
||||
});
|
||||
this._socket.on('close', () => {
|
||||
this._isClosed = true;
|
||||
if (this._notifyReader) this._notifyReader();
|
||||
this.close();
|
||||
this.emit('close');
|
||||
});
|
||||
this._socket.on('error', error => this.emit('error', error));
|
||||
}
|
||||
async write(data) {
|
||||
(0, _utilsBundle.debug)('pw:adb:send')(data.toString().substring(0, 100) + '...');
|
||||
await this._connectPromise;
|
||||
await new Promise(f => this._socket.write(data, f));
|
||||
}
|
||||
close() {
|
||||
if (this._isClosed) return;
|
||||
(0, _utilsBundle.debug)('pw:adb')('Close ' + this._command);
|
||||
this._socket.destroy();
|
||||
}
|
||||
async read(length) {
|
||||
await this._connectPromise;
|
||||
(0, _assert.assert)(!this._isSocket, 'Can not read by length in socket mode');
|
||||
while (this._buffer.length < length) await new Promise(f => this._notifyReader = f);
|
||||
const result = this._buffer.slice(0, length);
|
||||
this._buffer = this._buffer.slice(length);
|
||||
(0, _utilsBundle.debug)('pw:adb:recv')(result.toString().substring(0, 100) + '...');
|
||||
return result;
|
||||
}
|
||||
async readAll() {
|
||||
while (!this._isClosed) await new Promise(f => this._notifyReader = f);
|
||||
return this._buffer;
|
||||
}
|
||||
becomeSocket() {
|
||||
(0, _assert.assert)(!this._buffer.length);
|
||||
this._isSocket = true;
|
||||
}
|
||||
}
|
||||
104
node_modules/playwright-core/lib/server/artifact.js
generated
vendored
Normal file
104
node_modules/playwright-core/lib/server/artifact.js
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Artifact = void 0;
|
||||
var _fs = _interopRequireDefault(require("fs"));
|
||||
var _utils = require("../utils");
|
||||
var _errors = require("./errors");
|
||||
var _instrumentation = require("./instrumentation");
|
||||
var _manualPromise = require("../utils/isomorphic/manualPromise");
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Artifact extends _instrumentation.SdkObject {
|
||||
constructor(parent, localPath, unaccessibleErrorMessage, cancelCallback) {
|
||||
super(parent, 'artifact');
|
||||
this._localPath = void 0;
|
||||
this._unaccessibleErrorMessage = void 0;
|
||||
this._cancelCallback = void 0;
|
||||
this._finishedPromise = new _manualPromise.ManualPromise();
|
||||
this._saveCallbacks = [];
|
||||
this._finished = false;
|
||||
this._deleted = false;
|
||||
this._failureError = void 0;
|
||||
this._localPath = localPath;
|
||||
this._unaccessibleErrorMessage = unaccessibleErrorMessage;
|
||||
this._cancelCallback = cancelCallback;
|
||||
}
|
||||
finishedPromise() {
|
||||
return this._finishedPromise;
|
||||
}
|
||||
localPath() {
|
||||
return this._localPath;
|
||||
}
|
||||
async localPathAfterFinished() {
|
||||
if (this._unaccessibleErrorMessage) throw new Error(this._unaccessibleErrorMessage);
|
||||
await this._finishedPromise;
|
||||
if (this._failureError) throw this._failureError;
|
||||
return this._localPath;
|
||||
}
|
||||
saveAs(saveCallback) {
|
||||
if (this._unaccessibleErrorMessage) throw new Error(this._unaccessibleErrorMessage);
|
||||
if (this._deleted) throw new Error(`File already deleted. Save before deleting.`);
|
||||
if (this._failureError) throw this._failureError;
|
||||
if (this._finished) {
|
||||
saveCallback(this._localPath).catch(() => {});
|
||||
return;
|
||||
}
|
||||
this._saveCallbacks.push(saveCallback);
|
||||
}
|
||||
async failureError() {
|
||||
var _this$_failureError;
|
||||
if (this._unaccessibleErrorMessage) return this._unaccessibleErrorMessage;
|
||||
await this._finishedPromise;
|
||||
return ((_this$_failureError = this._failureError) === null || _this$_failureError === void 0 ? void 0 : _this$_failureError.message) || null;
|
||||
}
|
||||
async cancel() {
|
||||
(0, _utils.assert)(this._cancelCallback !== undefined);
|
||||
return this._cancelCallback();
|
||||
}
|
||||
async delete() {
|
||||
if (this._unaccessibleErrorMessage) return;
|
||||
const fileName = await this.localPathAfterFinished();
|
||||
if (this._deleted) return;
|
||||
this._deleted = true;
|
||||
if (fileName) await _fs.default.promises.unlink(fileName).catch(e => {});
|
||||
}
|
||||
async deleteOnContextClose() {
|
||||
// Compared to "delete", this method does not wait for the artifact to finish.
|
||||
// We use it when closing the context to avoid stalling.
|
||||
if (this._deleted) return;
|
||||
this._deleted = true;
|
||||
if (!this._unaccessibleErrorMessage) await _fs.default.promises.unlink(this._localPath).catch(e => {});
|
||||
await this.reportFinished(new _errors.TargetClosedError());
|
||||
}
|
||||
async reportFinished(error) {
|
||||
if (this._finished) return;
|
||||
this._finished = true;
|
||||
this._failureError = error;
|
||||
if (error) {
|
||||
for (const callback of this._saveCallbacks) await callback('', error);
|
||||
} else {
|
||||
for (const callback of this._saveCallbacks) await callback(this._localPath);
|
||||
}
|
||||
this._saveCallbacks = [];
|
||||
this._finishedPromise.resolve();
|
||||
}
|
||||
}
|
||||
exports.Artifact = Artifact;
|
||||
314
node_modules/playwright-core/lib/server/bidi/bidiBrowser.js
generated
vendored
Normal file
314
node_modules/playwright-core/lib/server/bidi/bidiBrowser.js
generated
vendored
Normal file
@@ -0,0 +1,314 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Network = exports.BidiBrowserContext = exports.BidiBrowser = void 0;
|
||||
var _eventsHelper = require("../utils/eventsHelper");
|
||||
var _browser = require("../browser");
|
||||
var _browserContext = require("../browserContext");
|
||||
var network = _interopRequireWildcard(require("../network"));
|
||||
var _bidiConnection = require("./bidiConnection");
|
||||
var _bidiNetworkManager = require("./bidiNetworkManager");
|
||||
var _bidiPage = require("./bidiPage");
|
||||
var bidi = _interopRequireWildcard(require("./third_party/bidiProtocol"));
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class BidiBrowser extends _browser.Browser {
|
||||
static async connect(parent, transport, options) {
|
||||
const browser = new BidiBrowser(parent, transport, options);
|
||||
if (options.__testHookOnConnectToBrowser) await options.__testHookOnConnectToBrowser();
|
||||
let proxy;
|
||||
if (options.proxy) {
|
||||
proxy = {
|
||||
proxyType: 'manual'
|
||||
};
|
||||
const url = new URL(options.proxy.server); // Validate proxy server.
|
||||
switch (url.protocol) {
|
||||
case 'http:':
|
||||
proxy.httpProxy = url.host;
|
||||
break;
|
||||
case 'https:':
|
||||
proxy.httpsProxy = url.host;
|
||||
break;
|
||||
case 'socks4:':
|
||||
proxy.socksProxy = url.host;
|
||||
proxy.socksVersion = 4;
|
||||
break;
|
||||
case 'socks5:':
|
||||
proxy.socksProxy = url.host;
|
||||
proxy.socksVersion = 5;
|
||||
break;
|
||||
default:
|
||||
throw new Error('Invalid proxy server protocol: ' + options.proxy.server);
|
||||
}
|
||||
if (options.proxy.bypass) proxy.noProxy = options.proxy.bypass.split(',');
|
||||
// TODO: support authentication.
|
||||
}
|
||||
browser._bidiSessionInfo = await browser._browserSession.send('session.new', {
|
||||
capabilities: {
|
||||
alwaysMatch: {
|
||||
acceptInsecureCerts: false,
|
||||
proxy,
|
||||
unhandledPromptBehavior: {
|
||||
default: bidi.Session.UserPromptHandlerType.Ignore
|
||||
},
|
||||
webSocketUrl: true
|
||||
}
|
||||
}
|
||||
});
|
||||
await browser._browserSession.send('session.subscribe', {
|
||||
events: ['browsingContext', 'network', 'log', 'script']
|
||||
});
|
||||
if (options.persistent) {
|
||||
browser._defaultContext = new BidiBrowserContext(browser, undefined, options.persistent);
|
||||
await browser._defaultContext._initialize();
|
||||
// Create default page as we cannot get access to the existing one.
|
||||
const page = await browser._defaultContext.doCreateNewPage();
|
||||
await page.waitForInitializedOrError();
|
||||
}
|
||||
return browser;
|
||||
}
|
||||
constructor(parent, transport, options) {
|
||||
super(parent, options);
|
||||
this._connection = void 0;
|
||||
this._browserSession = void 0;
|
||||
this._bidiSessionInfo = void 0;
|
||||
this._contexts = new Map();
|
||||
this._bidiPages = new Map();
|
||||
this._eventListeners = void 0;
|
||||
this._connection = new _bidiConnection.BidiConnection(transport, this._onDisconnect.bind(this), options.protocolLogger, options.browserLogsCollector);
|
||||
this._browserSession = this._connection.browserSession;
|
||||
this._eventListeners = [_eventsHelper.eventsHelper.addEventListener(this._browserSession, 'browsingContext.contextCreated', this._onBrowsingContextCreated.bind(this)), _eventsHelper.eventsHelper.addEventListener(this._browserSession, 'script.realmDestroyed', this._onScriptRealmDestroyed.bind(this))];
|
||||
}
|
||||
_onDisconnect() {
|
||||
this._didClose();
|
||||
}
|
||||
async doCreateNewContext(options) {
|
||||
const {
|
||||
userContext
|
||||
} = await this._browserSession.send('browser.createUserContext', {});
|
||||
const context = new BidiBrowserContext(this, userContext, options);
|
||||
await context._initialize();
|
||||
this._contexts.set(userContext, context);
|
||||
return context;
|
||||
}
|
||||
contexts() {
|
||||
return Array.from(this._contexts.values());
|
||||
}
|
||||
version() {
|
||||
return this._bidiSessionInfo.capabilities.browserVersion;
|
||||
}
|
||||
userAgent() {
|
||||
return this._bidiSessionInfo.capabilities.userAgent;
|
||||
}
|
||||
isConnected() {
|
||||
return !this._connection.isClosed();
|
||||
}
|
||||
_onBrowsingContextCreated(event) {
|
||||
if (event.parent) {
|
||||
const parentFrameId = event.parent;
|
||||
for (const page of this._bidiPages.values()) {
|
||||
const parentFrame = page._page._frameManager.frame(parentFrameId);
|
||||
if (!parentFrame) continue;
|
||||
page._session.addFrameBrowsingContext(event.context);
|
||||
page._page._frameManager.frameAttached(event.context, parentFrameId);
|
||||
const frame = page._page._frameManager.frame(event.context);
|
||||
if (frame) frame._url = event.url;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
let context = this._contexts.get(event.userContext);
|
||||
if (!context) context = this._defaultContext;
|
||||
if (!context) return;
|
||||
const session = this._connection.createMainFrameBrowsingContextSession(event.context);
|
||||
const opener = event.originalOpener && this._bidiPages.get(event.originalOpener);
|
||||
const page = new _bidiPage.BidiPage(context, session, opener || null);
|
||||
page._page.mainFrame()._url = event.url;
|
||||
this._bidiPages.set(event.context, page);
|
||||
}
|
||||
_onBrowsingContextDestroyed(event) {
|
||||
if (event.parent) {
|
||||
this._browserSession.removeFrameBrowsingContext(event.context);
|
||||
const parentFrameId = event.parent;
|
||||
for (const page of this._bidiPages.values()) {
|
||||
const parentFrame = page._page._frameManager.frame(parentFrameId);
|
||||
if (!parentFrame) continue;
|
||||
page._page._frameManager.frameDetached(event.context);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
const bidiPage = this._bidiPages.get(event.context);
|
||||
if (!bidiPage) return;
|
||||
bidiPage.didClose();
|
||||
this._bidiPages.delete(event.context);
|
||||
}
|
||||
_onScriptRealmDestroyed(event) {
|
||||
for (const page of this._bidiPages.values()) {
|
||||
if (page._onRealmDestroyed(event)) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.BidiBrowser = BidiBrowser;
|
||||
class BidiBrowserContext extends _browserContext.BrowserContext {
|
||||
constructor(browser, browserContextId, options) {
|
||||
super(browser, options, browserContextId);
|
||||
this._authenticateProxyViaHeader();
|
||||
}
|
||||
_bidiPages() {
|
||||
return [...this._browser._bidiPages.values()].filter(bidiPage => bidiPage._browserContext === this);
|
||||
}
|
||||
possiblyUninitializedPages() {
|
||||
return this._bidiPages().map(bidiPage => bidiPage._page);
|
||||
}
|
||||
async doCreateNewPage() {
|
||||
(0, _browserContext.assertBrowserContextIsNotOwned)(this);
|
||||
const {
|
||||
context
|
||||
} = await this._browser._browserSession.send('browsingContext.create', {
|
||||
type: bidi.BrowsingContext.CreateType.Window,
|
||||
userContext: this._browserContextId
|
||||
});
|
||||
return this._browser._bidiPages.get(context)._page;
|
||||
}
|
||||
async doGetCookies(urls) {
|
||||
const {
|
||||
cookies
|
||||
} = await this._browser._browserSession.send('storage.getCookies', {
|
||||
partition: {
|
||||
type: 'storageKey',
|
||||
userContext: this._browserContextId
|
||||
}
|
||||
});
|
||||
return network.filterCookies(cookies.map(c => {
|
||||
var _c$expiry;
|
||||
const copy = {
|
||||
name: c.name,
|
||||
value: (0, _bidiNetworkManager.bidiBytesValueToString)(c.value),
|
||||
domain: c.domain,
|
||||
path: c.path,
|
||||
httpOnly: c.httpOnly,
|
||||
secure: c.secure,
|
||||
expires: (_c$expiry = c.expiry) !== null && _c$expiry !== void 0 ? _c$expiry : -1,
|
||||
sameSite: c.sameSite ? fromBidiSameSite(c.sameSite) : 'None'
|
||||
};
|
||||
return copy;
|
||||
}), urls);
|
||||
}
|
||||
async addCookies(cookies) {
|
||||
cookies = network.rewriteCookies(cookies);
|
||||
const promises = cookies.map(c => {
|
||||
const cookie = {
|
||||
name: c.name,
|
||||
value: {
|
||||
type: 'string',
|
||||
value: c.value
|
||||
},
|
||||
domain: c.domain,
|
||||
path: c.path,
|
||||
httpOnly: c.httpOnly,
|
||||
secure: c.secure,
|
||||
sameSite: c.sameSite && toBidiSameSite(c.sameSite),
|
||||
expiry: c.expires === -1 || c.expires === undefined ? undefined : Math.round(c.expires)
|
||||
};
|
||||
return this._browser._browserSession.send('storage.setCookie', {
|
||||
cookie,
|
||||
partition: {
|
||||
type: 'storageKey',
|
||||
userContext: this._browserContextId
|
||||
}
|
||||
});
|
||||
});
|
||||
await Promise.all(promises);
|
||||
}
|
||||
async doClearCookies() {
|
||||
await this._browser._browserSession.send('storage.deleteCookies', {
|
||||
partition: {
|
||||
type: 'storageKey',
|
||||
userContext: this._browserContextId
|
||||
}
|
||||
});
|
||||
}
|
||||
async doGrantPermissions(origin, permissions) {}
|
||||
async doClearPermissions() {}
|
||||
async setGeolocation(geolocation) {}
|
||||
async setExtraHTTPHeaders(headers) {}
|
||||
async setUserAgent(userAgent) {}
|
||||
async setOffline(offline) {}
|
||||
async doSetHTTPCredentials(httpCredentials) {
|
||||
this._options.httpCredentials = httpCredentials;
|
||||
for (const page of this.pages()) await page._delegate.updateHttpCredentials();
|
||||
}
|
||||
async doAddInitScript(initScript) {
|
||||
await Promise.all(this.pages().map(page => page._delegate.addInitScript(initScript)));
|
||||
}
|
||||
async doRemoveNonInternalInitScripts() {}
|
||||
async doUpdateRequestInterception() {}
|
||||
onClosePersistent() {}
|
||||
async clearCache() {}
|
||||
async doClose(reason) {
|
||||
if (!this._browserContextId) {
|
||||
// Closing persistent context should close the browser.
|
||||
await this._browser.close({
|
||||
reason
|
||||
});
|
||||
return;
|
||||
}
|
||||
await this._browser._browserSession.send('browser.removeUserContext', {
|
||||
userContext: this._browserContextId
|
||||
});
|
||||
this._browser._contexts.delete(this._browserContextId);
|
||||
}
|
||||
async cancelDownload(uuid) {}
|
||||
}
|
||||
exports.BidiBrowserContext = BidiBrowserContext;
|
||||
function fromBidiSameSite(sameSite) {
|
||||
switch (sameSite) {
|
||||
case 'strict':
|
||||
return 'Strict';
|
||||
case 'lax':
|
||||
return 'Lax';
|
||||
case 'none':
|
||||
return 'None';
|
||||
}
|
||||
return 'None';
|
||||
}
|
||||
function toBidiSameSite(sameSite) {
|
||||
switch (sameSite) {
|
||||
case 'Strict':
|
||||
return bidi.Network.SameSite.Strict;
|
||||
case 'Lax':
|
||||
return bidi.Network.SameSite.Lax;
|
||||
case 'None':
|
||||
return bidi.Network.SameSite.None;
|
||||
}
|
||||
return bidi.Network.SameSite.None;
|
||||
}
|
||||
let Network = exports.Network = void 0;
|
||||
(function (_Network) {
|
||||
let SameSite = /*#__PURE__*/function (SameSite) {
|
||||
SameSite["Strict"] = "strict";
|
||||
SameSite["Lax"] = "lax";
|
||||
SameSite["None"] = "none";
|
||||
return SameSite;
|
||||
}({});
|
||||
_Network.SameSite = SameSite;
|
||||
})(Network || (exports.Network = Network = {}));
|
||||
125
node_modules/playwright-core/lib/server/bidi/bidiChromium.js
generated
vendored
Normal file
125
node_modules/playwright-core/lib/server/bidi/bidiChromium.js
generated
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.BidiChromium = void 0;
|
||||
var _os = _interopRequireDefault(require("os"));
|
||||
var _utils = require("../../utils");
|
||||
var _ascii = require("../utils/ascii");
|
||||
var _browserType = require("../browserType");
|
||||
var _bidiBrowser = require("./bidiBrowser");
|
||||
var _bidiConnection = require("./bidiConnection");
|
||||
var _chromiumSwitches = require("../chromium/chromiumSwitches");
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class BidiChromium extends _browserType.BrowserType {
|
||||
constructor(parent) {
|
||||
super(parent, 'bidi');
|
||||
this._useBidi = true;
|
||||
}
|
||||
async connectToTransport(transport, options) {
|
||||
// Chrome doesn't support Bidi, we create Bidi over CDP which is used by Chrome driver.
|
||||
// bidiOverCdp depends on chromium-bidi which we only have in devDependencies, so
|
||||
// we load bidiOverCdp dynamically.
|
||||
const bidiTransport = await require('./bidiOverCdp').connectBidiOverCdp(transport);
|
||||
transport[kBidiOverCdpWrapper] = bidiTransport;
|
||||
return _bidiBrowser.BidiBrowser.connect(this.attribution.playwright, bidiTransport, options);
|
||||
}
|
||||
doRewriteStartupLog(error) {
|
||||
if (!error.logs) return error;
|
||||
if (error.logs.includes('Missing X server')) error.logs = '\n' + (0, _ascii.wrapInASCIIBox)(_browserType.kNoXServerRunningError, 1);
|
||||
// These error messages are taken from Chromium source code as of July, 2020:
|
||||
// https://github.com/chromium/chromium/blob/70565f67e79f79e17663ad1337dc6e63ee207ce9/content/browser/zygote_host/zygote_host_impl_linux.cc
|
||||
if (!error.logs.includes('crbug.com/357670') && !error.logs.includes('No usable sandbox!') && !error.logs.includes('crbug.com/638180')) return error;
|
||||
error.logs = [`Chromium sandboxing failed!`, `================================`, `To avoid the sandboxing issue, do either of the following:`, ` - (preferred): Configure your environment to support sandboxing`, ` - (alternative): Launch Chromium without sandbox using 'chromiumSandbox: false' option`, `================================`, ``].join('\n');
|
||||
return error;
|
||||
}
|
||||
amendEnvironment(env, userDataDir, executable, browserArguments) {
|
||||
return env;
|
||||
}
|
||||
attemptToGracefullyCloseBrowser(transport) {
|
||||
const bidiTransport = transport[kBidiOverCdpWrapper];
|
||||
if (bidiTransport) transport = bidiTransport;
|
||||
transport.send({
|
||||
method: 'browser.close',
|
||||
params: {},
|
||||
id: _bidiConnection.kBrowserCloseMessageId
|
||||
});
|
||||
}
|
||||
defaultArgs(options, isPersistent, userDataDir) {
|
||||
const chromeArguments = this._innerDefaultArgs(options);
|
||||
chromeArguments.push(`--user-data-dir=${userDataDir}`);
|
||||
chromeArguments.push('--remote-debugging-port=0');
|
||||
if (isPersistent) chromeArguments.push('about:blank');else chromeArguments.push('--no-startup-window');
|
||||
return chromeArguments;
|
||||
}
|
||||
readyState(options) {
|
||||
(0, _utils.assert)(options.useWebSocket);
|
||||
return new ChromiumReadyState();
|
||||
}
|
||||
_innerDefaultArgs(options) {
|
||||
const {
|
||||
args = []
|
||||
} = options;
|
||||
const userDataDirArg = args.find(arg => arg.startsWith('--user-data-dir'));
|
||||
if (userDataDirArg) throw this._createUserDataDirArgMisuseError('--user-data-dir');
|
||||
if (args.find(arg => arg.startsWith('--remote-debugging-pipe'))) throw new Error('Playwright manages remote debugging connection itself.');
|
||||
if (args.find(arg => !arg.startsWith('-'))) throw new Error('Arguments can not specify page to be opened');
|
||||
const chromeArguments = [..._chromiumSwitches.chromiumSwitches];
|
||||
if (_os.default.platform() === 'darwin') {
|
||||
// See https://github.com/microsoft/playwright/issues/7362
|
||||
chromeArguments.push('--enable-use-zoom-for-dsf=false');
|
||||
// See https://bugs.chromium.org/p/chromium/issues/detail?id=1407025.
|
||||
if (options.headless) chromeArguments.push('--use-angle');
|
||||
}
|
||||
if (options.devtools) chromeArguments.push('--auto-open-devtools-for-tabs');
|
||||
if (options.headless) {
|
||||
chromeArguments.push('--headless');
|
||||
chromeArguments.push('--hide-scrollbars', '--mute-audio', '--blink-settings=primaryHoverType=2,availableHoverTypes=2,primaryPointerType=4,availablePointerTypes=4');
|
||||
}
|
||||
if (options.chromiumSandbox !== true) chromeArguments.push('--no-sandbox');
|
||||
const proxy = options.proxyOverride || options.proxy;
|
||||
if (proxy) {
|
||||
const proxyURL = new URL(proxy.server);
|
||||
const isSocks = proxyURL.protocol === 'socks5:';
|
||||
// https://www.chromium.org/developers/design-documents/network-settings
|
||||
if (isSocks && !this.attribution.playwright.options.socksProxyPort) {
|
||||
// https://www.chromium.org/developers/design-documents/network-stack/socks-proxy
|
||||
chromeArguments.push(`--host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE ${proxyURL.hostname}"`);
|
||||
}
|
||||
chromeArguments.push(`--proxy-server=${proxy.server}`);
|
||||
const proxyBypassRules = [];
|
||||
// https://source.chromium.org/chromium/chromium/src/+/master:net/docs/proxy.md;l=548;drc=71698e610121078e0d1a811054dcf9fd89b49578
|
||||
if (this.attribution.playwright.options.socksProxyPort) proxyBypassRules.push('<-loopback>');
|
||||
if (proxy.bypass) proxyBypassRules.push(...proxy.bypass.split(',').map(t => t.trim()).map(t => t.startsWith('.') ? '*' + t : t));
|
||||
if (!process.env.PLAYWRIGHT_DISABLE_FORCED_CHROMIUM_PROXIED_LOOPBACK && !proxyBypassRules.includes('<-loopback>')) proxyBypassRules.push('<-loopback>');
|
||||
if (proxyBypassRules.length > 0) chromeArguments.push(`--proxy-bypass-list=${proxyBypassRules.join(';')}`);
|
||||
}
|
||||
chromeArguments.push(...args);
|
||||
return chromeArguments;
|
||||
}
|
||||
}
|
||||
exports.BidiChromium = BidiChromium;
|
||||
class ChromiumReadyState extends _browserType.BrowserReadyState {
|
||||
onBrowserOutput(message) {
|
||||
const match = message.match(/DevTools listening on (.*)/);
|
||||
if (match) this._wsEndpoint.resolve(match[1]);
|
||||
}
|
||||
}
|
||||
const kBidiOverCdpWrapper = Symbol('kBidiConnectionWrapper');
|
||||
204
node_modules/playwright-core/lib/server/bidi/bidiConnection.js
generated
vendored
Normal file
204
node_modules/playwright-core/lib/server/bidi/bidiConnection.js
generated
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.kBrowserCloseMessageId = exports.BidiSession = exports.BidiConnection = void 0;
|
||||
var _events = require("events");
|
||||
var _debugLogger = require("../utils/debugLogger");
|
||||
var _helper = require("../helper");
|
||||
var _protocolError = require("../protocolError");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// BidiPlaywright uses this special id to issue Browser.close command which we
|
||||
// should ignore.
|
||||
const kBrowserCloseMessageId = exports.kBrowserCloseMessageId = 0;
|
||||
class BidiConnection {
|
||||
constructor(transport, onDisconnect, protocolLogger, browserLogsCollector) {
|
||||
this._transport = void 0;
|
||||
this._onDisconnect = void 0;
|
||||
this._protocolLogger = void 0;
|
||||
this._browserLogsCollector = void 0;
|
||||
this._browserDisconnectedLogs = void 0;
|
||||
this._lastId = 0;
|
||||
this._closed = false;
|
||||
this.browserSession = void 0;
|
||||
this._browsingContextToSession = new Map();
|
||||
this._transport = transport;
|
||||
this._onDisconnect = onDisconnect;
|
||||
this._protocolLogger = protocolLogger;
|
||||
this._browserLogsCollector = browserLogsCollector;
|
||||
this.browserSession = new BidiSession(this, '', message => {
|
||||
this.rawSend(message);
|
||||
});
|
||||
this._transport.onmessage = this._dispatchMessage.bind(this);
|
||||
// onclose should be set last, since it can be immediately called.
|
||||
this._transport.onclose = this._onClose.bind(this);
|
||||
}
|
||||
nextMessageId() {
|
||||
return ++this._lastId;
|
||||
}
|
||||
rawSend(message) {
|
||||
this._protocolLogger('send', message);
|
||||
this._transport.send(message);
|
||||
}
|
||||
_dispatchMessage(message) {
|
||||
this._protocolLogger('receive', message);
|
||||
const object = message;
|
||||
// Bidi messages do not have a common session identifier, so we
|
||||
// route them based on BrowsingContext.
|
||||
if (object.type === 'event') {
|
||||
var _object$params$source;
|
||||
// Route page events to the right session.
|
||||
let context;
|
||||
if ('context' in object.params) context = object.params.context;else if (object.method === 'log.entryAdded' || object.method === 'script.message') context = (_object$params$source = object.params.source) === null || _object$params$source === void 0 ? void 0 : _object$params$source.context;
|
||||
if (context) {
|
||||
const session = this._browsingContextToSession.get(context);
|
||||
if (session) {
|
||||
session.dispatchMessage(message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (message.id) {
|
||||
// Find caller session.
|
||||
for (const session of this._browsingContextToSession.values()) {
|
||||
if (session.hasCallback(message.id)) {
|
||||
session.dispatchMessage(message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.browserSession.dispatchMessage(message);
|
||||
}
|
||||
_onClose(reason) {
|
||||
this._closed = true;
|
||||
this._transport.onmessage = undefined;
|
||||
this._transport.onclose = undefined;
|
||||
this._browserDisconnectedLogs = _helper.helper.formatBrowserLogs(this._browserLogsCollector.recentLogs(), reason);
|
||||
this.browserSession.dispose();
|
||||
this._onDisconnect();
|
||||
}
|
||||
isClosed() {
|
||||
return this._closed;
|
||||
}
|
||||
close() {
|
||||
if (!this._closed) this._transport.close();
|
||||
}
|
||||
createMainFrameBrowsingContextSession(bowsingContextId) {
|
||||
const result = new BidiSession(this, bowsingContextId, message => this.rawSend(message));
|
||||
this._browsingContextToSession.set(bowsingContextId, result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
exports.BidiConnection = BidiConnection;
|
||||
class BidiSession extends _events.EventEmitter {
|
||||
constructor(connection, sessionId, rawSend) {
|
||||
super();
|
||||
this.connection = void 0;
|
||||
this.sessionId = void 0;
|
||||
this._disposed = false;
|
||||
this._rawSend = void 0;
|
||||
this._callbacks = new Map();
|
||||
this._crashed = false;
|
||||
this._browsingContexts = new Set();
|
||||
this.on = void 0;
|
||||
this.addListener = void 0;
|
||||
this.off = void 0;
|
||||
this.removeListener = void 0;
|
||||
this.once = void 0;
|
||||
this.setMaxListeners(0);
|
||||
this.connection = connection;
|
||||
this.sessionId = sessionId;
|
||||
this._rawSend = rawSend;
|
||||
this.on = super.on;
|
||||
this.off = super.removeListener;
|
||||
this.addListener = super.addListener;
|
||||
this.removeListener = super.removeListener;
|
||||
this.once = super.once;
|
||||
}
|
||||
addFrameBrowsingContext(context) {
|
||||
this._browsingContexts.add(context);
|
||||
this.connection._browsingContextToSession.set(context, this);
|
||||
}
|
||||
removeFrameBrowsingContext(context) {
|
||||
this._browsingContexts.delete(context);
|
||||
this.connection._browsingContextToSession.delete(context);
|
||||
}
|
||||
async send(method, params) {
|
||||
if (this._crashed || this._disposed || this.connection._browserDisconnectedLogs) throw new _protocolError.ProtocolError(this._crashed ? 'crashed' : 'closed', undefined, this.connection._browserDisconnectedLogs);
|
||||
const id = this.connection.nextMessageId();
|
||||
const messageObj = {
|
||||
id,
|
||||
method,
|
||||
params
|
||||
};
|
||||
this._rawSend(messageObj);
|
||||
return new Promise((resolve, reject) => {
|
||||
this._callbacks.set(id, {
|
||||
resolve,
|
||||
reject,
|
||||
error: new _protocolError.ProtocolError('error', method)
|
||||
});
|
||||
});
|
||||
}
|
||||
sendMayFail(method, params) {
|
||||
return this.send(method, params).catch(error => _debugLogger.debugLogger.log('error', error));
|
||||
}
|
||||
markAsCrashed() {
|
||||
this._crashed = true;
|
||||
}
|
||||
isDisposed() {
|
||||
return this._disposed;
|
||||
}
|
||||
dispose() {
|
||||
this._disposed = true;
|
||||
this.connection._browsingContextToSession.delete(this.sessionId);
|
||||
for (const context of this._browsingContexts) this.connection._browsingContextToSession.delete(context);
|
||||
this._browsingContexts.clear();
|
||||
for (const callback of this._callbacks.values()) {
|
||||
callback.error.type = this._crashed ? 'crashed' : 'closed';
|
||||
callback.error.logs = this.connection._browserDisconnectedLogs;
|
||||
callback.reject(callback.error);
|
||||
}
|
||||
this._callbacks.clear();
|
||||
}
|
||||
hasCallback(id) {
|
||||
return this._callbacks.has(id);
|
||||
}
|
||||
dispatchMessage(message) {
|
||||
const object = message;
|
||||
if (object.id === kBrowserCloseMessageId) return;
|
||||
if (object.id && this._callbacks.has(object.id)) {
|
||||
const callback = this._callbacks.get(object.id);
|
||||
this._callbacks.delete(object.id);
|
||||
if (object.type === 'error') {
|
||||
callback.error.setMessage(object.error + '\nMessage: ' + object.message);
|
||||
callback.reject(callback.error);
|
||||
} else if (object.type === 'success') {
|
||||
callback.resolve(object.result);
|
||||
} else {
|
||||
callback.error.setMessage('Internal error, unexpected response type: ' + JSON.stringify(object));
|
||||
callback.reject(callback.error);
|
||||
}
|
||||
} else if (object.id) {
|
||||
// Response might come after session has been disposed and rejected all callbacks.
|
||||
} else {
|
||||
Promise.resolve().then(() => this.emit(object.method, object.params));
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.BidiSession = BidiSession;
|
||||
205
node_modules/playwright-core/lib/server/bidi/bidiExecutionContext.js
generated
vendored
Normal file
205
node_modules/playwright-core/lib/server/bidi/bidiExecutionContext.js
generated
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.BidiExecutionContext = void 0;
|
||||
exports.createHandle = createHandle;
|
||||
var _utils = require("../../utils");
|
||||
var _utilityScriptSerializers = require("../isomorphic/utilityScriptSerializers");
|
||||
var js = _interopRequireWildcard(require("../javascript"));
|
||||
var dom = _interopRequireWildcard(require("../dom"));
|
||||
var _bidiDeserializer = require("./third_party/bidiDeserializer");
|
||||
var bidi = _interopRequireWildcard(require("./third_party/bidiProtocol"));
|
||||
var _bidiSerializer = require("./third_party/bidiSerializer");
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class BidiExecutionContext {
|
||||
constructor(session, realmInfo) {
|
||||
this._session = void 0;
|
||||
this._target = void 0;
|
||||
this._session = session;
|
||||
if (realmInfo.type === 'window') {
|
||||
// Simple realm does not seem to work for Window contexts.
|
||||
this._target = {
|
||||
context: realmInfo.context,
|
||||
sandbox: realmInfo.sandbox
|
||||
};
|
||||
} else {
|
||||
this._target = {
|
||||
realm: realmInfo.realm
|
||||
};
|
||||
}
|
||||
}
|
||||
async rawEvaluateJSON(expression) {
|
||||
const response = await this._session.send('script.evaluate', {
|
||||
expression,
|
||||
target: this._target,
|
||||
serializationOptions: {
|
||||
maxObjectDepth: 10,
|
||||
maxDomDepth: 10
|
||||
},
|
||||
awaitPromise: true,
|
||||
userActivation: true
|
||||
});
|
||||
if (response.type === 'success') return _bidiDeserializer.BidiDeserializer.deserialize(response.result);
|
||||
if (response.type === 'exception') throw new js.JavaScriptErrorInEvaluate(response.exceptionDetails.text + '\nFull val: ' + JSON.stringify(response.exceptionDetails));
|
||||
throw new js.JavaScriptErrorInEvaluate('Unexpected response type: ' + JSON.stringify(response));
|
||||
}
|
||||
async rawEvaluateHandle(context, expression) {
|
||||
const response = await this._session.send('script.evaluate', {
|
||||
expression,
|
||||
target: this._target,
|
||||
resultOwnership: bidi.Script.ResultOwnership.Root,
|
||||
// Necessary for the handle to be returned.
|
||||
serializationOptions: {
|
||||
maxObjectDepth: 0,
|
||||
maxDomDepth: 0
|
||||
},
|
||||
awaitPromise: true,
|
||||
userActivation: true
|
||||
});
|
||||
if (response.type === 'success') {
|
||||
if ('handle' in response.result) return createHandle(context, response.result);
|
||||
throw new js.JavaScriptErrorInEvaluate('Cannot get handle: ' + JSON.stringify(response.result));
|
||||
}
|
||||
if (response.type === 'exception') throw new js.JavaScriptErrorInEvaluate(response.exceptionDetails.text + '\nFull val: ' + JSON.stringify(response.exceptionDetails));
|
||||
throw new js.JavaScriptErrorInEvaluate('Unexpected response type: ' + JSON.stringify(response));
|
||||
}
|
||||
async evaluateWithArguments(functionDeclaration, returnByValue, utilityScript, values, handles) {
|
||||
const response = await this._session.send('script.callFunction', {
|
||||
functionDeclaration,
|
||||
target: this._target,
|
||||
arguments: [{
|
||||
handle: utilityScript._objectId
|
||||
}, ...values.map(_bidiSerializer.BidiSerializer.serialize), ...handles.map(handle => ({
|
||||
handle: handle._objectId
|
||||
}))],
|
||||
resultOwnership: returnByValue ? undefined : bidi.Script.ResultOwnership.Root,
|
||||
// Necessary for the handle to be returned.
|
||||
serializationOptions: returnByValue ? {} : {
|
||||
maxObjectDepth: 0,
|
||||
maxDomDepth: 0
|
||||
},
|
||||
awaitPromise: true,
|
||||
userActivation: true
|
||||
});
|
||||
if (response.type === 'exception') throw new js.JavaScriptErrorInEvaluate(response.exceptionDetails.text + '\nFull val: ' + JSON.stringify(response.exceptionDetails));
|
||||
if (response.type === 'success') {
|
||||
if (returnByValue) return (0, _utilityScriptSerializers.parseEvaluationResultValue)(_bidiDeserializer.BidiDeserializer.deserialize(response.result));
|
||||
return createHandle(utilityScript._context, response.result);
|
||||
}
|
||||
throw new js.JavaScriptErrorInEvaluate('Unexpected response type: ' + JSON.stringify(response));
|
||||
}
|
||||
async getProperties(handle) {
|
||||
const names = await handle.evaluate(object => {
|
||||
const names = [];
|
||||
const descriptors = Object.getOwnPropertyDescriptors(object);
|
||||
for (const name in descriptors) {
|
||||
var _descriptors$name;
|
||||
if ((_descriptors$name = descriptors[name]) !== null && _descriptors$name !== void 0 && _descriptors$name.enumerable) names.push(name);
|
||||
}
|
||||
return names;
|
||||
});
|
||||
const values = await Promise.all(names.map(name => handle.evaluateHandle((object, name) => object[name], name)));
|
||||
const map = new Map();
|
||||
for (let i = 0; i < names.length; i++) map.set(names[i], values[i]);
|
||||
return map;
|
||||
}
|
||||
async releaseHandle(handle) {
|
||||
if (!handle._objectId) return;
|
||||
await this._session.send('script.disown', {
|
||||
target: this._target,
|
||||
handles: [handle._objectId]
|
||||
});
|
||||
}
|
||||
async nodeIdForElementHandle(handle) {
|
||||
const shared = await this._remoteValueForReference({
|
||||
handle: handle._objectId
|
||||
});
|
||||
// TODO: store sharedId in the handle.
|
||||
if (!('sharedId' in shared)) throw new Error('Element is not a node');
|
||||
return {
|
||||
sharedId: shared.sharedId
|
||||
};
|
||||
}
|
||||
async remoteObjectForNodeId(context, nodeId) {
|
||||
const result = await this._remoteValueForReference(nodeId, true);
|
||||
if (!('handle' in result)) throw new Error('Can\'t get remote object for nodeId');
|
||||
return createHandle(context, result);
|
||||
}
|
||||
async contentFrameIdForFrame(handle) {
|
||||
const contentWindow = await this._rawCallFunction('e => e.contentWindow', {
|
||||
handle: handle._objectId
|
||||
});
|
||||
if ((contentWindow === null || contentWindow === void 0 ? void 0 : contentWindow.type) === 'window') return contentWindow.value.context;
|
||||
return null;
|
||||
}
|
||||
async frameIdForWindowHandle(handle) {
|
||||
if (!handle._objectId) throw new Error('JSHandle is not a DOM node handle');
|
||||
const contentWindow = await this._remoteValueForReference({
|
||||
handle: handle._objectId
|
||||
});
|
||||
if (contentWindow.type === 'window') return contentWindow.value.context;
|
||||
return null;
|
||||
}
|
||||
async _remoteValueForReference(reference, createHandle) {
|
||||
return await this._rawCallFunction('e => e', reference, createHandle);
|
||||
}
|
||||
async _rawCallFunction(functionDeclaration, arg, createHandle) {
|
||||
const response = await this._session.send('script.callFunction', {
|
||||
functionDeclaration,
|
||||
target: this._target,
|
||||
arguments: [arg],
|
||||
// "Root" is necessary for the handle to be returned.
|
||||
resultOwnership: createHandle ? bidi.Script.ResultOwnership.Root : bidi.Script.ResultOwnership.None,
|
||||
serializationOptions: {
|
||||
maxObjectDepth: 0,
|
||||
maxDomDepth: 0
|
||||
},
|
||||
awaitPromise: true,
|
||||
userActivation: true
|
||||
});
|
||||
if (response.type === 'exception') throw new js.JavaScriptErrorInEvaluate(response.exceptionDetails.text + '\nFull val: ' + JSON.stringify(response.exceptionDetails));
|
||||
if (response.type === 'success') return response.result;
|
||||
throw new js.JavaScriptErrorInEvaluate('Unexpected response type: ' + JSON.stringify(response));
|
||||
}
|
||||
}
|
||||
exports.BidiExecutionContext = BidiExecutionContext;
|
||||
function renderPreview(remoteObject) {
|
||||
if (remoteObject.type === 'undefined') return 'undefined';
|
||||
if (remoteObject.type === 'null') return 'null';
|
||||
if ('value' in remoteObject) return String(remoteObject.value);
|
||||
return `<${remoteObject.type}>`;
|
||||
}
|
||||
function remoteObjectValue(remoteObject) {
|
||||
if (remoteObject.type === 'undefined') return undefined;
|
||||
if (remoteObject.type === 'null') return null;
|
||||
if (remoteObject.type === 'number' && typeof remoteObject.value === 'string') return js.parseUnserializableValue(remoteObject.value);
|
||||
if ('value' in remoteObject) return remoteObject.value;
|
||||
return undefined;
|
||||
}
|
||||
function createHandle(context, remoteObject) {
|
||||
if (remoteObject.type === 'node') {
|
||||
(0, _utils.assert)(context instanceof dom.FrameExecutionContext);
|
||||
return new dom.ElementHandle(context, remoteObject.handle);
|
||||
}
|
||||
const objectId = 'handle' in remoteObject ? remoteObject.handle : undefined;
|
||||
return new js.JSHandle(context, remoteObject.type, renderPreview(remoteObject), objectId, remoteObjectValue(remoteObject));
|
||||
}
|
||||
105
node_modules/playwright-core/lib/server/bidi/bidiFirefox.js
generated
vendored
Normal file
105
node_modules/playwright-core/lib/server/bidi/bidiFirefox.js
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.BidiFirefox = void 0;
|
||||
var _os = _interopRequireDefault(require("os"));
|
||||
var _path = _interopRequireDefault(require("path"));
|
||||
var _utils = require("../../utils");
|
||||
var _ascii = require("../utils/ascii");
|
||||
var _browserType = require("../browserType");
|
||||
var _bidiBrowser = require("./bidiBrowser");
|
||||
var _bidiConnection = require("./bidiConnection");
|
||||
var _firefoxPrefs = require("./third_party/firefoxPrefs");
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class BidiFirefox extends _browserType.BrowserType {
|
||||
constructor(parent) {
|
||||
super(parent, 'bidi');
|
||||
this._useBidi = true;
|
||||
}
|
||||
async connectToTransport(transport, options) {
|
||||
return _bidiBrowser.BidiBrowser.connect(this.attribution.playwright, transport, options);
|
||||
}
|
||||
doRewriteStartupLog(error) {
|
||||
if (!error.logs) return error;
|
||||
// https://github.com/microsoft/playwright/issues/6500
|
||||
if (error.logs.includes(`as root in a regular user's session is not supported.`)) error.logs = '\n' + (0, _ascii.wrapInASCIIBox)(`Firefox is unable to launch if the $HOME folder isn't owned by the current user.\nWorkaround: Set the HOME=/root environment variable${process.env.GITHUB_ACTION ? ' in your GitHub Actions workflow file' : ''} when running Playwright.`, 1);
|
||||
if (error.logs.includes('no DISPLAY environment variable specified')) error.logs = '\n' + (0, _ascii.wrapInASCIIBox)(_browserType.kNoXServerRunningError, 1);
|
||||
return error;
|
||||
}
|
||||
amendEnvironment(env, userDataDir, executable, browserArguments) {
|
||||
if (!_path.default.isAbsolute(_os.default.homedir())) throw new Error(`Cannot launch Firefox with relative home directory. Did you set ${_os.default.platform() === 'win32' ? 'USERPROFILE' : 'HOME'} to a relative path?`);
|
||||
env = {
|
||||
...env,
|
||||
'MOZ_CRASHREPORTER': '1',
|
||||
'MOZ_CRASHREPORTER_NO_REPORT': '1',
|
||||
'MOZ_CRASHREPORTER_SHUTDOWN': '1'
|
||||
};
|
||||
if (_os.default.platform() === 'linux') {
|
||||
// Always remove SNAP_NAME and SNAP_INSTANCE_NAME env variables since they
|
||||
// confuse Firefox: in our case, builds never come from SNAP.
|
||||
// See https://github.com/microsoft/playwright/issues/20555
|
||||
return {
|
||||
...env,
|
||||
SNAP_NAME: undefined,
|
||||
SNAP_INSTANCE_NAME: undefined
|
||||
};
|
||||
}
|
||||
return env;
|
||||
}
|
||||
attemptToGracefullyCloseBrowser(transport) {
|
||||
transport.send({
|
||||
method: 'browser.close',
|
||||
params: {},
|
||||
id: _bidiConnection.kBrowserCloseMessageId
|
||||
});
|
||||
}
|
||||
async prepareUserDataDir(options, userDataDir) {
|
||||
await (0, _firefoxPrefs.createProfile)({
|
||||
path: userDataDir,
|
||||
preferences: options.firefoxUserPrefs || {}
|
||||
});
|
||||
}
|
||||
defaultArgs(options, isPersistent, userDataDir) {
|
||||
const {
|
||||
args = [],
|
||||
headless
|
||||
} = options;
|
||||
const userDataDirArg = args.find(arg => arg.startsWith('-profile') || arg.startsWith('--profile'));
|
||||
if (userDataDirArg) throw this._createUserDataDirArgMisuseError('--profile');
|
||||
const firefoxArguments = ['--remote-debugging-port=0'];
|
||||
if (headless) firefoxArguments.push('--headless');else firefoxArguments.push('--foreground');
|
||||
firefoxArguments.push(`--profile`, userDataDir);
|
||||
firefoxArguments.push(...args);
|
||||
return firefoxArguments;
|
||||
}
|
||||
readyState(options) {
|
||||
(0, _utils.assert)(options.useWebSocket);
|
||||
return new FirefoxReadyState();
|
||||
}
|
||||
}
|
||||
exports.BidiFirefox = BidiFirefox;
|
||||
class FirefoxReadyState extends _browserType.BrowserReadyState {
|
||||
onBrowserOutput(message) {
|
||||
// Bidi WebSocket in Firefox.
|
||||
const match = message.match(/WebDriver BiDi listening on (ws:\/\/.*)$/);
|
||||
if (match) this._wsEndpoint.resolve(match[1] + '/session');
|
||||
}
|
||||
}
|
||||
157
node_modules/playwright-core/lib/server/bidi/bidiInput.js
generated
vendored
Normal file
157
node_modules/playwright-core/lib/server/bidi/bidiInput.js
generated
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.RawTouchscreenImpl = exports.RawMouseImpl = exports.RawKeyboardImpl = void 0;
|
||||
var _input = require("../input");
|
||||
var _bidiKeyboard = require("./third_party/bidiKeyboard");
|
||||
var bidi = _interopRequireWildcard(require("./third_party/bidiProtocol"));
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class RawKeyboardImpl {
|
||||
constructor(session) {
|
||||
this._session = void 0;
|
||||
this._session = session;
|
||||
}
|
||||
setSession(session) {
|
||||
this._session = session;
|
||||
}
|
||||
async keydown(modifiers, keyName, description, autoRepeat) {
|
||||
keyName = (0, _input.resolveSmartModifierString)(keyName);
|
||||
const actions = [];
|
||||
actions.push({
|
||||
type: 'keyDown',
|
||||
value: (0, _bidiKeyboard.getBidiKeyValue)(keyName)
|
||||
});
|
||||
await this._performActions(actions);
|
||||
}
|
||||
async keyup(modifiers, keyName, description) {
|
||||
keyName = (0, _input.resolveSmartModifierString)(keyName);
|
||||
const actions = [];
|
||||
actions.push({
|
||||
type: 'keyUp',
|
||||
value: (0, _bidiKeyboard.getBidiKeyValue)(keyName)
|
||||
});
|
||||
await this._performActions(actions);
|
||||
}
|
||||
async sendText(text) {
|
||||
const actions = [];
|
||||
for (const char of text) {
|
||||
const value = (0, _bidiKeyboard.getBidiKeyValue)(char);
|
||||
actions.push({
|
||||
type: 'keyDown',
|
||||
value
|
||||
});
|
||||
actions.push({
|
||||
type: 'keyUp',
|
||||
value
|
||||
});
|
||||
}
|
||||
await this._performActions(actions);
|
||||
}
|
||||
async _performActions(actions) {
|
||||
await this._session.send('input.performActions', {
|
||||
context: this._session.sessionId,
|
||||
actions: [{
|
||||
type: 'key',
|
||||
id: 'pw_keyboard',
|
||||
actions
|
||||
}]
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.RawKeyboardImpl = RawKeyboardImpl;
|
||||
class RawMouseImpl {
|
||||
constructor(session) {
|
||||
this._session = void 0;
|
||||
this._session = session;
|
||||
}
|
||||
async move(x, y, button, buttons, modifiers, forClick) {
|
||||
await this._performActions([{
|
||||
type: 'pointerMove',
|
||||
x,
|
||||
y
|
||||
}]);
|
||||
}
|
||||
async down(x, y, button, buttons, modifiers, clickCount) {
|
||||
await this._performActions([{
|
||||
type: 'pointerDown',
|
||||
button: toBidiButton(button)
|
||||
}]);
|
||||
}
|
||||
async up(x, y, button, buttons, modifiers, clickCount) {
|
||||
await this._performActions([{
|
||||
type: 'pointerUp',
|
||||
button: toBidiButton(button)
|
||||
}]);
|
||||
}
|
||||
async wheel(x, y, buttons, modifiers, deltaX, deltaY) {
|
||||
// Bidi throws when x/y are not integers.
|
||||
x = Math.floor(x);
|
||||
y = Math.floor(y);
|
||||
await this._session.send('input.performActions', {
|
||||
context: this._session.sessionId,
|
||||
actions: [{
|
||||
type: 'wheel',
|
||||
id: 'pw_mouse_wheel',
|
||||
actions: [{
|
||||
type: 'scroll',
|
||||
x,
|
||||
y,
|
||||
deltaX,
|
||||
deltaY
|
||||
}]
|
||||
}]
|
||||
});
|
||||
}
|
||||
async _performActions(actions) {
|
||||
await this._session.send('input.performActions', {
|
||||
context: this._session.sessionId,
|
||||
actions: [{
|
||||
type: 'pointer',
|
||||
id: 'pw_mouse',
|
||||
parameters: {
|
||||
pointerType: bidi.Input.PointerType.Mouse
|
||||
},
|
||||
actions
|
||||
}]
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.RawMouseImpl = RawMouseImpl;
|
||||
class RawTouchscreenImpl {
|
||||
constructor(session) {
|
||||
this._session = void 0;
|
||||
this._session = session;
|
||||
}
|
||||
async tap(x, y, modifiers) {}
|
||||
}
|
||||
exports.RawTouchscreenImpl = RawTouchscreenImpl;
|
||||
function toBidiButton(button) {
|
||||
switch (button) {
|
||||
case 'left':
|
||||
return 0;
|
||||
case 'right':
|
||||
return 2;
|
||||
case 'middle':
|
||||
return 1;
|
||||
}
|
||||
throw new Error('Unknown button: ' + button);
|
||||
}
|
||||
337
node_modules/playwright-core/lib/server/bidi/bidiNetworkManager.js
generated
vendored
Normal file
337
node_modules/playwright-core/lib/server/bidi/bidiNetworkManager.js
generated
vendored
Normal file
@@ -0,0 +1,337 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.BidiNetworkManager = void 0;
|
||||
exports.bidiBytesValueToString = bidiBytesValueToString;
|
||||
var _eventsHelper = require("../utils/eventsHelper");
|
||||
var _cookieStore = require("../cookieStore");
|
||||
var network = _interopRequireWildcard(require("../network"));
|
||||
var bidi = _interopRequireWildcard(require("./third_party/bidiProtocol"));
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class BidiNetworkManager {
|
||||
constructor(bidiSession, page, onNavigationResponseStarted) {
|
||||
this._session = void 0;
|
||||
this._requests = void 0;
|
||||
this._page = void 0;
|
||||
this._eventListeners = void 0;
|
||||
this._onNavigationResponseStarted = void 0;
|
||||
this._userRequestInterceptionEnabled = false;
|
||||
this._protocolRequestInterceptionEnabled = false;
|
||||
this._credentials = void 0;
|
||||
this._intercepId = void 0;
|
||||
this._session = bidiSession;
|
||||
this._requests = new Map();
|
||||
this._page = page;
|
||||
this._onNavigationResponseStarted = onNavigationResponseStarted;
|
||||
this._eventListeners = [_eventsHelper.eventsHelper.addEventListener(bidiSession, 'network.beforeRequestSent', this._onBeforeRequestSent.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'network.responseStarted', this._onResponseStarted.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'network.responseCompleted', this._onResponseCompleted.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'network.fetchError', this._onFetchError.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'network.authRequired', this._onAuthRequired.bind(this))];
|
||||
}
|
||||
dispose() {
|
||||
_eventsHelper.eventsHelper.removeEventListeners(this._eventListeners);
|
||||
}
|
||||
_onBeforeRequestSent(param) {
|
||||
if (param.request.url.startsWith('data:')) return;
|
||||
const redirectedFrom = param.redirectCount ? this._requests.get(param.request.request) || null : null;
|
||||
const frame = redirectedFrom ? redirectedFrom.request.frame() : param.context ? this._page._frameManager.frame(param.context) : null;
|
||||
if (!frame) return;
|
||||
if (redirectedFrom) this._requests.delete(redirectedFrom._id);
|
||||
let route;
|
||||
if (param.intercepts) {
|
||||
// We do not support intercepting redirects.
|
||||
if (redirectedFrom) {
|
||||
var _redirectedFrom$_orig, _redirectedFrom$_orig2;
|
||||
let params = {};
|
||||
if ((_redirectedFrom$_orig = redirectedFrom._originalRequestRoute) !== null && _redirectedFrom$_orig !== void 0 && _redirectedFrom$_orig._alreadyContinuedHeaders) params = toBidiRequestHeaders((_redirectedFrom$_orig2 = redirectedFrom._originalRequestRoute._alreadyContinuedHeaders) !== null && _redirectedFrom$_orig2 !== void 0 ? _redirectedFrom$_orig2 : []);
|
||||
this._session.sendMayFail('network.continueRequest', {
|
||||
request: param.request.request,
|
||||
...params
|
||||
});
|
||||
} else {
|
||||
route = new BidiRouteImpl(this._session, param.request.request);
|
||||
}
|
||||
}
|
||||
const request = new BidiRequest(frame, redirectedFrom, param, route);
|
||||
this._requests.set(request._id, request);
|
||||
this._page._frameManager.requestStarted(request.request, route);
|
||||
}
|
||||
_onResponseStarted(params) {
|
||||
const request = this._requests.get(params.request.request);
|
||||
if (!request) return;
|
||||
const getResponseBody = async () => {
|
||||
throw new Error(`Response body is not available for requests in Bidi`);
|
||||
};
|
||||
const timings = params.request.timings;
|
||||
const startTime = timings.requestTime;
|
||||
function relativeToStart(time) {
|
||||
if (!time) return -1;
|
||||
return time - startTime;
|
||||
}
|
||||
const timing = {
|
||||
startTime: startTime,
|
||||
requestStart: relativeToStart(timings.requestStart),
|
||||
responseStart: relativeToStart(timings.responseStart),
|
||||
domainLookupStart: relativeToStart(timings.dnsStart),
|
||||
domainLookupEnd: relativeToStart(timings.dnsEnd),
|
||||
connectStart: relativeToStart(timings.connectStart),
|
||||
secureConnectionStart: relativeToStart(timings.tlsStart),
|
||||
connectEnd: relativeToStart(timings.connectEnd)
|
||||
};
|
||||
const response = new network.Response(request.request, params.response.status, params.response.statusText, fromBidiHeaders(params.response.headers), timing, getResponseBody, false);
|
||||
response._serverAddrFinished();
|
||||
response._securityDetailsFinished();
|
||||
// "raw" headers are the same as "provisional" headers in Bidi.
|
||||
response.setRawResponseHeaders(null);
|
||||
response.setResponseHeadersSize(params.response.headersSize);
|
||||
this._page._frameManager.requestReceivedResponse(response);
|
||||
if (params.navigation) this._onNavigationResponseStarted(params);
|
||||
}
|
||||
_onResponseCompleted(params) {
|
||||
const request = this._requests.get(params.request.request);
|
||||
if (!request) return;
|
||||
const response = request.request._existingResponse();
|
||||
// TODO: body size is the encoded size
|
||||
response.setTransferSize(params.response.bodySize);
|
||||
response.setEncodedBodySize(params.response.bodySize);
|
||||
|
||||
// Keep redirected requests in the map for future reference as redirectedFrom.
|
||||
const isRedirected = response.status() >= 300 && response.status() <= 399;
|
||||
const responseEndTime = params.request.timings.responseEnd - response.timing().startTime;
|
||||
if (isRedirected) {
|
||||
response._requestFinished(responseEndTime);
|
||||
} else {
|
||||
this._requests.delete(request._id);
|
||||
response._requestFinished(responseEndTime);
|
||||
}
|
||||
response._setHttpVersion(params.response.protocol);
|
||||
this._page._frameManager.reportRequestFinished(request.request, response);
|
||||
}
|
||||
_onFetchError(params) {
|
||||
const request = this._requests.get(params.request.request);
|
||||
if (!request) return;
|
||||
this._requests.delete(request._id);
|
||||
const response = request.request._existingResponse();
|
||||
if (response) {
|
||||
response.setTransferSize(null);
|
||||
response.setEncodedBodySize(null);
|
||||
response._requestFinished(-1);
|
||||
}
|
||||
request.request._setFailureText(params.errorText);
|
||||
// TODO: support canceled flag
|
||||
this._page._frameManager.requestFailed(request.request, params.errorText === 'NS_BINDING_ABORTED');
|
||||
}
|
||||
_onAuthRequired(params) {
|
||||
var _params$response$auth;
|
||||
const isBasic = (_params$response$auth = params.response.authChallenges) === null || _params$response$auth === void 0 ? void 0 : _params$response$auth.some(challenge => challenge.scheme.startsWith('Basic'));
|
||||
const credentials = this._page._browserContext._options.httpCredentials;
|
||||
if (isBasic && credentials) {
|
||||
this._session.sendMayFail('network.continueWithAuth', {
|
||||
request: params.request.request,
|
||||
action: 'provideCredentials',
|
||||
credentials: {
|
||||
type: 'password',
|
||||
username: credentials.username,
|
||||
password: credentials.password
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this._session.sendMayFail('network.continueWithAuth', {
|
||||
request: params.request.request,
|
||||
action: 'default'
|
||||
});
|
||||
}
|
||||
}
|
||||
async setRequestInterception(value) {
|
||||
this._userRequestInterceptionEnabled = value;
|
||||
await this._updateProtocolRequestInterception();
|
||||
}
|
||||
async setCredentials(credentials) {
|
||||
this._credentials = credentials;
|
||||
await this._updateProtocolRequestInterception();
|
||||
}
|
||||
async _updateProtocolRequestInterception(initial) {
|
||||
const enabled = this._userRequestInterceptionEnabled || !!this._credentials;
|
||||
if (enabled === this._protocolRequestInterceptionEnabled) return;
|
||||
this._protocolRequestInterceptionEnabled = enabled;
|
||||
if (initial && !enabled) return;
|
||||
const cachePromise = this._session.send('network.setCacheBehavior', {
|
||||
cacheBehavior: enabled ? 'bypass' : 'default'
|
||||
});
|
||||
let interceptPromise = Promise.resolve(undefined);
|
||||
if (enabled) {
|
||||
interceptPromise = this._session.send('network.addIntercept', {
|
||||
phases: [bidi.Network.InterceptPhase.AuthRequired, bidi.Network.InterceptPhase.BeforeRequestSent],
|
||||
urlPatterns: [{
|
||||
type: 'pattern'
|
||||
}]
|
||||
// urlPatterns: [{ type: 'string', pattern: '*' }],
|
||||
}).then(r => {
|
||||
this._intercepId = r.intercept;
|
||||
});
|
||||
} else if (this._intercepId) {
|
||||
interceptPromise = this._session.send('network.removeIntercept', {
|
||||
intercept: this._intercepId
|
||||
});
|
||||
this._intercepId = undefined;
|
||||
}
|
||||
await Promise.all([cachePromise, interceptPromise]);
|
||||
}
|
||||
}
|
||||
exports.BidiNetworkManager = BidiNetworkManager;
|
||||
class BidiRequest {
|
||||
constructor(frame, redirectedFrom, payload, route) {
|
||||
var _payload$navigation;
|
||||
this.request = void 0;
|
||||
this._id = void 0;
|
||||
this._redirectedTo = void 0;
|
||||
// Only first request in the chain can be intercepted, so this will
|
||||
// store the first and only Route in the chain (if any).
|
||||
this._originalRequestRoute = void 0;
|
||||
this._id = payload.request.request;
|
||||
if (redirectedFrom) redirectedFrom._redirectedTo = this;
|
||||
// TODO: missing in the spec?
|
||||
const postDataBuffer = null;
|
||||
this.request = new network.Request(frame._page._browserContext, frame, null, redirectedFrom ? redirectedFrom.request : null, (_payload$navigation = payload.navigation) !== null && _payload$navigation !== void 0 ? _payload$navigation : undefined, payload.request.url, 'other', payload.request.method, postDataBuffer, fromBidiHeaders(payload.request.headers));
|
||||
// "raw" headers are the same as "provisional" headers in Bidi.
|
||||
this.request.setRawRequestHeaders(null);
|
||||
this.request._setBodySize(payload.request.bodySize || 0);
|
||||
this._originalRequestRoute = route !== null && route !== void 0 ? route : redirectedFrom === null || redirectedFrom === void 0 ? void 0 : redirectedFrom._originalRequestRoute;
|
||||
route === null || route === void 0 || route._setRequest(this.request);
|
||||
}
|
||||
_finalRequest() {
|
||||
let request = this;
|
||||
while (request._redirectedTo) request = request._redirectedTo;
|
||||
return request;
|
||||
}
|
||||
}
|
||||
class BidiRouteImpl {
|
||||
constructor(session, requestId) {
|
||||
this._requestId = void 0;
|
||||
this._session = void 0;
|
||||
this._request = void 0;
|
||||
this._alreadyContinuedHeaders = void 0;
|
||||
this._session = session;
|
||||
this._requestId = requestId;
|
||||
}
|
||||
_setRequest(request) {
|
||||
this._request = request;
|
||||
}
|
||||
async continue(overrides) {
|
||||
// Firefox does not update content-length header.
|
||||
let headers = overrides.headers || this._request.headers();
|
||||
if (overrides.postData && headers) {
|
||||
headers = headers.map(header => {
|
||||
if (header.name.toLowerCase() === 'content-length') return {
|
||||
name: header.name,
|
||||
value: overrides.postData.byteLength.toString()
|
||||
};
|
||||
return header;
|
||||
});
|
||||
}
|
||||
this._alreadyContinuedHeaders = headers;
|
||||
await this._session.sendMayFail('network.continueRequest', {
|
||||
request: this._requestId,
|
||||
url: overrides.url,
|
||||
method: overrides.method,
|
||||
...toBidiRequestHeaders(this._alreadyContinuedHeaders),
|
||||
body: overrides.postData ? {
|
||||
type: 'base64',
|
||||
value: Buffer.from(overrides.postData).toString('base64')
|
||||
} : undefined
|
||||
});
|
||||
}
|
||||
async fulfill(response) {
|
||||
const base64body = response.isBase64 ? response.body : Buffer.from(response.body).toString('base64');
|
||||
await this._session.sendMayFail('network.provideResponse', {
|
||||
request: this._requestId,
|
||||
statusCode: response.status,
|
||||
reasonPhrase: network.statusText(response.status),
|
||||
...toBidiResponseHeaders(response.headers),
|
||||
body: {
|
||||
type: 'base64',
|
||||
value: base64body
|
||||
}
|
||||
});
|
||||
}
|
||||
async abort(errorCode) {
|
||||
await this._session.sendMayFail('network.failRequest', {
|
||||
request: this._requestId
|
||||
});
|
||||
}
|
||||
}
|
||||
function fromBidiHeaders(bidiHeaders) {
|
||||
const result = [];
|
||||
for (const {
|
||||
name,
|
||||
value
|
||||
} of bidiHeaders) result.push({
|
||||
name,
|
||||
value: bidiBytesValueToString(value)
|
||||
});
|
||||
return result;
|
||||
}
|
||||
function toBidiRequestHeaders(allHeaders) {
|
||||
const bidiHeaders = toBidiHeaders(allHeaders);
|
||||
return {
|
||||
headers: bidiHeaders
|
||||
};
|
||||
}
|
||||
function toBidiResponseHeaders(headers) {
|
||||
const setCookieHeaders = headers.filter(h => h.name.toLowerCase() === 'set-cookie');
|
||||
const otherHeaders = headers.filter(h => h.name.toLowerCase() !== 'set-cookie');
|
||||
const rawCookies = setCookieHeaders.map(h => (0, _cookieStore.parseRawCookie)(h.value));
|
||||
const cookies = rawCookies.filter(Boolean).map(c => {
|
||||
return {
|
||||
...c,
|
||||
value: {
|
||||
type: 'string',
|
||||
value: c.value
|
||||
},
|
||||
sameSite: toBidiSameSite(c.sameSite)
|
||||
};
|
||||
});
|
||||
return {
|
||||
cookies,
|
||||
headers: toBidiHeaders(otherHeaders)
|
||||
};
|
||||
}
|
||||
function toBidiHeaders(headers) {
|
||||
return headers.map(({
|
||||
name,
|
||||
value
|
||||
}) => ({
|
||||
name,
|
||||
value: {
|
||||
type: 'string',
|
||||
value
|
||||
}
|
||||
}));
|
||||
}
|
||||
function bidiBytesValueToString(value) {
|
||||
if (value.type === 'string') return value.value;
|
||||
if (value.type === 'base64') return Buffer.from(value.type, 'base64').toString('binary');
|
||||
return 'unknown value type: ' + value.type;
|
||||
}
|
||||
function toBidiSameSite(sameSite) {
|
||||
if (!sameSite) return undefined;
|
||||
if (sameSite === 'Strict') return bidi.Network.SameSite.Strict;
|
||||
if (sameSite === 'Lax') return bidi.Network.SameSite.Lax;
|
||||
return bidi.Network.SameSite.None;
|
||||
}
|
||||
103
node_modules/playwright-core/lib/server/bidi/bidiOverCdp.js
generated
vendored
Normal file
103
node_modules/playwright-core/lib/server/bidi/bidiOverCdp.js
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.connectBidiOverCdp = connectBidiOverCdp;
|
||||
var bidiMapper = _interopRequireWildcard(require("chromium-bidi/lib/cjs/bidiMapper/BidiMapper"));
|
||||
var bidiCdpConnection = _interopRequireWildcard(require("chromium-bidi/lib/cjs/cdp/CdpConnection"));
|
||||
var _debugLogger = require("../utils/debugLogger");
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const bidiServerLogger = (prefix, ...args) => {
|
||||
_debugLogger.debugLogger.log(prefix, args);
|
||||
};
|
||||
async function connectBidiOverCdp(cdp) {
|
||||
let server = undefined;
|
||||
const bidiTransport = new BidiTransportImpl();
|
||||
const bidiConnection = new BidiConnection(bidiTransport, () => {
|
||||
var _server;
|
||||
return (_server = server) === null || _server === void 0 ? void 0 : _server.close();
|
||||
});
|
||||
const cdpTransportImpl = new CdpTransportImpl(cdp);
|
||||
const cdpConnection = new bidiCdpConnection.MapperCdpConnection(cdpTransportImpl, bidiServerLogger);
|
||||
// Make sure onclose event is propagated.
|
||||
cdp.onclose = () => {
|
||||
var _bidiConnection$onclo;
|
||||
return (_bidiConnection$onclo = bidiConnection.onclose) === null || _bidiConnection$onclo === void 0 ? void 0 : _bidiConnection$onclo.call(bidiConnection);
|
||||
};
|
||||
server = await bidiMapper.BidiServer.createAndStart(bidiTransport, cdpConnection, await cdpConnection.createBrowserSession(), /* selfTargetId= */'', undefined, bidiServerLogger);
|
||||
return bidiConnection;
|
||||
}
|
||||
class BidiTransportImpl {
|
||||
constructor() {
|
||||
this._handler = void 0;
|
||||
this._bidiConnection = void 0;
|
||||
}
|
||||
setOnMessage(handler) {
|
||||
this._handler = handler;
|
||||
}
|
||||
sendMessage(message) {
|
||||
var _this$_bidiConnection, _this$_bidiConnection2;
|
||||
return (_this$_bidiConnection = (_this$_bidiConnection2 = this._bidiConnection).onmessage) === null || _this$_bidiConnection === void 0 ? void 0 : _this$_bidiConnection.call(_this$_bidiConnection2, message);
|
||||
}
|
||||
close() {
|
||||
var _this$_bidiConnection3, _this$_bidiConnection4;
|
||||
(_this$_bidiConnection3 = (_this$_bidiConnection4 = this._bidiConnection).onclose) === null || _this$_bidiConnection3 === void 0 || _this$_bidiConnection3.call(_this$_bidiConnection4);
|
||||
}
|
||||
}
|
||||
class BidiConnection {
|
||||
constructor(bidiTransport, closeCallback) {
|
||||
this._bidiTransport = void 0;
|
||||
this._closeCallback = void 0;
|
||||
this.onmessage = void 0;
|
||||
this.onclose = void 0;
|
||||
this._bidiTransport = bidiTransport;
|
||||
this._bidiTransport._bidiConnection = this;
|
||||
this._closeCallback = closeCallback;
|
||||
}
|
||||
send(s) {
|
||||
var _this$_bidiTransport$, _this$_bidiTransport;
|
||||
(_this$_bidiTransport$ = (_this$_bidiTransport = this._bidiTransport)._handler) === null || _this$_bidiTransport$ === void 0 || _this$_bidiTransport$.call(_this$_bidiTransport, s);
|
||||
}
|
||||
close() {
|
||||
this._closeCallback();
|
||||
}
|
||||
}
|
||||
class CdpTransportImpl {
|
||||
constructor(connection) {
|
||||
this._connection = void 0;
|
||||
this._handler = void 0;
|
||||
this._bidiConnection = void 0;
|
||||
this._connection = connection;
|
||||
this._connection.onmessage = message => {
|
||||
var _this$_handler;
|
||||
(_this$_handler = this._handler) === null || _this$_handler === void 0 || _this$_handler.call(this, JSON.stringify(message));
|
||||
};
|
||||
}
|
||||
setOnMessage(handler) {
|
||||
this._handler = handler;
|
||||
}
|
||||
sendMessage(message) {
|
||||
return this._connection.send(JSON.parse(message));
|
||||
}
|
||||
close() {
|
||||
this._connection.close();
|
||||
}
|
||||
}
|
||||
502
node_modules/playwright-core/lib/server/bidi/bidiPage.js
generated
vendored
Normal file
502
node_modules/playwright-core/lib/server/bidi/bidiPage.js
generated
vendored
Normal file
@@ -0,0 +1,502 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.BidiPage = void 0;
|
||||
var _utils = require("../../utils");
|
||||
var _eventsHelper = require("../utils/eventsHelper");
|
||||
var _browserContext = require("../browserContext");
|
||||
var dialog = _interopRequireWildcard(require("../dialog"));
|
||||
var dom = _interopRequireWildcard(require("../dom"));
|
||||
var _page = require("../page");
|
||||
var _bidiExecutionContext = require("./bidiExecutionContext");
|
||||
var _bidiInput = require("./bidiInput");
|
||||
var _bidiNetworkManager = require("./bidiNetworkManager");
|
||||
var _bidiPdf = require("./bidiPdf");
|
||||
var bidi = _interopRequireWildcard(require("./third_party/bidiProtocol"));
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const UTILITY_WORLD_NAME = '__playwright_utility_world__';
|
||||
const kPlaywrightBindingChannel = 'playwrightChannel';
|
||||
class BidiPage {
|
||||
constructor(browserContext, bidiSession, opener) {
|
||||
this.rawMouse = void 0;
|
||||
this.rawKeyboard = void 0;
|
||||
this.rawTouchscreen = void 0;
|
||||
this._page = void 0;
|
||||
this._session = void 0;
|
||||
this._opener = void 0;
|
||||
this._realmToContext = void 0;
|
||||
this._sessionListeners = [];
|
||||
this._browserContext = void 0;
|
||||
this._networkManager = void 0;
|
||||
this._pdf = void 0;
|
||||
this._initScriptIds = [];
|
||||
this._session = bidiSession;
|
||||
this._opener = opener;
|
||||
this.rawKeyboard = new _bidiInput.RawKeyboardImpl(bidiSession);
|
||||
this.rawMouse = new _bidiInput.RawMouseImpl(bidiSession);
|
||||
this.rawTouchscreen = new _bidiInput.RawTouchscreenImpl(bidiSession);
|
||||
this._realmToContext = new Map();
|
||||
this._page = new _page.Page(this, browserContext);
|
||||
this._browserContext = browserContext;
|
||||
this._networkManager = new _bidiNetworkManager.BidiNetworkManager(this._session, this._page, this._onNavigationResponseStarted.bind(this));
|
||||
this._pdf = new _bidiPdf.BidiPDF(this._session);
|
||||
this._page.on(_page.Page.Events.FrameDetached, frame => this._removeContextsForFrame(frame, false));
|
||||
this._sessionListeners = [_eventsHelper.eventsHelper.addEventListener(bidiSession, 'script.realmCreated', this._onRealmCreated.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'script.message', this._onScriptMessage.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'browsingContext.contextDestroyed', this._onBrowsingContextDestroyed.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'browsingContext.navigationStarted', this._onNavigationStarted.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'browsingContext.navigationAborted', this._onNavigationAborted.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'browsingContext.navigationFailed', this._onNavigationFailed.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'browsingContext.fragmentNavigated', this._onFragmentNavigated.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'browsingContext.domContentLoaded', this._onDomContentLoaded.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'browsingContext.load', this._onLoad.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'browsingContext.userPromptOpened', this._onUserPromptOpened.bind(this)), _eventsHelper.eventsHelper.addEventListener(bidiSession, 'log.entryAdded', this._onLogEntryAdded.bind(this))];
|
||||
|
||||
// Initialize main frame.
|
||||
// TODO: Wait for first execution context to be created and maybe about:blank navigated.
|
||||
this._initialize().then(() => {
|
||||
var _this$_opener;
|
||||
return this._page.reportAsNew((_this$_opener = this._opener) === null || _this$_opener === void 0 ? void 0 : _this$_opener._page);
|
||||
}, error => {
|
||||
var _this$_opener2;
|
||||
return this._page.reportAsNew((_this$_opener2 = this._opener) === null || _this$_opener2 === void 0 ? void 0 : _this$_opener2._page, error);
|
||||
});
|
||||
}
|
||||
async _initialize() {
|
||||
// Initialize main frame.
|
||||
this._onFrameAttached(this._session.sessionId, null);
|
||||
await Promise.all([this.updateHttpCredentials(), this.updateRequestInterception(), this._updateViewport(), this._installMainBinding(), this._addAllInitScripts()]);
|
||||
}
|
||||
async _addAllInitScripts() {
|
||||
return Promise.all(this._page.allInitScripts().map(initScript => this.addInitScript(initScript)));
|
||||
}
|
||||
didClose() {
|
||||
this._session.dispose();
|
||||
_eventsHelper.eventsHelper.removeEventListeners(this._sessionListeners);
|
||||
this._page._didClose();
|
||||
}
|
||||
_onFrameAttached(frameId, parentFrameId) {
|
||||
return this._page._frameManager.frameAttached(frameId, parentFrameId);
|
||||
}
|
||||
_removeContextsForFrame(frame, notifyFrame) {
|
||||
for (const [contextId, context] of this._realmToContext) {
|
||||
if (context.frame === frame) {
|
||||
this._realmToContext.delete(contextId);
|
||||
if (notifyFrame) frame._contextDestroyed(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
_onRealmCreated(realmInfo) {
|
||||
if (this._realmToContext.has(realmInfo.realm)) return;
|
||||
if (realmInfo.type !== 'window') return;
|
||||
const frame = this._page._frameManager.frame(realmInfo.context);
|
||||
if (!frame) return;
|
||||
let worldName;
|
||||
if (!realmInfo.sandbox) {
|
||||
worldName = 'main';
|
||||
// Force creating utility world every time the main world is created (e.g. due to navigation).
|
||||
this._touchUtilityWorld(realmInfo.context);
|
||||
} else if (realmInfo.sandbox === UTILITY_WORLD_NAME) {
|
||||
worldName = 'utility';
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
const delegate = new _bidiExecutionContext.BidiExecutionContext(this._session, realmInfo);
|
||||
const context = new dom.FrameExecutionContext(delegate, frame, worldName);
|
||||
frame._contextCreated(worldName, context);
|
||||
this._realmToContext.set(realmInfo.realm, context);
|
||||
}
|
||||
async _touchUtilityWorld(context) {
|
||||
await this._session.sendMayFail('script.evaluate', {
|
||||
expression: '1 + 1',
|
||||
target: {
|
||||
context,
|
||||
sandbox: UTILITY_WORLD_NAME
|
||||
},
|
||||
serializationOptions: {
|
||||
maxObjectDepth: 10,
|
||||
maxDomDepth: 10
|
||||
},
|
||||
awaitPromise: true,
|
||||
userActivation: true
|
||||
});
|
||||
}
|
||||
_onRealmDestroyed(params) {
|
||||
const context = this._realmToContext.get(params.realm);
|
||||
if (!context) return false;
|
||||
this._realmToContext.delete(params.realm);
|
||||
context.frame._contextDestroyed(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: route the message directly to the browser
|
||||
_onBrowsingContextDestroyed(params) {
|
||||
this._browserContext._browser._onBrowsingContextDestroyed(params);
|
||||
}
|
||||
_onNavigationStarted(params) {
|
||||
const frameId = params.context;
|
||||
this._page._frameManager.frameRequestedNavigation(frameId, params.navigation);
|
||||
const url = params.url.toLowerCase();
|
||||
if (url.startsWith('file:') || url.startsWith('data:') || url === 'about:blank') {
|
||||
// Navigation to file urls doesn't emit network events, so we fire 'commit' event right when navigation is started.
|
||||
// Doing it in domcontentload would be too late as we'd clear frame tree.
|
||||
const frame = this._page._frameManager.frame(frameId);
|
||||
if (frame) this._page._frameManager.frameCommittedNewDocumentNavigation(frameId, params.url, '', params.navigation, /* initial */false);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: there is no separate event for committed navigation, so we approximate it with responseStarted.
|
||||
_onNavigationResponseStarted(params) {
|
||||
const frameId = params.context;
|
||||
const frame = this._page._frameManager.frame(frameId);
|
||||
(0, _utils.assert)(frame);
|
||||
this._page._frameManager.frameCommittedNewDocumentNavigation(frameId, params.response.url, '', params.navigation, /* initial */false);
|
||||
// if (!initial)
|
||||
// this._firstNonInitialNavigationCommittedFulfill();
|
||||
}
|
||||
_onDomContentLoaded(params) {
|
||||
const frameId = params.context;
|
||||
this._page._frameManager.frameLifecycleEvent(frameId, 'domcontentloaded');
|
||||
}
|
||||
_onLoad(params) {
|
||||
this._page._frameManager.frameLifecycleEvent(params.context, 'load');
|
||||
}
|
||||
_onNavigationAborted(params) {
|
||||
this._page._frameManager.frameAbortedNavigation(params.context, 'Navigation aborted', params.navigation || undefined);
|
||||
}
|
||||
_onNavigationFailed(params) {
|
||||
this._page._frameManager.frameAbortedNavigation(params.context, 'Navigation failed', params.navigation || undefined);
|
||||
}
|
||||
_onFragmentNavigated(params) {
|
||||
this._page._frameManager.frameCommittedSameDocumentNavigation(params.context, params.url);
|
||||
}
|
||||
_onUserPromptOpened(event) {
|
||||
this._page.emitOnContext(_browserContext.BrowserContext.Events.Dialog, new dialog.Dialog(this._page, event.type, event.message, async (accept, userText) => {
|
||||
await this._session.send('browsingContext.handleUserPrompt', {
|
||||
context: event.context,
|
||||
accept,
|
||||
userText
|
||||
});
|
||||
}, event.defaultValue));
|
||||
}
|
||||
_onLogEntryAdded(params) {
|
||||
var _params$stackTrace;
|
||||
if (params.type !== 'console') return;
|
||||
const entry = params;
|
||||
const context = this._realmToContext.get(params.source.realm);
|
||||
if (!context) return;
|
||||
const callFrame = (_params$stackTrace = params.stackTrace) === null || _params$stackTrace === void 0 ? void 0 : _params$stackTrace.callFrames[0];
|
||||
const location = callFrame !== null && callFrame !== void 0 ? callFrame : {
|
||||
url: '',
|
||||
lineNumber: 1,
|
||||
columnNumber: 1
|
||||
};
|
||||
this._page._addConsoleMessage(entry.method, entry.args.map(arg => (0, _bidiExecutionContext.createHandle)(context, arg)), location, params.text || undefined);
|
||||
}
|
||||
async navigateFrame(frame, url, referrer) {
|
||||
const {
|
||||
navigation
|
||||
} = await this._session.send('browsingContext.navigate', {
|
||||
context: frame._id,
|
||||
url
|
||||
});
|
||||
return {
|
||||
newDocumentId: navigation || undefined
|
||||
};
|
||||
}
|
||||
async updateExtraHTTPHeaders() {}
|
||||
async updateEmulateMedia() {}
|
||||
async updateEmulatedViewportSize() {
|
||||
await this._updateViewport();
|
||||
}
|
||||
async updateUserAgent() {}
|
||||
async bringToFront() {
|
||||
await this._session.send('browsingContext.activate', {
|
||||
context: this._session.sessionId
|
||||
});
|
||||
}
|
||||
async _updateViewport() {
|
||||
const options = this._browserContext._options;
|
||||
const deviceSize = this._page.emulatedSize();
|
||||
if (deviceSize === null) return;
|
||||
const viewportSize = deviceSize.viewport;
|
||||
await this._session.send('browsingContext.setViewport', {
|
||||
context: this._session.sessionId,
|
||||
viewport: {
|
||||
width: viewportSize.width,
|
||||
height: viewportSize.height
|
||||
},
|
||||
devicePixelRatio: options.deviceScaleFactor || 1
|
||||
});
|
||||
}
|
||||
async updateRequestInterception() {
|
||||
await this._networkManager.setRequestInterception(this._page.needsRequestInterception());
|
||||
}
|
||||
async updateOffline() {}
|
||||
async updateHttpCredentials() {
|
||||
await this._networkManager.setCredentials(this._browserContext._options.httpCredentials);
|
||||
}
|
||||
async updateFileChooserInterception() {}
|
||||
async reload() {
|
||||
await this._session.send('browsingContext.reload', {
|
||||
context: this._session.sessionId,
|
||||
// ignoreCache: true,
|
||||
wait: bidi.BrowsingContext.ReadinessState.Interactive
|
||||
});
|
||||
}
|
||||
async goBack() {
|
||||
return await this._session.send('browsingContext.traverseHistory', {
|
||||
context: this._session.sessionId,
|
||||
delta: -1
|
||||
}).then(() => true).catch(() => false);
|
||||
}
|
||||
async goForward() {
|
||||
return await this._session.send('browsingContext.traverseHistory', {
|
||||
context: this._session.sessionId,
|
||||
delta: +1
|
||||
}).then(() => true).catch(() => false);
|
||||
}
|
||||
async requestGC() {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
// TODO: consider calling this only when bindings are added.
|
||||
async _installMainBinding() {
|
||||
const functionDeclaration = addMainBinding.toString();
|
||||
const args = [{
|
||||
type: 'channel',
|
||||
value: {
|
||||
channel: kPlaywrightBindingChannel,
|
||||
ownership: bidi.Script.ResultOwnership.Root
|
||||
}
|
||||
}];
|
||||
const promises = [];
|
||||
promises.push(this._session.send('script.addPreloadScript', {
|
||||
functionDeclaration,
|
||||
arguments: args
|
||||
}));
|
||||
promises.push(this._session.send('script.callFunction', {
|
||||
functionDeclaration,
|
||||
arguments: args,
|
||||
target: toBidiExecutionContext(await this._page.mainFrame()._mainContext())._target,
|
||||
awaitPromise: false,
|
||||
userActivation: false
|
||||
}));
|
||||
await Promise.all(promises);
|
||||
}
|
||||
async _onScriptMessage(event) {
|
||||
if (event.channel !== kPlaywrightBindingChannel) return;
|
||||
const pageOrError = await this._page.waitForInitializedOrError();
|
||||
if (pageOrError instanceof Error) return;
|
||||
const context = this._realmToContext.get(event.source.realm);
|
||||
if (!context) return;
|
||||
if (event.data.type !== 'string') return;
|
||||
await this._page._onBindingCalled(event.data.value, context);
|
||||
}
|
||||
async addInitScript(initScript) {
|
||||
const {
|
||||
script
|
||||
} = await this._session.send('script.addPreloadScript', {
|
||||
// TODO: remove function call from the source.
|
||||
functionDeclaration: `() => { return ${initScript.source} }`,
|
||||
// TODO: push to iframes?
|
||||
contexts: [this._session.sessionId]
|
||||
});
|
||||
if (!initScript.internal) this._initScriptIds.push(script);
|
||||
}
|
||||
async removeNonInternalInitScripts() {
|
||||
const promises = this._initScriptIds.map(script => this._session.send('script.removePreloadScript', {
|
||||
script
|
||||
}));
|
||||
this._initScriptIds = [];
|
||||
await Promise.all(promises);
|
||||
}
|
||||
async closePage(runBeforeUnload) {
|
||||
await this._session.send('browsingContext.close', {
|
||||
context: this._session.sessionId,
|
||||
promptUnload: runBeforeUnload
|
||||
});
|
||||
}
|
||||
async setBackgroundColor(color) {}
|
||||
async takeScreenshot(progress, format, documentRect, viewportRect, quality, fitsViewport, scale) {
|
||||
const rect = documentRect || viewportRect;
|
||||
const {
|
||||
data
|
||||
} = await this._session.send('browsingContext.captureScreenshot', {
|
||||
context: this._session.sessionId,
|
||||
format: {
|
||||
type: `image/${format === 'png' ? 'png' : 'jpeg'}`,
|
||||
quality: quality ? quality / 100 : 0.8
|
||||
},
|
||||
origin: documentRect ? 'document' : 'viewport',
|
||||
clip: {
|
||||
type: 'box',
|
||||
...rect
|
||||
}
|
||||
});
|
||||
return Buffer.from(data, 'base64');
|
||||
}
|
||||
async getContentFrame(handle) {
|
||||
const executionContext = toBidiExecutionContext(handle._context);
|
||||
const frameId = await executionContext.contentFrameIdForFrame(handle);
|
||||
if (!frameId) return null;
|
||||
return this._page._frameManager.frame(frameId);
|
||||
}
|
||||
async getOwnerFrame(handle) {
|
||||
// TODO: switch to utility world?
|
||||
const windowHandle = await handle.evaluateHandle(node => {
|
||||
var _node$ownerDocument;
|
||||
const doc = (_node$ownerDocument = node.ownerDocument) !== null && _node$ownerDocument !== void 0 ? _node$ownerDocument : node;
|
||||
return doc.defaultView;
|
||||
});
|
||||
if (!windowHandle) return null;
|
||||
const executionContext = toBidiExecutionContext(handle._context);
|
||||
return executionContext.frameIdForWindowHandle(windowHandle);
|
||||
}
|
||||
async getBoundingBox(handle) {
|
||||
const box = await handle.evaluate(element => {
|
||||
if (!(element instanceof Element)) return null;
|
||||
const rect = element.getBoundingClientRect();
|
||||
return {
|
||||
x: rect.x,
|
||||
y: rect.y,
|
||||
width: rect.width,
|
||||
height: rect.height
|
||||
};
|
||||
});
|
||||
if (!box) return null;
|
||||
const position = await this._framePosition(handle._frame);
|
||||
if (!position) return null;
|
||||
box.x += position.x;
|
||||
box.y += position.y;
|
||||
return box;
|
||||
}
|
||||
|
||||
// TODO: move to Frame.
|
||||
async _framePosition(frame) {
|
||||
if (frame === this._page.mainFrame()) return {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
const element = await frame.frameElement();
|
||||
const box = await element.boundingBox();
|
||||
if (!box) return null;
|
||||
const style = await element.evaluateInUtility(([injected, iframe]) => injected.describeIFrameStyle(iframe), {}).catch(e => 'error:notconnected');
|
||||
if (style === 'error:notconnected' || style === 'transformed') return null;
|
||||
// Content box is offset by border and padding widths.
|
||||
box.x += style.left;
|
||||
box.y += style.top;
|
||||
return box;
|
||||
}
|
||||
async scrollRectIntoViewIfNeeded(handle, rect) {
|
||||
return await handle.evaluateInUtility(([injected, node]) => {
|
||||
node.scrollIntoView({
|
||||
block: 'center',
|
||||
inline: 'center',
|
||||
behavior: 'instant'
|
||||
});
|
||||
}, null).then(() => 'done').catch(e => {
|
||||
if (e instanceof Error && e.message.includes('Node is detached from document')) return 'error:notconnected';
|
||||
if (e instanceof Error && e.message.includes('Node does not have a layout object')) return 'error:notvisible';
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
async setScreencastOptions(options) {}
|
||||
rafCountForStablePosition() {
|
||||
return 1;
|
||||
}
|
||||
async getContentQuads(handle) {
|
||||
const quads = await handle.evaluateInUtility(([injected, node]) => {
|
||||
if (!node.isConnected) return 'error:notconnected';
|
||||
const rects = node.getClientRects();
|
||||
if (!rects) return null;
|
||||
return [...rects].map(rect => [{
|
||||
x: rect.left,
|
||||
y: rect.top
|
||||
}, {
|
||||
x: rect.right,
|
||||
y: rect.top
|
||||
}, {
|
||||
x: rect.right,
|
||||
y: rect.bottom
|
||||
}, {
|
||||
x: rect.left,
|
||||
y: rect.bottom
|
||||
}]);
|
||||
}, null);
|
||||
if (!quads || quads === 'error:notconnected') return quads;
|
||||
// TODO: consider transforming quads to support clicks in iframes.
|
||||
const position = await this._framePosition(handle._frame);
|
||||
if (!position) return null;
|
||||
quads.forEach(quad => quad.forEach(point => {
|
||||
point.x += position.x;
|
||||
point.y += position.y;
|
||||
}));
|
||||
return quads;
|
||||
}
|
||||
async setInputFilePaths(handle, paths) {
|
||||
const fromContext = toBidiExecutionContext(handle._context);
|
||||
await this._session.send('input.setFiles', {
|
||||
context: this._session.sessionId,
|
||||
element: await fromContext.nodeIdForElementHandle(handle),
|
||||
files: paths
|
||||
});
|
||||
}
|
||||
async adoptElementHandle(handle, to) {
|
||||
const fromContext = toBidiExecutionContext(handle._context);
|
||||
const nodeId = await fromContext.nodeIdForElementHandle(handle);
|
||||
const executionContext = toBidiExecutionContext(to);
|
||||
return await executionContext.remoteObjectForNodeId(to, nodeId);
|
||||
}
|
||||
async getAccessibilityTree(needle) {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
async inputActionEpilogue() {}
|
||||
async resetForReuse() {}
|
||||
async pdf(options) {
|
||||
return this._pdf.generate(options);
|
||||
}
|
||||
async getFrameElement(frame) {
|
||||
const parent = frame.parentFrame();
|
||||
if (!parent) throw new Error('Frame has been detached.');
|
||||
const parentContext = await parent._mainContext();
|
||||
const list = await parentContext.evaluateHandle(() => {
|
||||
return [...document.querySelectorAll('iframe,frame')];
|
||||
});
|
||||
const length = await list.evaluate(list => list.length);
|
||||
let foundElement = null;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const element = await list.evaluateHandle((list, i) => list[i], i);
|
||||
const candidate = await element.contentFrame();
|
||||
if (frame === candidate) {
|
||||
foundElement = element;
|
||||
break;
|
||||
} else {
|
||||
element.dispose();
|
||||
}
|
||||
}
|
||||
list.dispose();
|
||||
if (!foundElement) throw new Error('Frame has been detached.');
|
||||
return foundElement;
|
||||
}
|
||||
shouldToggleStyleSheetToSyncAnimations() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
exports.BidiPage = BidiPage;
|
||||
function addMainBinding(callback) {
|
||||
globalThis['__playwright__binding__'] = callback;
|
||||
}
|
||||
function toBidiExecutionContext(executionContext) {
|
||||
return executionContext.delegate;
|
||||
}
|
||||
140
node_modules/playwright-core/lib/server/bidi/bidiPdf.js
generated
vendored
Normal file
140
node_modules/playwright-core/lib/server/bidi/bidiPdf.js
generated
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.BidiPDF = void 0;
|
||||
var _utils = require("../../utils");
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const PagePaperFormats = {
|
||||
letter: {
|
||||
width: 8.5,
|
||||
height: 11
|
||||
},
|
||||
legal: {
|
||||
width: 8.5,
|
||||
height: 14
|
||||
},
|
||||
tabloid: {
|
||||
width: 11,
|
||||
height: 17
|
||||
},
|
||||
ledger: {
|
||||
width: 17,
|
||||
height: 11
|
||||
},
|
||||
a0: {
|
||||
width: 33.1,
|
||||
height: 46.8
|
||||
},
|
||||
a1: {
|
||||
width: 23.4,
|
||||
height: 33.1
|
||||
},
|
||||
a2: {
|
||||
width: 16.54,
|
||||
height: 23.4
|
||||
},
|
||||
a3: {
|
||||
width: 11.7,
|
||||
height: 16.54
|
||||
},
|
||||
a4: {
|
||||
width: 8.27,
|
||||
height: 11.7
|
||||
},
|
||||
a5: {
|
||||
width: 5.83,
|
||||
height: 8.27
|
||||
},
|
||||
a6: {
|
||||
width: 4.13,
|
||||
height: 5.83
|
||||
}
|
||||
};
|
||||
const unitToPixels = {
|
||||
'px': 1,
|
||||
'in': 96,
|
||||
'cm': 37.8,
|
||||
'mm': 3.78
|
||||
};
|
||||
function convertPrintParameterToInches(text) {
|
||||
if (text === undefined) return undefined;
|
||||
let unit = text.substring(text.length - 2).toLowerCase();
|
||||
let valueText = '';
|
||||
if (unitToPixels.hasOwnProperty(unit)) {
|
||||
valueText = text.substring(0, text.length - 2);
|
||||
} else {
|
||||
// In case of unknown unit try to parse the whole parameter as number of pixels.
|
||||
// This is consistent with phantom's paperSize behavior.
|
||||
unit = 'px';
|
||||
valueText = text;
|
||||
}
|
||||
const value = Number(valueText);
|
||||
(0, _utils.assert)(!isNaN(value), 'Failed to parse parameter value: ' + text);
|
||||
const pixels = value * unitToPixels[unit];
|
||||
return pixels / 96;
|
||||
}
|
||||
class BidiPDF {
|
||||
constructor(session) {
|
||||
this._session = void 0;
|
||||
this._session = session;
|
||||
}
|
||||
async generate(options) {
|
||||
const {
|
||||
scale = 1,
|
||||
printBackground = false,
|
||||
landscape = false,
|
||||
pageRanges = '',
|
||||
margin = {}
|
||||
} = options;
|
||||
let paperWidth = 8.5;
|
||||
let paperHeight = 11;
|
||||
if (options.format) {
|
||||
const format = PagePaperFormats[options.format.toLowerCase()];
|
||||
(0, _utils.assert)(format, 'Unknown paper format: ' + options.format);
|
||||
paperWidth = format.width;
|
||||
paperHeight = format.height;
|
||||
} else {
|
||||
paperWidth = convertPrintParameterToInches(options.width) || paperWidth;
|
||||
paperHeight = convertPrintParameterToInches(options.height) || paperHeight;
|
||||
}
|
||||
const {
|
||||
data
|
||||
} = await this._session.send('browsingContext.print', {
|
||||
context: this._session.sessionId,
|
||||
background: printBackground,
|
||||
margin: {
|
||||
bottom: convertPrintParameterToInches(margin.bottom) || 0,
|
||||
left: convertPrintParameterToInches(margin.left) || 0,
|
||||
right: convertPrintParameterToInches(margin.right) || 0,
|
||||
top: convertPrintParameterToInches(margin.top) || 0
|
||||
},
|
||||
orientation: landscape ? 'landscape' : 'portrait',
|
||||
page: {
|
||||
width: paperWidth,
|
||||
height: paperHeight
|
||||
},
|
||||
pageRanges: pageRanges ? pageRanges.split(',').map(r => r.trim()) : undefined,
|
||||
scale
|
||||
});
|
||||
return Buffer.from(data, 'base64');
|
||||
}
|
||||
}
|
||||
exports.BidiPDF = BidiPDF;
|
||||
93
node_modules/playwright-core/lib/server/bidi/third_party/bidiDeserializer.js
generated
vendored
Normal file
93
node_modules/playwright-core/lib/server/bidi/third_party/bidiDeserializer.js
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.BidiDeserializer = void 0;
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2024 Google Inc.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* eslint-disable object-curly-spacing */
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class BidiDeserializer {
|
||||
static deserialize(result) {
|
||||
var _result$value, _result$value2, _result$value3, _result$value4;
|
||||
if (!result) return undefined;
|
||||
switch (result.type) {
|
||||
case 'array':
|
||||
return (_result$value = result.value) === null || _result$value === void 0 ? void 0 : _result$value.map(value => {
|
||||
return BidiDeserializer.deserialize(value);
|
||||
});
|
||||
case 'set':
|
||||
return (_result$value2 = result.value) === null || _result$value2 === void 0 ? void 0 : _result$value2.reduce((acc, value) => {
|
||||
return acc.add(BidiDeserializer.deserialize(value));
|
||||
}, new Set());
|
||||
case 'object':
|
||||
return (_result$value3 = result.value) === null || _result$value3 === void 0 ? void 0 : _result$value3.reduce((acc, tuple) => {
|
||||
const {
|
||||
key,
|
||||
value
|
||||
} = BidiDeserializer._deserializeTuple(tuple);
|
||||
acc[key] = value;
|
||||
return acc;
|
||||
}, {});
|
||||
case 'map':
|
||||
return (_result$value4 = result.value) === null || _result$value4 === void 0 ? void 0 : _result$value4.reduce((acc, tuple) => {
|
||||
const {
|
||||
key,
|
||||
value
|
||||
} = BidiDeserializer._deserializeTuple(tuple);
|
||||
return acc.set(key, value);
|
||||
}, new Map());
|
||||
case 'promise':
|
||||
return {};
|
||||
case 'regexp':
|
||||
return new RegExp(result.value.pattern, result.value.flags);
|
||||
case 'date':
|
||||
return new Date(result.value);
|
||||
case 'undefined':
|
||||
return undefined;
|
||||
case 'null':
|
||||
return null;
|
||||
case 'number':
|
||||
return BidiDeserializer._deserializeNumber(result.value);
|
||||
case 'bigint':
|
||||
return BigInt(result.value);
|
||||
case 'boolean':
|
||||
return Boolean(result.value);
|
||||
case 'string':
|
||||
return result.value;
|
||||
}
|
||||
throw new Error(`Deserialization of type ${result.type} not supported.`);
|
||||
}
|
||||
static _deserializeNumber(value) {
|
||||
switch (value) {
|
||||
case '-0':
|
||||
return -0;
|
||||
case 'NaN':
|
||||
return NaN;
|
||||
case 'Infinity':
|
||||
return Infinity;
|
||||
case '-Infinity':
|
||||
return -Infinity;
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
static _deserializeTuple([serializedKey, serializedValue]) {
|
||||
const key = typeof serializedKey === 'string' ? serializedKey : BidiDeserializer.deserialize(serializedKey);
|
||||
const value = BidiDeserializer.deserialize(serializedValue);
|
||||
return {
|
||||
key,
|
||||
value
|
||||
};
|
||||
}
|
||||
}
|
||||
exports.BidiDeserializer = BidiDeserializer;
|
||||
240
node_modules/playwright-core/lib/server/bidi/third_party/bidiKeyboard.js
generated
vendored
Normal file
240
node_modules/playwright-core/lib/server/bidi/third_party/bidiKeyboard.js
generated
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.getBidiKeyValue = void 0;
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2024 Google Inc.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* eslint-disable curly */
|
||||
|
||||
const getBidiKeyValue = keyName => {
|
||||
switch (keyName) {
|
||||
case '\r':
|
||||
case '\n':
|
||||
keyName = 'Enter';
|
||||
break;
|
||||
}
|
||||
// Measures the number of code points rather than UTF-16 code units.
|
||||
if ([...keyName].length === 1) {
|
||||
return keyName;
|
||||
}
|
||||
switch (keyName) {
|
||||
case 'Cancel':
|
||||
return '\uE001';
|
||||
case 'Help':
|
||||
return '\uE002';
|
||||
case 'Backspace':
|
||||
return '\uE003';
|
||||
case 'Tab':
|
||||
return '\uE004';
|
||||
case 'Clear':
|
||||
return '\uE005';
|
||||
case 'Enter':
|
||||
return '\uE007';
|
||||
case 'Shift':
|
||||
case 'ShiftLeft':
|
||||
return '\uE008';
|
||||
case 'Control':
|
||||
case 'ControlLeft':
|
||||
return '\uE009';
|
||||
case 'Alt':
|
||||
case 'AltLeft':
|
||||
return '\uE00A';
|
||||
case 'Pause':
|
||||
return '\uE00B';
|
||||
case 'Escape':
|
||||
return '\uE00C';
|
||||
case 'PageUp':
|
||||
return '\uE00E';
|
||||
case 'PageDown':
|
||||
return '\uE00F';
|
||||
case 'End':
|
||||
return '\uE010';
|
||||
case 'Home':
|
||||
return '\uE011';
|
||||
case 'ArrowLeft':
|
||||
return '\uE012';
|
||||
case 'ArrowUp':
|
||||
return '\uE013';
|
||||
case 'ArrowRight':
|
||||
return '\uE014';
|
||||
case 'ArrowDown':
|
||||
return '\uE015';
|
||||
case 'Insert':
|
||||
return '\uE016';
|
||||
case 'Delete':
|
||||
return '\uE017';
|
||||
case 'NumpadEqual':
|
||||
return '\uE019';
|
||||
case 'Numpad0':
|
||||
return '\uE01A';
|
||||
case 'Numpad1':
|
||||
return '\uE01B';
|
||||
case 'Numpad2':
|
||||
return '\uE01C';
|
||||
case 'Numpad3':
|
||||
return '\uE01D';
|
||||
case 'Numpad4':
|
||||
return '\uE01E';
|
||||
case 'Numpad5':
|
||||
return '\uE01F';
|
||||
case 'Numpad6':
|
||||
return '\uE020';
|
||||
case 'Numpad7':
|
||||
return '\uE021';
|
||||
case 'Numpad8':
|
||||
return '\uE022';
|
||||
case 'Numpad9':
|
||||
return '\uE023';
|
||||
case 'NumpadMultiply':
|
||||
return '\uE024';
|
||||
case 'NumpadAdd':
|
||||
return '\uE025';
|
||||
case 'NumpadSubtract':
|
||||
return '\uE027';
|
||||
case 'NumpadDecimal':
|
||||
return '\uE028';
|
||||
case 'NumpadDivide':
|
||||
return '\uE029';
|
||||
case 'F1':
|
||||
return '\uE031';
|
||||
case 'F2':
|
||||
return '\uE032';
|
||||
case 'F3':
|
||||
return '\uE033';
|
||||
case 'F4':
|
||||
return '\uE034';
|
||||
case 'F5':
|
||||
return '\uE035';
|
||||
case 'F6':
|
||||
return '\uE036';
|
||||
case 'F7':
|
||||
return '\uE037';
|
||||
case 'F8':
|
||||
return '\uE038';
|
||||
case 'F9':
|
||||
return '\uE039';
|
||||
case 'F10':
|
||||
return '\uE03A';
|
||||
case 'F11':
|
||||
return '\uE03B';
|
||||
case 'F12':
|
||||
return '\uE03C';
|
||||
case 'Meta':
|
||||
case 'MetaLeft':
|
||||
return '\uE03D';
|
||||
case 'ShiftRight':
|
||||
return '\uE050';
|
||||
case 'ControlRight':
|
||||
return '\uE051';
|
||||
case 'AltRight':
|
||||
return '\uE052';
|
||||
case 'MetaRight':
|
||||
return '\uE053';
|
||||
case 'Space':
|
||||
return ' ';
|
||||
case 'Digit0':
|
||||
return '0';
|
||||
case 'Digit1':
|
||||
return '1';
|
||||
case 'Digit2':
|
||||
return '2';
|
||||
case 'Digit3':
|
||||
return '3';
|
||||
case 'Digit4':
|
||||
return '4';
|
||||
case 'Digit5':
|
||||
return '5';
|
||||
case 'Digit6':
|
||||
return '6';
|
||||
case 'Digit7':
|
||||
return '7';
|
||||
case 'Digit8':
|
||||
return '8';
|
||||
case 'Digit9':
|
||||
return '9';
|
||||
case 'KeyA':
|
||||
return 'a';
|
||||
case 'KeyB':
|
||||
return 'b';
|
||||
case 'KeyC':
|
||||
return 'c';
|
||||
case 'KeyD':
|
||||
return 'd';
|
||||
case 'KeyE':
|
||||
return 'e';
|
||||
case 'KeyF':
|
||||
return 'f';
|
||||
case 'KeyG':
|
||||
return 'g';
|
||||
case 'KeyH':
|
||||
return 'h';
|
||||
case 'KeyI':
|
||||
return 'i';
|
||||
case 'KeyJ':
|
||||
return 'j';
|
||||
case 'KeyK':
|
||||
return 'k';
|
||||
case 'KeyL':
|
||||
return 'l';
|
||||
case 'KeyM':
|
||||
return 'm';
|
||||
case 'KeyN':
|
||||
return 'n';
|
||||
case 'KeyO':
|
||||
return 'o';
|
||||
case 'KeyP':
|
||||
return 'p';
|
||||
case 'KeyQ':
|
||||
return 'q';
|
||||
case 'KeyR':
|
||||
return 'r';
|
||||
case 'KeyS':
|
||||
return 's';
|
||||
case 'KeyT':
|
||||
return 't';
|
||||
case 'KeyU':
|
||||
return 'u';
|
||||
case 'KeyV':
|
||||
return 'v';
|
||||
case 'KeyW':
|
||||
return 'w';
|
||||
case 'KeyX':
|
||||
return 'x';
|
||||
case 'KeyY':
|
||||
return 'y';
|
||||
case 'KeyZ':
|
||||
return 'z';
|
||||
case 'Semicolon':
|
||||
return ';';
|
||||
case 'Equal':
|
||||
return '=';
|
||||
case 'Comma':
|
||||
return ',';
|
||||
case 'Minus':
|
||||
return '-';
|
||||
case 'Period':
|
||||
return '.';
|
||||
case 'Slash':
|
||||
return '/';
|
||||
case 'Backquote':
|
||||
return '`';
|
||||
case 'BracketLeft':
|
||||
return '[';
|
||||
case 'Backslash':
|
||||
return '\\';
|
||||
case 'BracketRight':
|
||||
return ']';
|
||||
case 'Quote':
|
||||
return '"';
|
||||
default:
|
||||
throw new Error(`Unknown key: "${keyName}"`);
|
||||
}
|
||||
};
|
||||
exports.getBidiKeyValue = getBidiKeyValue;
|
||||
139
node_modules/playwright-core/lib/server/bidi/third_party/bidiProtocol.js
generated
vendored
Normal file
139
node_modules/playwright-core/lib/server/bidi/third_party/bidiProtocol.js
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Storage = exports.Session = exports.Script = exports.Network = exports.Log = exports.Input = exports.ErrorCode = exports.BrowsingContext = exports.Browser = void 0;
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2024 Google Inc.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/**
|
||||
* THIS FILE IS AUTOGENERATED by cddlconv 0.1.5.
|
||||
* Run `node tools/generate-bidi-types.mjs` to regenerate.
|
||||
* @see https://github.com/w3c/webdriver-bidi/blob/master/index.bs
|
||||
*/
|
||||
/**
|
||||
* Must be between `-9007199254740991` and `9007199254740991`, inclusive.
|
||||
*/
|
||||
/**
|
||||
* Must be between `0` and `9007199254740991`, inclusive.
|
||||
*/
|
||||
let ErrorCode = exports.ErrorCode = /*#__PURE__*/function (ErrorCode) {
|
||||
ErrorCode["InvalidArgument"] = "invalid argument";
|
||||
ErrorCode["InvalidSelector"] = "invalid selector";
|
||||
ErrorCode["InvalidSessionId"] = "invalid session id";
|
||||
ErrorCode["MoveTargetOutOfBounds"] = "move target out of bounds";
|
||||
ErrorCode["NoSuchAlert"] = "no such alert";
|
||||
ErrorCode["NoSuchElement"] = "no such element";
|
||||
ErrorCode["NoSuchFrame"] = "no such frame";
|
||||
ErrorCode["NoSuchHandle"] = "no such handle";
|
||||
ErrorCode["NoSuchHistoryEntry"] = "no such history entry";
|
||||
ErrorCode["NoSuchIntercept"] = "no such intercept";
|
||||
ErrorCode["NoSuchNode"] = "no such node";
|
||||
ErrorCode["NoSuchRequest"] = "no such request";
|
||||
ErrorCode["NoSuchScript"] = "no such script";
|
||||
ErrorCode["NoSuchStoragePartition"] = "no such storage partition";
|
||||
ErrorCode["NoSuchUserContext"] = "no such user context";
|
||||
ErrorCode["SessionNotCreated"] = "session not created";
|
||||
ErrorCode["UnableToCaptureScreen"] = "unable to capture screen";
|
||||
ErrorCode["UnableToCloseBrowser"] = "unable to close browser";
|
||||
ErrorCode["UnableToSetCookie"] = "unable to set cookie";
|
||||
ErrorCode["UnableToSetFileInput"] = "unable to set file input";
|
||||
ErrorCode["UnderspecifiedStoragePartition"] = "underspecified storage partition";
|
||||
ErrorCode["UnknownCommand"] = "unknown command";
|
||||
ErrorCode["UnknownError"] = "unknown error";
|
||||
ErrorCode["UnsupportedOperation"] = "unsupported operation";
|
||||
return ErrorCode;
|
||||
}({});
|
||||
let Session = exports.Session = void 0;
|
||||
(function (_Session10) {
|
||||
let UserPromptHandlerType = /*#__PURE__*/function (UserPromptHandlerType) {
|
||||
UserPromptHandlerType["Accept"] = "accept";
|
||||
UserPromptHandlerType["Dismiss"] = "dismiss";
|
||||
UserPromptHandlerType["Ignore"] = "ignore";
|
||||
return UserPromptHandlerType;
|
||||
}({});
|
||||
_Session10.UserPromptHandlerType = UserPromptHandlerType;
|
||||
})(Session || (exports.Session = Session = {}));
|
||||
let Browser = exports.Browser = void 0;
|
||||
let BrowsingContext = exports.BrowsingContext = void 0;
|
||||
(function (_BrowsingContext10) {
|
||||
let ReadinessState = /*#__PURE__*/function (ReadinessState) {
|
||||
ReadinessState["None"] = "none";
|
||||
ReadinessState["Interactive"] = "interactive";
|
||||
ReadinessState["Complete"] = "complete";
|
||||
return ReadinessState;
|
||||
}({});
|
||||
_BrowsingContext10.ReadinessState = ReadinessState;
|
||||
})(BrowsingContext || (exports.BrowsingContext = BrowsingContext = {}));
|
||||
(function (_BrowsingContext11) {
|
||||
let UserPromptType = /*#__PURE__*/function (UserPromptType) {
|
||||
UserPromptType["Alert"] = "alert";
|
||||
UserPromptType["Beforeunload"] = "beforeunload";
|
||||
UserPromptType["Confirm"] = "confirm";
|
||||
UserPromptType["Prompt"] = "prompt";
|
||||
return UserPromptType;
|
||||
}({});
|
||||
_BrowsingContext11.UserPromptType = UserPromptType;
|
||||
})(BrowsingContext || (exports.BrowsingContext = BrowsingContext = {}));
|
||||
(function (_BrowsingContext24) {
|
||||
let CreateType = /*#__PURE__*/function (CreateType) {
|
||||
CreateType["Tab"] = "tab";
|
||||
CreateType["Window"] = "window";
|
||||
return CreateType;
|
||||
}({});
|
||||
_BrowsingContext24.CreateType = CreateType;
|
||||
})(BrowsingContext || (exports.BrowsingContext = BrowsingContext = {}));
|
||||
let Network = exports.Network = void 0;
|
||||
(function (_Network6) {
|
||||
let SameSite = /*#__PURE__*/function (SameSite) {
|
||||
SameSite["Strict"] = "strict";
|
||||
SameSite["Lax"] = "lax";
|
||||
SameSite["None"] = "none";
|
||||
return SameSite;
|
||||
}({});
|
||||
_Network6.SameSite = SameSite;
|
||||
})(Network || (exports.Network = Network = {}));
|
||||
(function (_Network23) {
|
||||
let InterceptPhase = /*#__PURE__*/function (InterceptPhase) {
|
||||
InterceptPhase["BeforeRequestSent"] = "beforeRequestSent";
|
||||
InterceptPhase["ResponseStarted"] = "responseStarted";
|
||||
InterceptPhase["AuthRequired"] = "authRequired";
|
||||
return InterceptPhase;
|
||||
}({});
|
||||
_Network23.InterceptPhase = InterceptPhase;
|
||||
})(Network || (exports.Network = Network = {}));
|
||||
let Script = exports.Script = void 0;
|
||||
(function (_Script68) {
|
||||
let ResultOwnership = /*#__PURE__*/function (ResultOwnership) {
|
||||
ResultOwnership["Root"] = "root";
|
||||
ResultOwnership["None"] = "none";
|
||||
return ResultOwnership;
|
||||
}({});
|
||||
_Script68.ResultOwnership = ResultOwnership;
|
||||
})(Script || (exports.Script = Script = {}));
|
||||
let Storage = exports.Storage = void 0;
|
||||
let Log = exports.Log = void 0;
|
||||
(function (_Log7) {
|
||||
let Level = /*#__PURE__*/function (Level) {
|
||||
Level["Debug"] = "debug";
|
||||
Level["Info"] = "info";
|
||||
Level["Warn"] = "warn";
|
||||
Level["Error"] = "error";
|
||||
return Level;
|
||||
}({});
|
||||
_Log7.Level = Level;
|
||||
})(Log || (exports.Log = Log = {}));
|
||||
let Input = exports.Input = void 0;
|
||||
(function (_Input9) {
|
||||
let PointerType = /*#__PURE__*/function (PointerType) {
|
||||
PointerType["Mouse"] = "mouse";
|
||||
PointerType["Pen"] = "pen";
|
||||
PointerType["Touch"] = "touch";
|
||||
return PointerType;
|
||||
}({});
|
||||
_Input9.PointerType = PointerType;
|
||||
})(Input || (exports.Input = Input = {}));
|
||||
144
node_modules/playwright-core/lib/server/bidi/third_party/bidiSerializer.js
generated
vendored
Normal file
144
node_modules/playwright-core/lib/server/bidi/third_party/bidiSerializer.js
generated
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.isRegExp = exports.isPlainObject = exports.isDate = exports.BidiSerializer = void 0;
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2024 Google Inc.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* eslint-disable curly, indent */
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class UnserializableError extends Error {}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class BidiSerializer {
|
||||
static serialize(arg) {
|
||||
switch (typeof arg) {
|
||||
case 'symbol':
|
||||
case 'function':
|
||||
throw new UnserializableError(`Unable to serializable ${typeof arg}`);
|
||||
case 'object':
|
||||
return BidiSerializer._serializeObject(arg);
|
||||
case 'undefined':
|
||||
return {
|
||||
type: 'undefined'
|
||||
};
|
||||
case 'number':
|
||||
return BidiSerializer._serializeNumber(arg);
|
||||
case 'bigint':
|
||||
return {
|
||||
type: 'bigint',
|
||||
value: arg.toString()
|
||||
};
|
||||
case 'string':
|
||||
return {
|
||||
type: 'string',
|
||||
value: arg
|
||||
};
|
||||
case 'boolean':
|
||||
return {
|
||||
type: 'boolean',
|
||||
value: arg
|
||||
};
|
||||
}
|
||||
}
|
||||
static _serializeNumber(arg) {
|
||||
let value;
|
||||
if (Object.is(arg, -0)) {
|
||||
value = '-0';
|
||||
} else if (Object.is(arg, Infinity)) {
|
||||
value = 'Infinity';
|
||||
} else if (Object.is(arg, -Infinity)) {
|
||||
value = '-Infinity';
|
||||
} else if (Object.is(arg, NaN)) {
|
||||
value = 'NaN';
|
||||
} else {
|
||||
value = arg;
|
||||
}
|
||||
return {
|
||||
type: 'number',
|
||||
value
|
||||
};
|
||||
}
|
||||
static _serializeObject(arg) {
|
||||
if (arg === null) {
|
||||
return {
|
||||
type: 'null'
|
||||
};
|
||||
} else if (Array.isArray(arg)) {
|
||||
const parsedArray = arg.map(subArg => {
|
||||
return BidiSerializer.serialize(subArg);
|
||||
});
|
||||
return {
|
||||
type: 'array',
|
||||
value: parsedArray
|
||||
};
|
||||
} else if (isPlainObject(arg)) {
|
||||
try {
|
||||
JSON.stringify(arg);
|
||||
} catch (error) {
|
||||
if (error instanceof TypeError && error.message.startsWith('Converting circular structure to JSON')) {
|
||||
error.message += ' Recursive objects are not allowed.';
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
const parsedObject = [];
|
||||
for (const key in arg) {
|
||||
parsedObject.push([BidiSerializer.serialize(key), BidiSerializer.serialize(arg[key])]);
|
||||
}
|
||||
return {
|
||||
type: 'object',
|
||||
value: parsedObject
|
||||
};
|
||||
} else if (isRegExp(arg)) {
|
||||
return {
|
||||
type: 'regexp',
|
||||
value: {
|
||||
pattern: arg.source,
|
||||
flags: arg.flags
|
||||
}
|
||||
};
|
||||
} else if (isDate(arg)) {
|
||||
return {
|
||||
type: 'date',
|
||||
value: arg.toISOString()
|
||||
};
|
||||
}
|
||||
throw new UnserializableError('Custom object serialization not possible. Use plain objects instead.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
exports.BidiSerializer = BidiSerializer;
|
||||
const isPlainObject = obj => {
|
||||
return typeof obj === 'object' && (obj === null || obj === void 0 ? void 0 : obj.constructor) === Object;
|
||||
};
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
exports.isPlainObject = isPlainObject;
|
||||
const isRegExp = obj => {
|
||||
return typeof obj === 'object' && (obj === null || obj === void 0 ? void 0 : obj.constructor) === RegExp;
|
||||
};
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
exports.isRegExp = isRegExp;
|
||||
const isDate = obj => {
|
||||
return typeof obj === 'object' && (obj === null || obj === void 0 ? void 0 : obj.constructor) === Date;
|
||||
};
|
||||
exports.isDate = isDate;
|
||||
237
node_modules/playwright-core/lib/server/bidi/third_party/firefoxPrefs.js
generated
vendored
Normal file
237
node_modules/playwright-core/lib/server/bidi/third_party/firefoxPrefs.js
generated
vendored
Normal file
@@ -0,0 +1,237 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.createProfile = createProfile;
|
||||
var _fs = _interopRequireDefault(require("fs"));
|
||||
var _path = _interopRequireDefault(require("path"));
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2023 Google Inc.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* eslint-disable curly, indent */
|
||||
|
||||
async function createProfile(options) {
|
||||
if (!_fs.default.existsSync(options.path)) {
|
||||
await _fs.default.promises.mkdir(options.path, {
|
||||
recursive: true
|
||||
});
|
||||
}
|
||||
await writePreferences({
|
||||
preferences: {
|
||||
...defaultProfilePreferences(options.preferences),
|
||||
...options.preferences
|
||||
},
|
||||
path: options.path
|
||||
});
|
||||
}
|
||||
function defaultProfilePreferences(extraPrefs) {
|
||||
const server = 'dummy.test';
|
||||
const defaultPrefs = {
|
||||
// Make sure Shield doesn't hit the network.
|
||||
'app.normandy.api_url': '',
|
||||
// Disable Firefox old build background check
|
||||
'app.update.checkInstallTime': false,
|
||||
// Disable automatically upgrading Firefox
|
||||
'app.update.disabledForTesting': true,
|
||||
// Increase the APZ content response timeout to 1 minute
|
||||
'apz.content_response_timeout': 60000,
|
||||
// Prevent various error message on the console
|
||||
// jest-puppeteer asserts that no error message is emitted by the console
|
||||
'browser.contentblocking.features.standard': '-tp,tpPrivate,cookieBehavior0,-cm,-fp',
|
||||
// Enable the dump function: which sends messages to the system
|
||||
// console
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1543115
|
||||
'browser.dom.window.dump.enabled': true,
|
||||
// Make sure newtab weather doesn't hit the network to retrieve weather data.
|
||||
'browser.newtabpage.activity-stream.discoverystream.region-weather-config': '',
|
||||
// Make sure newtab wallpapers don't hit the network to retrieve wallpaper data.
|
||||
'browser.newtabpage.activity-stream.newtabWallpapers.enabled': false,
|
||||
'browser.newtabpage.activity-stream.newtabWallpapers.v2.enabled': false,
|
||||
// Make sure Topsites doesn't hit the network to retrieve sponsored tiles.
|
||||
'browser.newtabpage.activity-stream.showSponsoredTopSites': false,
|
||||
// Disable topstories
|
||||
'browser.newtabpage.activity-stream.feeds.system.topstories': false,
|
||||
// Always display a blank page
|
||||
'browser.newtabpage.enabled': false,
|
||||
// Background thumbnails in particular cause grief: and disabling
|
||||
// thumbnails in general cannot hurt
|
||||
'browser.pagethumbnails.capturing_disabled': true,
|
||||
// Disable safebrowsing components.
|
||||
'browser.safebrowsing.blockedURIs.enabled': false,
|
||||
'browser.safebrowsing.downloads.enabled': false,
|
||||
'browser.safebrowsing.malware.enabled': false,
|
||||
'browser.safebrowsing.phishing.enabled': false,
|
||||
// Disable updates to search engines.
|
||||
'browser.search.update': false,
|
||||
// Do not restore the last open set of tabs if the browser has crashed
|
||||
'browser.sessionstore.resume_from_crash': false,
|
||||
// Skip check for default browser on startup
|
||||
'browser.shell.checkDefaultBrowser': false,
|
||||
// Disable newtabpage
|
||||
'browser.startup.homepage': 'about:blank',
|
||||
// Do not redirect user when a milstone upgrade of Firefox is detected
|
||||
'browser.startup.homepage_override.mstone': 'ignore',
|
||||
// Start with a blank page about:blank
|
||||
'browser.startup.page': 0,
|
||||
// Do not allow background tabs to be zombified on Android: otherwise for
|
||||
// tests that open additional tabs: the test harness tab itself might get
|
||||
// unloaded
|
||||
'browser.tabs.disableBackgroundZombification': false,
|
||||
// Do not warn when closing all other open tabs
|
||||
'browser.tabs.warnOnCloseOtherTabs': false,
|
||||
// Do not warn when multiple tabs will be opened
|
||||
'browser.tabs.warnOnOpen': false,
|
||||
// Do not automatically offer translations, as tests do not expect this.
|
||||
'browser.translations.automaticallyPopup': false,
|
||||
// Disable the UI tour.
|
||||
'browser.uitour.enabled': false,
|
||||
// Turn off search suggestions in the location bar so as not to trigger
|
||||
// network connections.
|
||||
'browser.urlbar.suggest.searches': false,
|
||||
// Disable first run splash page on Windows 10
|
||||
'browser.usedOnWindows10.introURL': '',
|
||||
// Do not warn on quitting Firefox
|
||||
'browser.warnOnQuit': false,
|
||||
// Defensively disable data reporting systems
|
||||
'datareporting.healthreport.documentServerURI': `http://${server}/dummy/healthreport/`,
|
||||
'datareporting.healthreport.logging.consoleEnabled': false,
|
||||
'datareporting.healthreport.service.enabled': false,
|
||||
'datareporting.healthreport.service.firstRun': false,
|
||||
'datareporting.healthreport.uploadEnabled': false,
|
||||
// Do not show datareporting policy notifications which can interfere with tests
|
||||
'datareporting.policy.dataSubmissionEnabled': false,
|
||||
'datareporting.policy.dataSubmissionPolicyBypassNotification': true,
|
||||
// DevTools JSONViewer sometimes fails to load dependencies with its require.js.
|
||||
// This doesn't affect Puppeteer but spams console (Bug 1424372)
|
||||
'devtools.jsonview.enabled': false,
|
||||
// Disable popup-blocker
|
||||
'dom.disable_open_during_load': false,
|
||||
// Enable the support for File object creation in the content process
|
||||
// Required for |Page.setFileInputFiles| protocol method.
|
||||
'dom.file.createInChild': true,
|
||||
// Disable the ProcessHangMonitor
|
||||
'dom.ipc.reportProcessHangs': false,
|
||||
// Disable slow script dialogues
|
||||
'dom.max_chrome_script_run_time': 0,
|
||||
'dom.max_script_run_time': 0,
|
||||
// Disable background timer throttling to allow tests to run in parallel
|
||||
// without a decrease in performance.
|
||||
'dom.min_background_timeout_value': 0,
|
||||
'dom.min_background_timeout_value_without_budget_throttling': 0,
|
||||
'dom.timeout.enable_budget_timer_throttling': false,
|
||||
// Disable HTTPS-First upgrades
|
||||
'dom.security.https_first': false,
|
||||
// Only load extensions from the application and user profile
|
||||
// AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
|
||||
'extensions.autoDisableScopes': 0,
|
||||
'extensions.enabledScopes': 5,
|
||||
// Disable metadata caching for installed add-ons by default
|
||||
'extensions.getAddons.cache.enabled': false,
|
||||
// Disable installing any distribution extensions or add-ons.
|
||||
'extensions.installDistroAddons': false,
|
||||
// Disabled screenshots extension
|
||||
'extensions.screenshots.disabled': true,
|
||||
// Turn off extension updates so they do not bother tests
|
||||
'extensions.update.enabled': false,
|
||||
// Turn off extension updates so they do not bother tests
|
||||
'extensions.update.notifyUser': false,
|
||||
// Make sure opening about:addons will not hit the network
|
||||
'extensions.webservice.discoverURL': `http://${server}/dummy/discoveryURL`,
|
||||
// Allow the application to have focus even it runs in the background
|
||||
'focusmanager.testmode': true,
|
||||
// Disable useragent updates
|
||||
'general.useragent.updates.enabled': false,
|
||||
// Always use network provider for geolocation tests so we bypass the
|
||||
// macOS dialog raised by the corelocation provider
|
||||
'geo.provider.testing': true,
|
||||
// Do not scan Wifi
|
||||
'geo.wifi.scan': false,
|
||||
// No hang monitor
|
||||
'hangmonitor.timeout': 0,
|
||||
// Show chrome errors and warnings in the error console
|
||||
'javascript.options.showInConsole': true,
|
||||
// Do not throttle rendering (requestAnimationFrame) in background tabs
|
||||
'layout.testing.top-level-always-active': true,
|
||||
// Disable download and usage of OpenH264: and Widevine plugins
|
||||
'media.gmp-manager.updateEnabled': false,
|
||||
// Disable the GFX sanity window
|
||||
'media.sanity-test.disabled': true,
|
||||
// Disable connectivity service pings
|
||||
'network.connectivity-service.enabled': false,
|
||||
// Disable experimental feature that is only available in Nightly
|
||||
'network.cookie.sameSite.laxByDefault': false,
|
||||
// Do not prompt for temporary redirects
|
||||
'network.http.prompt-temp-redirect': false,
|
||||
// Disable speculative connections so they are not reported as leaking
|
||||
// when they are hanging around
|
||||
'network.http.speculative-parallel-limit': 0,
|
||||
// Do not automatically switch between offline and online
|
||||
'network.manage-offline-status': false,
|
||||
// Make sure SNTP requests do not hit the network
|
||||
'network.sntp.pools': server,
|
||||
// Disable Flash.
|
||||
'plugin.state.flash': 0,
|
||||
'privacy.trackingprotection.enabled': false,
|
||||
// Can be removed once Firefox 89 is no longer supported
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1710839
|
||||
'remote.enabled': true,
|
||||
// Don't do network connections for mitm priming
|
||||
'security.certerrors.mitm.priming.enabled': false,
|
||||
// Local documents have access to all other local documents,
|
||||
// including directory listings
|
||||
'security.fileuri.strict_origin_policy': false,
|
||||
// Do not wait for the notification button security delay
|
||||
'security.notification_enable_delay': 0,
|
||||
// Do not automatically fill sign-in forms with known usernames and
|
||||
// passwords
|
||||
'signon.autofillForms': false,
|
||||
// Disable password capture, so that tests that include forms are not
|
||||
// influenced by the presence of the persistent doorhanger notification
|
||||
'signon.rememberSignons': false,
|
||||
// Disable first-run welcome page
|
||||
'startup.homepage_welcome_url': 'about:blank',
|
||||
// Disable first-run welcome page
|
||||
'startup.homepage_welcome_url.additional': '',
|
||||
// Disable browser animations (tabs, fullscreen, sliding alerts)
|
||||
'toolkit.cosmeticAnimations.enabled': false,
|
||||
// Prevent starting into safe mode after application crashes
|
||||
'toolkit.startup.max_resumed_crashes': -1
|
||||
};
|
||||
return Object.assign(defaultPrefs, extraPrefs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the user.js file with custom preferences as needed to allow
|
||||
* Firefox's CDP support to properly function. These preferences will be
|
||||
* automatically copied over to prefs.js during startup of Firefox. To be
|
||||
* able to restore the original values of preferences a backup of prefs.js
|
||||
* will be created.
|
||||
*
|
||||
* @param prefs - List of preferences to add.
|
||||
* @param profilePath - Firefox profile to write the preferences to.
|
||||
*/
|
||||
async function writePreferences(options) {
|
||||
const prefsPath = _path.default.join(options.path, 'prefs.js');
|
||||
const lines = Object.entries(options.preferences).map(([key, value]) => {
|
||||
return `user_pref(${JSON.stringify(key)}, ${JSON.stringify(value)});`;
|
||||
});
|
||||
|
||||
// Use allSettled to prevent corruption
|
||||
const result = await Promise.allSettled([_fs.default.promises.writeFile(_path.default.join(options.path, 'user.js'), lines.join('\n')),
|
||||
// Create a backup of the preferences file if it already exitsts.
|
||||
_fs.default.promises.access(prefsPath, _fs.default.constants.F_OK).then(async () => {
|
||||
await _fs.default.promises.copyFile(prefsPath, _path.default.join(options.path, 'prefs.js.playwright'));
|
||||
},
|
||||
// Swallow only if file does not exist
|
||||
() => {})]);
|
||||
for (const command of result) {
|
||||
if (command.status === 'rejected') {
|
||||
throw command.reason;
|
||||
}
|
||||
}
|
||||
}
|
||||
148
node_modules/playwright-core/lib/server/browser.js
generated
vendored
Normal file
148
node_modules/playwright-core/lib/server/browser.js
generated
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Browser = void 0;
|
||||
var _artifact = require("./artifact");
|
||||
var _browserContext = require("./browserContext");
|
||||
var _download = require("./download");
|
||||
var _instrumentation = require("./instrumentation");
|
||||
var _page = require("./page");
|
||||
var _socksClientCertificatesInterceptor = require("./socksClientCertificatesInterceptor");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class Browser extends _instrumentation.SdkObject {
|
||||
constructor(parent, options) {
|
||||
super(parent, 'browser');
|
||||
this.options = void 0;
|
||||
this._downloads = new Map();
|
||||
this._defaultContext = null;
|
||||
this._startedClosing = false;
|
||||
this._idToVideo = new Map();
|
||||
this._contextForReuse = void 0;
|
||||
this._closeReason = void 0;
|
||||
this._isCollocatedWithServer = true;
|
||||
this.attribution.browser = this;
|
||||
this.options = options;
|
||||
this.instrumentation.onBrowserOpen(this);
|
||||
}
|
||||
async newContext(metadata, options) {
|
||||
var _options$clientCertif;
|
||||
(0, _browserContext.validateBrowserContextOptions)(options, this.options);
|
||||
let clientCertificatesProxy;
|
||||
if ((_options$clientCertif = options.clientCertificates) !== null && _options$clientCertif !== void 0 && _options$clientCertif.length) {
|
||||
clientCertificatesProxy = new _socksClientCertificatesInterceptor.ClientCertificatesProxy(options);
|
||||
options = {
|
||||
...options
|
||||
};
|
||||
options.proxyOverride = await clientCertificatesProxy.listen();
|
||||
options.internalIgnoreHTTPSErrors = true;
|
||||
}
|
||||
let context;
|
||||
try {
|
||||
context = await this.doCreateNewContext(options);
|
||||
} catch (error) {
|
||||
var _clientCertificatesPr;
|
||||
await ((_clientCertificatesPr = clientCertificatesProxy) === null || _clientCertificatesPr === void 0 ? void 0 : _clientCertificatesPr.close());
|
||||
throw error;
|
||||
}
|
||||
context._clientCertificatesProxy = clientCertificatesProxy;
|
||||
if (options.storageState) await context.setStorageState(metadata, options.storageState);
|
||||
return context;
|
||||
}
|
||||
async newContextForReuse(params, metadata) {
|
||||
const hash = _browserContext.BrowserContext.reusableContextHash(params);
|
||||
if (!this._contextForReuse || hash !== this._contextForReuse.hash || !this._contextForReuse.context.canResetForReuse()) {
|
||||
if (this._contextForReuse) await this._contextForReuse.context.close({
|
||||
reason: 'Context reused'
|
||||
});
|
||||
this._contextForReuse = {
|
||||
context: await this.newContext(metadata, params),
|
||||
hash
|
||||
};
|
||||
return {
|
||||
context: this._contextForReuse.context,
|
||||
needsReset: false
|
||||
};
|
||||
}
|
||||
await this._contextForReuse.context.stopPendingOperations('Context recreated');
|
||||
return {
|
||||
context: this._contextForReuse.context,
|
||||
needsReset: true
|
||||
};
|
||||
}
|
||||
async stopPendingOperations(reason) {
|
||||
var _this$_contextForReus;
|
||||
await ((_this$_contextForReus = this._contextForReuse) === null || _this$_contextForReus === void 0 || (_this$_contextForReus = _this$_contextForReus.context) === null || _this$_contextForReus === void 0 ? void 0 : _this$_contextForReus.stopPendingOperations(reason));
|
||||
}
|
||||
_downloadCreated(page, uuid, url, suggestedFilename) {
|
||||
const download = new _download.Download(page, this.options.downloadsPath || '', uuid, url, suggestedFilename);
|
||||
this._downloads.set(uuid, download);
|
||||
}
|
||||
_downloadFilenameSuggested(uuid, suggestedFilename) {
|
||||
const download = this._downloads.get(uuid);
|
||||
if (!download) return;
|
||||
download._filenameSuggested(suggestedFilename);
|
||||
}
|
||||
_downloadFinished(uuid, error) {
|
||||
const download = this._downloads.get(uuid);
|
||||
if (!download) return;
|
||||
download.artifact.reportFinished(error ? new Error(error) : undefined);
|
||||
this._downloads.delete(uuid);
|
||||
}
|
||||
_videoStarted(context, videoId, path, pageOrError) {
|
||||
const artifact = new _artifact.Artifact(context, path);
|
||||
this._idToVideo.set(videoId, {
|
||||
context,
|
||||
artifact
|
||||
});
|
||||
pageOrError.then(page => {
|
||||
if (page instanceof _page.Page) {
|
||||
page._video = artifact;
|
||||
page.emitOnContext(_browserContext.BrowserContext.Events.VideoStarted, artifact);
|
||||
page.emit(_page.Page.Events.Video, artifact);
|
||||
}
|
||||
});
|
||||
}
|
||||
_takeVideo(videoId) {
|
||||
const video = this._idToVideo.get(videoId);
|
||||
this._idToVideo.delete(videoId);
|
||||
return video === null || video === void 0 ? void 0 : video.artifact;
|
||||
}
|
||||
_didClose() {
|
||||
for (const context of this.contexts()) context._browserClosed();
|
||||
if (this._defaultContext) this._defaultContext._browserClosed();
|
||||
this.emit(Browser.Events.Disconnected);
|
||||
this.instrumentation.onBrowserClose(this);
|
||||
}
|
||||
async close(options) {
|
||||
if (!this._startedClosing) {
|
||||
if (options.reason) this._closeReason = options.reason;
|
||||
this._startedClosing = true;
|
||||
await this.options.browserProcess.close();
|
||||
}
|
||||
if (this.isConnected()) await new Promise(x => this.once(Browser.Events.Disconnected, x));
|
||||
}
|
||||
async killForTests() {
|
||||
await this.options.browserProcess.kill();
|
||||
}
|
||||
}
|
||||
exports.Browser = Browser;
|
||||
Browser.Events = {
|
||||
Disconnected: 'disconnected'
|
||||
};
|
||||
672
node_modules/playwright-core/lib/server/browserContext.js
generated
vendored
Normal file
672
node_modules/playwright-core/lib/server/browserContext.js
generated
vendored
Normal file
@@ -0,0 +1,672 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.BrowserContext = void 0;
|
||||
exports.assertBrowserContextIsNotOwned = assertBrowserContextIsNotOwned;
|
||||
exports.normalizeProxySettings = normalizeProxySettings;
|
||||
exports.validateBrowserContextOptions = validateBrowserContextOptions;
|
||||
exports.verifyClientCertificates = verifyClientCertificates;
|
||||
exports.verifyGeolocation = verifyGeolocation;
|
||||
var _fs = _interopRequireDefault(require("fs"));
|
||||
var _path = _interopRequireDefault(require("path"));
|
||||
var _timeoutSettings = require("./timeoutSettings");
|
||||
var _crypto = require("./utils/crypto");
|
||||
var _debug = require("./utils/debug");
|
||||
var _clock = require("./clock");
|
||||
var _debugger = require("./debugger");
|
||||
var _fetch = require("./fetch");
|
||||
var _fileUtils = require("./utils/fileUtils");
|
||||
var _harRecorder = require("./har/harRecorder");
|
||||
var _helper = require("./helper");
|
||||
var _instrumentation = require("./instrumentation");
|
||||
var utilityScriptSerializers = _interopRequireWildcard(require("./isomorphic/utilityScriptSerializers"));
|
||||
var network = _interopRequireWildcard(require("./network"));
|
||||
var _page6 = require("./page");
|
||||
var _recorder = require("./recorder");
|
||||
var _recorderApp = require("./recorder/recorderApp");
|
||||
var storageScript = _interopRequireWildcard(require("./storageScript"));
|
||||
var consoleApiSource = _interopRequireWildcard(require("../generated/consoleApiSource"));
|
||||
var _tracing = require("./trace/recorder/tracing");
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class BrowserContext extends _instrumentation.SdkObject {
|
||||
constructor(browser, options, browserContextId) {
|
||||
super(browser, 'browser-context');
|
||||
this._timeoutSettings = new _timeoutSettings.TimeoutSettings();
|
||||
this._pageBindings = new Map();
|
||||
this._activeProgressControllers = new Set();
|
||||
this._options = void 0;
|
||||
this._requestInterceptor = void 0;
|
||||
this._isPersistentContext = void 0;
|
||||
this._closedStatus = 'open';
|
||||
this._closePromise = void 0;
|
||||
this._closePromiseFulfill = void 0;
|
||||
this._permissions = new Map();
|
||||
this._downloads = new Set();
|
||||
this._browser = void 0;
|
||||
this._browserContextId = void 0;
|
||||
this._selectors = void 0;
|
||||
this._origins = new Set();
|
||||
this._harRecorders = new Map();
|
||||
this.tracing = void 0;
|
||||
this.fetchRequest = void 0;
|
||||
this._customCloseHandler = void 0;
|
||||
this._tempDirs = [];
|
||||
this._settingStorageState = false;
|
||||
this.initScripts = [];
|
||||
this._routesInFlight = new Set();
|
||||
this._debugger = void 0;
|
||||
this._closeReason = void 0;
|
||||
this.clock = void 0;
|
||||
this._clientCertificatesProxy = void 0;
|
||||
this.attribution.context = this;
|
||||
this._browser = browser;
|
||||
this._options = options;
|
||||
this._browserContextId = browserContextId;
|
||||
this._isPersistentContext = !browserContextId;
|
||||
this._closePromise = new Promise(fulfill => this._closePromiseFulfill = fulfill);
|
||||
this.fetchRequest = new _fetch.BrowserContextAPIRequestContext(this);
|
||||
if (this._options.recordHar) this._harRecorders.set('', new _harRecorder.HarRecorder(this, null, this._options.recordHar));
|
||||
this.tracing = new _tracing.Tracing(this, browser.options.tracesDir);
|
||||
this.clock = new _clock.Clock(this);
|
||||
}
|
||||
isPersistentContext() {
|
||||
return this._isPersistentContext;
|
||||
}
|
||||
setSelectors(selectors) {
|
||||
this._selectors = selectors;
|
||||
}
|
||||
selectors() {
|
||||
return this._selectors || this.attribution.playwright.selectors;
|
||||
}
|
||||
async _initialize() {
|
||||
if (this.attribution.playwright.options.isInternalPlaywright) return;
|
||||
// Debugger will pause execution upon page.pause in headed mode.
|
||||
this._debugger = new _debugger.Debugger(this);
|
||||
|
||||
// When PWDEBUG=1, show inspector for each context.
|
||||
if ((0, _debug.debugMode)() === 'inspector') await _recorder.Recorder.show(this, _recorderApp.RecorderApp.factory(this), {
|
||||
pauseOnNextStatement: true
|
||||
});
|
||||
|
||||
// When paused, show inspector.
|
||||
if (this._debugger.isPaused()) _recorder.Recorder.showInspectorNoReply(this, _recorderApp.RecorderApp.factory(this));
|
||||
this._debugger.on(_debugger.Debugger.Events.PausedStateChanged, () => {
|
||||
if (this._debugger.isPaused()) _recorder.Recorder.showInspectorNoReply(this, _recorderApp.RecorderApp.factory(this));
|
||||
});
|
||||
if ((0, _debug.debugMode)() === 'console') await this.extendInjectedScript(consoleApiSource.source);
|
||||
if (this._options.serviceWorkers === 'block') await this.addInitScript(`\nif (navigator.serviceWorker) navigator.serviceWorker.register = async () => { console.warn('Service Worker registration blocked by Playwright'); };\n`);
|
||||
if (this._options.permissions) await this.grantPermissions(this._options.permissions);
|
||||
}
|
||||
debugger() {
|
||||
return this._debugger;
|
||||
}
|
||||
async _ensureVideosPath() {
|
||||
if (this._options.recordVideo) await (0, _fileUtils.mkdirIfNeeded)(_path.default.join(this._options.recordVideo.dir, 'dummy'));
|
||||
}
|
||||
canResetForReuse() {
|
||||
if (this._closedStatus !== 'open') return false;
|
||||
return true;
|
||||
}
|
||||
async stopPendingOperations(reason) {
|
||||
// When using context reuse, stop pending operations to gracefully terminate all the actions
|
||||
// with a user-friendly error message containing operation log.
|
||||
for (const controller of this._activeProgressControllers) controller.abort(new Error(reason));
|
||||
// Let rejections in microtask generate events before returning.
|
||||
await new Promise(f => setTimeout(f, 0));
|
||||
}
|
||||
static reusableContextHash(params) {
|
||||
const paramsCopy = {
|
||||
...params
|
||||
};
|
||||
for (const k of Object.keys(paramsCopy)) {
|
||||
const key = k;
|
||||
if (paramsCopy[key] === defaultNewContextParamValues[key]) delete paramsCopy[key];
|
||||
}
|
||||
for (const key of paramsThatAllowContextReuse) delete paramsCopy[key];
|
||||
return JSON.stringify(paramsCopy);
|
||||
}
|
||||
async resetForReuse(metadata, params) {
|
||||
var _page, _page2, _page3, _page4, _page5;
|
||||
this.setDefaultNavigationTimeout(undefined);
|
||||
this.setDefaultTimeout(undefined);
|
||||
this.tracing.resetForReuse();
|
||||
if (params) {
|
||||
for (const key of paramsThatAllowContextReuse) this._options[key] = params[key];
|
||||
}
|
||||
await this._cancelAllRoutesInFlight();
|
||||
|
||||
// Close extra pages early.
|
||||
let page = this.pages()[0];
|
||||
const [, ...otherPages] = this.pages();
|
||||
for (const p of otherPages) await p.close(metadata);
|
||||
if (page && page.hasCrashed()) {
|
||||
await page.close(metadata);
|
||||
page = undefined;
|
||||
}
|
||||
|
||||
// Unless dialogs are dismissed, setting extra http headers below does not respond.
|
||||
(_page = page) === null || _page === void 0 || _page._frameManager.setCloseAllOpeningDialogs(true);
|
||||
await ((_page2 = page) === null || _page2 === void 0 ? void 0 : _page2._frameManager.closeOpenDialogs());
|
||||
// Navigate to about:blank first to ensure no page scripts are running after this point.
|
||||
await ((_page3 = page) === null || _page3 === void 0 ? void 0 : _page3.mainFrame().goto(metadata, 'about:blank', {
|
||||
timeout: 0
|
||||
}));
|
||||
(_page4 = page) === null || _page4 === void 0 || _page4._frameManager.setCloseAllOpeningDialogs(false);
|
||||
await this._resetStorage();
|
||||
await this._removeExposedBindings();
|
||||
await this._removeInitScripts();
|
||||
this.clock.markAsUninstalled();
|
||||
// TODO: following can be optimized to not perform noops.
|
||||
if (this._options.permissions) await this.grantPermissions(this._options.permissions);else await this.clearPermissions();
|
||||
await this.setExtraHTTPHeaders(this._options.extraHTTPHeaders || []);
|
||||
await this.setGeolocation(this._options.geolocation);
|
||||
await this.setOffline(!!this._options.offline);
|
||||
await this.setUserAgent(this._options.userAgent);
|
||||
await this.clearCache();
|
||||
await this._resetCookies();
|
||||
await ((_page5 = page) === null || _page5 === void 0 ? void 0 : _page5.resetForReuse(metadata));
|
||||
}
|
||||
_browserClosed() {
|
||||
for (const page of this.pages()) page._didClose();
|
||||
this._didCloseInternal();
|
||||
}
|
||||
_didCloseInternal() {
|
||||
var _this$_clientCertific;
|
||||
if (this._closedStatus === 'closed') {
|
||||
// We can come here twice if we close browser context and browser
|
||||
// at the same time.
|
||||
return;
|
||||
}
|
||||
(_this$_clientCertific = this._clientCertificatesProxy) === null || _this$_clientCertific === void 0 || _this$_clientCertific.close().catch(() => {});
|
||||
this.tracing.abort();
|
||||
if (this._isPersistentContext) this.onClosePersistent();
|
||||
this._closePromiseFulfill(new Error('Context closed'));
|
||||
this.emit(BrowserContext.Events.Close);
|
||||
}
|
||||
pages() {
|
||||
return this.possiblyUninitializedPages().filter(page => page.initializedOrUndefined());
|
||||
}
|
||||
|
||||
// BrowserContext methods.
|
||||
|
||||
async cookies(urls = []) {
|
||||
if (urls && !Array.isArray(urls)) urls = [urls];
|
||||
return await this.doGetCookies(urls);
|
||||
}
|
||||
async clearCookies(options) {
|
||||
const currentCookies = await this.cookies();
|
||||
await this.doClearCookies();
|
||||
const matches = (cookie, prop, value) => {
|
||||
if (!value) return true;
|
||||
if (value instanceof RegExp) {
|
||||
value.lastIndex = 0;
|
||||
return value.test(cookie[prop]);
|
||||
}
|
||||
return cookie[prop] === value;
|
||||
};
|
||||
const cookiesToReadd = currentCookies.filter(cookie => {
|
||||
return !matches(cookie, 'name', options.name) || !matches(cookie, 'domain', options.domain) || !matches(cookie, 'path', options.path);
|
||||
});
|
||||
await this.addCookies(cookiesToReadd);
|
||||
}
|
||||
setHTTPCredentials(httpCredentials) {
|
||||
return this.doSetHTTPCredentials(httpCredentials);
|
||||
}
|
||||
hasBinding(name) {
|
||||
return this._pageBindings.has(name);
|
||||
}
|
||||
async exposeBinding(name, needsHandle, playwrightBinding) {
|
||||
if (this._pageBindings.has(name)) throw new Error(`Function "${name}" has been already registered`);
|
||||
for (const page of this.pages()) {
|
||||
if (page.getBinding(name)) throw new Error(`Function "${name}" has been already registered in one of the pages`);
|
||||
}
|
||||
const binding = new _page6.PageBinding(name, playwrightBinding, needsHandle);
|
||||
this._pageBindings.set(name, binding);
|
||||
await this.doAddInitScript(binding.initScript);
|
||||
const frames = this.pages().map(page => page.frames()).flat();
|
||||
await Promise.all(frames.map(frame => frame.evaluateExpression(binding.initScript.source).catch(e => {})));
|
||||
}
|
||||
async _removeExposedBindings() {
|
||||
for (const [key, binding] of this._pageBindings) {
|
||||
if (!binding.internal) this._pageBindings.delete(key);
|
||||
}
|
||||
}
|
||||
async grantPermissions(permissions, origin) {
|
||||
let resolvedOrigin = '*';
|
||||
if (origin) {
|
||||
const url = new URL(origin);
|
||||
resolvedOrigin = url.origin;
|
||||
}
|
||||
const existing = new Set(this._permissions.get(resolvedOrigin) || []);
|
||||
permissions.forEach(p => existing.add(p));
|
||||
const list = [...existing.values()];
|
||||
this._permissions.set(resolvedOrigin, list);
|
||||
await this.doGrantPermissions(resolvedOrigin, list);
|
||||
}
|
||||
async clearPermissions() {
|
||||
this._permissions.clear();
|
||||
await this.doClearPermissions();
|
||||
}
|
||||
setDefaultNavigationTimeout(timeout) {
|
||||
this._timeoutSettings.setDefaultNavigationTimeout(timeout);
|
||||
}
|
||||
setDefaultTimeout(timeout) {
|
||||
this._timeoutSettings.setDefaultTimeout(timeout);
|
||||
}
|
||||
async _loadDefaultContextAsIs(progress) {
|
||||
if (!this.possiblyUninitializedPages().length) {
|
||||
const waitForEvent = _helper.helper.waitForEvent(progress, this, BrowserContext.Events.Page);
|
||||
progress.cleanupWhenAborted(() => waitForEvent.dispose);
|
||||
// Race against BrowserContext.close
|
||||
await Promise.race([waitForEvent.promise, this._closePromise]);
|
||||
}
|
||||
const page = this.possiblyUninitializedPages()[0];
|
||||
if (!page) return;
|
||||
const pageOrError = await page.waitForInitializedOrError();
|
||||
if (pageOrError instanceof Error) throw pageOrError;
|
||||
await page.mainFrame()._waitForLoadState(progress, 'load');
|
||||
return page;
|
||||
}
|
||||
async _loadDefaultContext(progress) {
|
||||
const defaultPage = await this._loadDefaultContextAsIs(progress);
|
||||
if (!defaultPage) return;
|
||||
const browserName = this._browser.options.name;
|
||||
if (this._options.isMobile && browserName === 'chromium' || this._options.locale && browserName === 'webkit') {
|
||||
// Workaround for:
|
||||
// - chromium fails to change isMobile for existing page;
|
||||
// - webkit fails to change locale for existing page.
|
||||
await this.newPage(progress.metadata);
|
||||
await defaultPage.close(progress.metadata);
|
||||
}
|
||||
}
|
||||
_authenticateProxyViaHeader() {
|
||||
const proxy = this._options.proxy || this._browser.options.proxy || {
|
||||
username: undefined,
|
||||
password: undefined
|
||||
};
|
||||
const {
|
||||
username,
|
||||
password
|
||||
} = proxy;
|
||||
if (username) {
|
||||
this._options.httpCredentials = {
|
||||
username,
|
||||
password: password
|
||||
};
|
||||
const token = Buffer.from(`${username}:${password}`).toString('base64');
|
||||
this._options.extraHTTPHeaders = network.mergeHeaders([this._options.extraHTTPHeaders, network.singleHeader('Proxy-Authorization', `Basic ${token}`)]);
|
||||
}
|
||||
}
|
||||
_authenticateProxyViaCredentials() {
|
||||
const proxy = this._options.proxy || this._browser.options.proxy;
|
||||
if (!proxy) return;
|
||||
const {
|
||||
username,
|
||||
password
|
||||
} = proxy;
|
||||
if (username) this._options.httpCredentials = {
|
||||
username,
|
||||
password: password || ''
|
||||
};
|
||||
}
|
||||
async addInitScript(source, name) {
|
||||
const initScript = new _page6.InitScript(source, false /* internal */, name);
|
||||
this.initScripts.push(initScript);
|
||||
await this.doAddInitScript(initScript);
|
||||
}
|
||||
async _removeInitScripts() {
|
||||
this.initScripts = this.initScripts.filter(script => script.internal);
|
||||
await this.doRemoveNonInternalInitScripts();
|
||||
}
|
||||
async setRequestInterceptor(handler) {
|
||||
this._requestInterceptor = handler;
|
||||
await this.doUpdateRequestInterception();
|
||||
}
|
||||
isClosingOrClosed() {
|
||||
return this._closedStatus !== 'open';
|
||||
}
|
||||
async _deleteAllDownloads() {
|
||||
await Promise.all(Array.from(this._downloads).map(download => download.artifact.deleteOnContextClose()));
|
||||
}
|
||||
async _deleteAllTempDirs() {
|
||||
await Promise.all(this._tempDirs.map(async dir => await _fs.default.promises.unlink(dir).catch(e => {})));
|
||||
}
|
||||
setCustomCloseHandler(handler) {
|
||||
this._customCloseHandler = handler;
|
||||
}
|
||||
async close(options) {
|
||||
if (this._closedStatus === 'open') {
|
||||
if (options.reason) this._closeReason = options.reason;
|
||||
this.emit(BrowserContext.Events.BeforeClose);
|
||||
this._closedStatus = 'closing';
|
||||
for (const harRecorder of this._harRecorders.values()) await harRecorder.flush();
|
||||
await this.tracing.flush();
|
||||
|
||||
// Cleanup.
|
||||
const promises = [];
|
||||
for (const {
|
||||
context,
|
||||
artifact
|
||||
} of this._browser._idToVideo.values()) {
|
||||
// Wait for the videos to finish.
|
||||
if (context === this) promises.push(artifact.finishedPromise());
|
||||
}
|
||||
if (this._customCloseHandler) {
|
||||
await this._customCloseHandler();
|
||||
} else {
|
||||
// Close the context.
|
||||
await this.doClose(options.reason);
|
||||
}
|
||||
|
||||
// We delete downloads after context closure
|
||||
// so that browser does not write to the download file anymore.
|
||||
promises.push(this._deleteAllDownloads());
|
||||
promises.push(this._deleteAllTempDirs());
|
||||
await Promise.all(promises);
|
||||
|
||||
// Custom handler should trigger didCloseInternal itself.
|
||||
if (!this._customCloseHandler) this._didCloseInternal();
|
||||
}
|
||||
await this._closePromise;
|
||||
}
|
||||
async newPage(metadata) {
|
||||
const page = await this.doCreateNewPage();
|
||||
if (metadata.isServerSide) page.markAsServerSideOnly();
|
||||
const pageOrError = await page.waitForInitializedOrError();
|
||||
if (pageOrError instanceof _page6.Page) {
|
||||
if (pageOrError.isClosed()) throw new Error('Page has been closed.');
|
||||
return pageOrError;
|
||||
}
|
||||
throw pageOrError;
|
||||
}
|
||||
addVisitedOrigin(origin) {
|
||||
this._origins.add(origin);
|
||||
}
|
||||
async storageState(indexedDB = false) {
|
||||
const result = {
|
||||
cookies: await this.cookies(),
|
||||
origins: []
|
||||
};
|
||||
const originsToSave = new Set(this._origins);
|
||||
const collectScript = `(${storageScript.collect})((${utilityScriptSerializers.source})(), ${this._browser.options.name === 'firefox'}, ${indexedDB})`;
|
||||
|
||||
// First try collecting storage stage from existing pages.
|
||||
for (const page of this.pages()) {
|
||||
const origin = page.mainFrame().origin();
|
||||
if (!origin || !originsToSave.has(origin)) continue;
|
||||
try {
|
||||
var _storage$indexedDB;
|
||||
const storage = await page.mainFrame().nonStallingEvaluateInExistingContext(collectScript, 'utility');
|
||||
if (storage.localStorage.length || (_storage$indexedDB = storage.indexedDB) !== null && _storage$indexedDB !== void 0 && _storage$indexedDB.length) result.origins.push({
|
||||
origin,
|
||||
localStorage: storage.localStorage,
|
||||
indexedDB: storage.indexedDB
|
||||
});
|
||||
originsToSave.delete(origin);
|
||||
} catch {
|
||||
// When failed on the live page, we'll retry on the blank page below.
|
||||
}
|
||||
}
|
||||
|
||||
// If there are still origins to save, create a blank page to iterate over origins.
|
||||
if (originsToSave.size) {
|
||||
const internalMetadata = (0, _instrumentation.serverSideCallMetadata)();
|
||||
const page = await this.newPage(internalMetadata);
|
||||
await page._setServerRequestInterceptor(handler => {
|
||||
handler.fulfill({
|
||||
body: '<html></html>'
|
||||
}).catch(() => {});
|
||||
return true;
|
||||
});
|
||||
for (const origin of originsToSave) {
|
||||
var _storage$indexedDB2;
|
||||
const frame = page.mainFrame();
|
||||
await frame.goto(internalMetadata, origin);
|
||||
const storage = await frame.evaluateExpression(collectScript, {
|
||||
world: 'utility'
|
||||
});
|
||||
if (storage.localStorage.length || (_storage$indexedDB2 = storage.indexedDB) !== null && _storage$indexedDB2 !== void 0 && _storage$indexedDB2.length) result.origins.push({
|
||||
origin,
|
||||
localStorage: storage.localStorage,
|
||||
indexedDB: storage.indexedDB
|
||||
});
|
||||
}
|
||||
await page.close(internalMetadata);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
async _resetStorage() {
|
||||
var _this$_options$storag;
|
||||
const oldOrigins = this._origins;
|
||||
const newOrigins = new Map(((_this$_options$storag = this._options.storageState) === null || _this$_options$storag === void 0 || (_this$_options$storag = _this$_options$storag.origins) === null || _this$_options$storag === void 0 ? void 0 : _this$_options$storag.map(p => [p.origin, p])) || []);
|
||||
if (!oldOrigins.size && !newOrigins.size) return;
|
||||
let page = this.pages()[0];
|
||||
const internalMetadata = (0, _instrumentation.serverSideCallMetadata)();
|
||||
page = page || (await this.newPage({
|
||||
...internalMetadata,
|
||||
// Do not mark this page as internal, because we will leave it for later reuse
|
||||
// as a user-visible page.
|
||||
isServerSide: false
|
||||
}));
|
||||
await page._setServerRequestInterceptor(handler => {
|
||||
handler.fulfill({
|
||||
body: '<html></html>'
|
||||
}).catch(() => {});
|
||||
return true;
|
||||
});
|
||||
for (const origin of new Set([...oldOrigins, ...newOrigins.keys()])) {
|
||||
const frame = page.mainFrame();
|
||||
await frame.goto(internalMetadata, origin);
|
||||
await frame.resetStorageForCurrentOriginBestEffort(newOrigins.get(origin));
|
||||
}
|
||||
await page._setServerRequestInterceptor(undefined);
|
||||
this._origins = new Set([...newOrigins.keys()]);
|
||||
// It is safe to not restore the URL to about:blank since we are doing it in Page::resetForReuse.
|
||||
}
|
||||
async _resetCookies() {
|
||||
var _this$_options$storag2, _this$_options$storag3;
|
||||
await this.doClearCookies();
|
||||
if ((_this$_options$storag2 = this._options.storageState) !== null && _this$_options$storag2 !== void 0 && _this$_options$storag2.cookies) await this.addCookies((_this$_options$storag3 = this._options.storageState) === null || _this$_options$storag3 === void 0 ? void 0 : _this$_options$storag3.cookies);
|
||||
}
|
||||
isSettingStorageState() {
|
||||
return this._settingStorageState;
|
||||
}
|
||||
async setStorageState(metadata, state) {
|
||||
this._settingStorageState = true;
|
||||
try {
|
||||
if (state.cookies) await this.addCookies(state.cookies);
|
||||
if (state.origins && state.origins.length) {
|
||||
const internalMetadata = (0, _instrumentation.serverSideCallMetadata)();
|
||||
const page = await this.newPage(internalMetadata);
|
||||
await page._setServerRequestInterceptor(handler => {
|
||||
handler.fulfill({
|
||||
body: '<html></html>'
|
||||
}).catch(() => {});
|
||||
return true;
|
||||
});
|
||||
for (const originState of state.origins) {
|
||||
const frame = page.mainFrame();
|
||||
await frame.goto(metadata, originState.origin);
|
||||
await frame.evaluateExpression(`(${storageScript.restore})(${JSON.stringify(originState)}, (${utilityScriptSerializers.source})())`, {
|
||||
world: 'utility'
|
||||
});
|
||||
}
|
||||
await page.close(internalMetadata);
|
||||
}
|
||||
} finally {
|
||||
this._settingStorageState = false;
|
||||
}
|
||||
}
|
||||
async extendInjectedScript(source, arg) {
|
||||
const installInFrame = frame => frame.extendInjectedScript(source, arg).catch(() => {});
|
||||
const installInPage = page => {
|
||||
page.on(_page6.Page.Events.InternalFrameNavigatedToNewDocument, installInFrame);
|
||||
return Promise.all(page.frames().map(installInFrame));
|
||||
};
|
||||
this.on(BrowserContext.Events.Page, installInPage);
|
||||
return Promise.all(this.pages().map(installInPage));
|
||||
}
|
||||
async safeNonStallingEvaluateInAllFrames(expression, world, options = {}) {
|
||||
await Promise.all(this.pages().map(page => page.safeNonStallingEvaluateInAllFrames(expression, world, options)));
|
||||
}
|
||||
async _harStart(page, options) {
|
||||
const harId = (0, _crypto.createGuid)();
|
||||
this._harRecorders.set(harId, new _harRecorder.HarRecorder(this, page, options));
|
||||
return harId;
|
||||
}
|
||||
async _harExport(harId) {
|
||||
const recorder = this._harRecorders.get(harId || '');
|
||||
return recorder.export();
|
||||
}
|
||||
addRouteInFlight(route) {
|
||||
this._routesInFlight.add(route);
|
||||
}
|
||||
removeRouteInFlight(route) {
|
||||
this._routesInFlight.delete(route);
|
||||
}
|
||||
async _cancelAllRoutesInFlight() {
|
||||
await Promise.all([...this._routesInFlight].map(r => r.abort())).catch(() => {});
|
||||
this._routesInFlight.clear();
|
||||
}
|
||||
}
|
||||
exports.BrowserContext = BrowserContext;
|
||||
BrowserContext.Events = {
|
||||
Console: 'console',
|
||||
Close: 'close',
|
||||
Dialog: 'dialog',
|
||||
Page: 'page',
|
||||
// Can't use just 'error' due to node.js special treatment of error events.
|
||||
// @see https://nodejs.org/api/events.html#events_error_events
|
||||
PageError: 'pageerror',
|
||||
Request: 'request',
|
||||
Response: 'response',
|
||||
RequestFailed: 'requestfailed',
|
||||
RequestFinished: 'requestfinished',
|
||||
RequestAborted: 'requestaborted',
|
||||
RequestFulfilled: 'requestfulfilled',
|
||||
RequestContinued: 'requestcontinued',
|
||||
BeforeClose: 'beforeclose',
|
||||
VideoStarted: 'videostarted'
|
||||
};
|
||||
function assertBrowserContextIsNotOwned(context) {
|
||||
for (const page of context.pages()) {
|
||||
if (page._ownedContext) throw new Error('Please use browser.newContext() for multi-page scripts that share the context.');
|
||||
}
|
||||
}
|
||||
function validateBrowserContextOptions(options, browserOptions) {
|
||||
if (options.noDefaultViewport && options.deviceScaleFactor !== undefined) throw new Error(`"deviceScaleFactor" option is not supported with null "viewport"`);
|
||||
if (options.noDefaultViewport && !!options.isMobile) throw new Error(`"isMobile" option is not supported with null "viewport"`);
|
||||
if (options.acceptDownloads === undefined && browserOptions.name !== 'electron') options.acceptDownloads = 'accept';
|
||||
// Electron requires explicit acceptDownloads: true since we wait for
|
||||
// https://github.com/electron/electron/pull/41718 to be widely shipped.
|
||||
// In 6-12 months, we can remove this check.
|
||||
else if (options.acceptDownloads === undefined && browserOptions.name === 'electron') options.acceptDownloads = 'internal-browser-default';
|
||||
if (!options.viewport && !options.noDefaultViewport) options.viewport = {
|
||||
width: 1280,
|
||||
height: 720
|
||||
};
|
||||
if (options.recordVideo) {
|
||||
if (!options.recordVideo.size) {
|
||||
if (options.noDefaultViewport) {
|
||||
options.recordVideo.size = {
|
||||
width: 800,
|
||||
height: 600
|
||||
};
|
||||
} else {
|
||||
const size = options.viewport;
|
||||
const scale = Math.min(1, 800 / Math.max(size.width, size.height));
|
||||
options.recordVideo.size = {
|
||||
width: Math.floor(size.width * scale),
|
||||
height: Math.floor(size.height * scale)
|
||||
};
|
||||
}
|
||||
}
|
||||
// Make sure both dimensions are odd, this is required for vp8
|
||||
options.recordVideo.size.width &= ~1;
|
||||
options.recordVideo.size.height &= ~1;
|
||||
}
|
||||
if (options.proxy) options.proxy = normalizeProxySettings(options.proxy);
|
||||
verifyGeolocation(options.geolocation);
|
||||
}
|
||||
function verifyGeolocation(geolocation) {
|
||||
if (!geolocation) return;
|
||||
geolocation.accuracy = geolocation.accuracy || 0;
|
||||
const {
|
||||
longitude,
|
||||
latitude,
|
||||
accuracy
|
||||
} = geolocation;
|
||||
if (longitude < -180 || longitude > 180) throw new Error(`geolocation.longitude: precondition -180 <= LONGITUDE <= 180 failed.`);
|
||||
if (latitude < -90 || latitude > 90) throw new Error(`geolocation.latitude: precondition -90 <= LATITUDE <= 90 failed.`);
|
||||
if (accuracy < 0) throw new Error(`geolocation.accuracy: precondition 0 <= ACCURACY failed.`);
|
||||
}
|
||||
function verifyClientCertificates(clientCertificates) {
|
||||
if (!clientCertificates) return;
|
||||
for (const cert of clientCertificates) {
|
||||
if (!cert.origin) throw new Error(`clientCertificates.origin is required`);
|
||||
if (!cert.cert && !cert.key && !cert.passphrase && !cert.pfx) throw new Error('None of cert, key, passphrase or pfx is specified');
|
||||
if (cert.cert && !cert.key) throw new Error('cert is specified without key');
|
||||
if (!cert.cert && cert.key) throw new Error('key is specified without cert');
|
||||
if (cert.pfx && (cert.cert || cert.key)) throw new Error('pfx is specified together with cert, key or passphrase');
|
||||
}
|
||||
}
|
||||
function normalizeProxySettings(proxy) {
|
||||
let {
|
||||
server,
|
||||
bypass
|
||||
} = proxy;
|
||||
let url;
|
||||
try {
|
||||
// new URL('127.0.0.1:8080') throws
|
||||
// new URL('localhost:8080') fails to parse host or protocol
|
||||
// In both of these cases, we need to try re-parse URL with `http://` prefix.
|
||||
url = new URL(server);
|
||||
if (!url.host || !url.protocol) url = new URL('http://' + server);
|
||||
} catch (e) {
|
||||
url = new URL('http://' + server);
|
||||
}
|
||||
if (url.protocol === 'socks4:' && (proxy.username || proxy.password)) throw new Error(`Socks4 proxy protocol does not support authentication`);
|
||||
if (url.protocol === 'socks5:' && (proxy.username || proxy.password)) throw new Error(`Browser does not support socks5 proxy authentication`);
|
||||
server = url.protocol + '//' + url.host;
|
||||
if (bypass) bypass = bypass.split(',').map(t => t.trim()).join(',');
|
||||
return {
|
||||
...proxy,
|
||||
server,
|
||||
bypass
|
||||
};
|
||||
}
|
||||
const paramsThatAllowContextReuse = ['colorScheme', 'forcedColors', 'reducedMotion', 'contrast', 'screen', 'userAgent', 'viewport'];
|
||||
const defaultNewContextParamValues = {
|
||||
noDefaultViewport: false,
|
||||
ignoreHTTPSErrors: false,
|
||||
javaScriptEnabled: true,
|
||||
bypassCSP: false,
|
||||
offline: false,
|
||||
isMobile: false,
|
||||
hasTouch: false,
|
||||
acceptDownloads: 'accept',
|
||||
strictSelectors: false,
|
||||
serviceWorkers: 'allow',
|
||||
locale: 'en-US'
|
||||
};
|
||||
339
node_modules/playwright-core/lib/server/browserType.js
generated
vendored
Normal file
339
node_modules/playwright-core/lib/server/browserType.js
generated
vendored
Normal file
@@ -0,0 +1,339 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.kNoXServerRunningError = exports.BrowserType = exports.BrowserReadyState = void 0;
|
||||
var _fs = _interopRequireDefault(require("fs"));
|
||||
var _os = _interopRequireDefault(require("os"));
|
||||
var _path = _interopRequireDefault(require("path"));
|
||||
var _browserContext = require("./browserContext");
|
||||
var _timeoutSettings = require("./timeoutSettings");
|
||||
var _debug = require("./utils/debug");
|
||||
var _assert = require("../utils/isomorphic/assert");
|
||||
var _manualPromise = require("../utils/isomorphic/manualPromise");
|
||||
var _fileUtils = require("./utils/fileUtils");
|
||||
var _helper = require("./helper");
|
||||
var _instrumentation = require("./instrumentation");
|
||||
var _pipeTransport = require("./pipeTransport");
|
||||
var _processLauncher = require("./utils/processLauncher");
|
||||
var _progress = require("./progress");
|
||||
var _protocolError = require("./protocolError");
|
||||
var _registry = require("./registry");
|
||||
var _socksClientCertificatesInterceptor = require("./socksClientCertificatesInterceptor");
|
||||
var _transport = require("./transport");
|
||||
var _debugLogger = require("./utils/debugLogger");
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const kNoXServerRunningError = exports.kNoXServerRunningError = 'Looks like you launched a headed browser without having a XServer running.\n' + 'Set either \'headless: true\' or use \'xvfb-run <your-playwright-app>\' before running Playwright.\n\n<3 Playwright Team';
|
||||
class BrowserReadyState {
|
||||
constructor() {
|
||||
this._wsEndpoint = new _manualPromise.ManualPromise();
|
||||
}
|
||||
onBrowserExit() {
|
||||
// Unblock launch when browser prematurely exits.
|
||||
this._wsEndpoint.resolve(undefined);
|
||||
}
|
||||
async waitUntilReady() {
|
||||
const wsEndpoint = await this._wsEndpoint;
|
||||
return {
|
||||
wsEndpoint
|
||||
};
|
||||
}
|
||||
}
|
||||
exports.BrowserReadyState = BrowserReadyState;
|
||||
class BrowserType extends _instrumentation.SdkObject {
|
||||
constructor(parent, browserName) {
|
||||
super(parent, 'browser-type');
|
||||
this._name = void 0;
|
||||
this._useBidi = false;
|
||||
this.attribution.browserType = this;
|
||||
this._name = browserName;
|
||||
}
|
||||
executablePath() {
|
||||
return _registry.registry.findExecutable(this._name).executablePath(this.attribution.playwright.options.sdkLanguage) || '';
|
||||
}
|
||||
name() {
|
||||
return this._name;
|
||||
}
|
||||
async launch(metadata, options, protocolLogger) {
|
||||
options = this._validateLaunchOptions(options);
|
||||
if (this._useBidi) options.useWebSocket = true;
|
||||
const controller = new _progress.ProgressController(metadata, this);
|
||||
controller.setLogName('browser');
|
||||
const browser = await controller.run(progress => {
|
||||
const seleniumHubUrl = options.__testHookSeleniumRemoteURL || process.env.SELENIUM_REMOTE_URL;
|
||||
if (seleniumHubUrl) return this._launchWithSeleniumHub(progress, seleniumHubUrl, options);
|
||||
return this._innerLaunchWithRetries(progress, options, undefined, _helper.helper.debugProtocolLogger(protocolLogger)).catch(e => {
|
||||
throw this._rewriteStartupLog(e);
|
||||
});
|
||||
}, _timeoutSettings.TimeoutSettings.launchTimeout(options));
|
||||
return browser;
|
||||
}
|
||||
async launchPersistentContext(metadata, userDataDir, options) {
|
||||
const launchOptions = this._validateLaunchOptions(options);
|
||||
if (this._useBidi) launchOptions.useWebSocket = true;
|
||||
const controller = new _progress.ProgressController(metadata, this);
|
||||
controller.setLogName('browser');
|
||||
const browser = await controller.run(async progress => {
|
||||
var _options$clientCertif;
|
||||
// Note: Any initial TLS requests will fail since we rely on the Page/Frames initialize which sets ignoreHTTPSErrors.
|
||||
let clientCertificatesProxy;
|
||||
if ((_options$clientCertif = options.clientCertificates) !== null && _options$clientCertif !== void 0 && _options$clientCertif.length) {
|
||||
var _clientCertificatesPr;
|
||||
clientCertificatesProxy = new _socksClientCertificatesInterceptor.ClientCertificatesProxy(options);
|
||||
launchOptions.proxyOverride = await ((_clientCertificatesPr = clientCertificatesProxy) === null || _clientCertificatesPr === void 0 ? void 0 : _clientCertificatesPr.listen());
|
||||
options = {
|
||||
...options
|
||||
};
|
||||
options.internalIgnoreHTTPSErrors = true;
|
||||
}
|
||||
progress.cleanupWhenAborted(() => {
|
||||
var _clientCertificatesPr2;
|
||||
return (_clientCertificatesPr2 = clientCertificatesProxy) === null || _clientCertificatesPr2 === void 0 ? void 0 : _clientCertificatesPr2.close();
|
||||
});
|
||||
const browser = await this._innerLaunchWithRetries(progress, launchOptions, options, _helper.helper.debugProtocolLogger(), userDataDir).catch(e => {
|
||||
throw this._rewriteStartupLog(e);
|
||||
});
|
||||
browser._defaultContext._clientCertificatesProxy = clientCertificatesProxy;
|
||||
return browser;
|
||||
}, _timeoutSettings.TimeoutSettings.launchTimeout(launchOptions));
|
||||
return browser._defaultContext;
|
||||
}
|
||||
async _innerLaunchWithRetries(progress, options, persistent, protocolLogger, userDataDir) {
|
||||
try {
|
||||
return await this._innerLaunch(progress, options, persistent, protocolLogger, userDataDir);
|
||||
} catch (error) {
|
||||
// @see https://github.com/microsoft/playwright/issues/5214
|
||||
const errorMessage = typeof error === 'object' && typeof error.message === 'string' ? error.message : '';
|
||||
if (errorMessage.includes('Inconsistency detected by ld.so')) {
|
||||
progress.log(`<restarting browser due to hitting race condition in glibc>`);
|
||||
return this._innerLaunch(progress, options, persistent, protocolLogger, userDataDir);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async _innerLaunch(progress, options, persistent, protocolLogger, maybeUserDataDir) {
|
||||
options.proxy = options.proxy ? (0, _browserContext.normalizeProxySettings)(options.proxy) : undefined;
|
||||
const browserLogsCollector = new _debugLogger.RecentLogsCollector();
|
||||
const {
|
||||
browserProcess,
|
||||
userDataDir,
|
||||
artifactsDir,
|
||||
transport
|
||||
} = await this._launchProcess(progress, options, !!persistent, browserLogsCollector, maybeUserDataDir);
|
||||
if (options.__testHookBeforeCreateBrowser) await options.__testHookBeforeCreateBrowser();
|
||||
const browserOptions = {
|
||||
name: this._name,
|
||||
isChromium: this._name === 'chromium',
|
||||
channel: options.channel,
|
||||
slowMo: options.slowMo,
|
||||
persistent,
|
||||
headful: !options.headless,
|
||||
artifactsDir,
|
||||
downloadsPath: options.downloadsPath || artifactsDir,
|
||||
tracesDir: options.tracesDir || artifactsDir,
|
||||
browserProcess,
|
||||
customExecutablePath: options.executablePath,
|
||||
proxy: options.proxy,
|
||||
protocolLogger,
|
||||
browserLogsCollector,
|
||||
wsEndpoint: options.useWebSocket ? transport.wsEndpoint : undefined,
|
||||
originalLaunchOptions: options
|
||||
};
|
||||
if (persistent) (0, _browserContext.validateBrowserContextOptions)(persistent, browserOptions);
|
||||
copyTestHooks(options, browserOptions);
|
||||
const browser = await this.connectToTransport(transport, browserOptions);
|
||||
browser._userDataDirForTest = userDataDir;
|
||||
// We assume no control when using custom arguments, and do not prepare the default context in that case.
|
||||
if (persistent && !options.ignoreAllDefaultArgs) await browser._defaultContext._loadDefaultContext(progress);
|
||||
return browser;
|
||||
}
|
||||
async _launchProcess(progress, options, isPersistent, browserLogsCollector, userDataDir) {
|
||||
var _await$readyState$wai;
|
||||
const {
|
||||
ignoreDefaultArgs,
|
||||
ignoreAllDefaultArgs,
|
||||
args = [],
|
||||
executablePath = null,
|
||||
handleSIGINT = true,
|
||||
handleSIGTERM = true,
|
||||
handleSIGHUP = true
|
||||
} = options;
|
||||
const env = options.env ? (0, _processLauncher.envArrayToObject)(options.env) : process.env;
|
||||
await this._createArtifactDirs(options);
|
||||
const tempDirectories = [];
|
||||
const artifactsDir = await _fs.default.promises.mkdtemp(_path.default.join(_os.default.tmpdir(), 'playwright-artifacts-'));
|
||||
tempDirectories.push(artifactsDir);
|
||||
if (userDataDir) {
|
||||
(0, _assert.assert)(_path.default.isAbsolute(userDataDir), 'userDataDir must be an absolute path');
|
||||
// Firefox bails if the profile directory does not exist, Chrome creates it. We ensure consistent behavior here.
|
||||
if (!(await (0, _fileUtils.existsAsync)(userDataDir))) await _fs.default.promises.mkdir(userDataDir, {
|
||||
recursive: true,
|
||||
mode: 0o700
|
||||
});
|
||||
} else {
|
||||
userDataDir = await _fs.default.promises.mkdtemp(_path.default.join(_os.default.tmpdir(), `playwright_${this._name}dev_profile-`));
|
||||
tempDirectories.push(userDataDir);
|
||||
}
|
||||
await this.prepareUserDataDir(options, userDataDir);
|
||||
const browserArguments = [];
|
||||
if (ignoreAllDefaultArgs) browserArguments.push(...args);else if (ignoreDefaultArgs) browserArguments.push(...this.defaultArgs(options, isPersistent, userDataDir).filter(arg => ignoreDefaultArgs.indexOf(arg) === -1));else browserArguments.push(...this.defaultArgs(options, isPersistent, userDataDir));
|
||||
let executable;
|
||||
if (executablePath) {
|
||||
if (!(await (0, _fileUtils.existsAsync)(executablePath))) throw new Error(`Failed to launch ${this._name} because executable doesn't exist at ${executablePath}`);
|
||||
executable = executablePath;
|
||||
} else {
|
||||
const registryExecutable = _registry.registry.findExecutable(this.getExecutableName(options));
|
||||
if (!registryExecutable || registryExecutable.browserName !== this._name) throw new Error(`Unsupported ${this._name} channel "${options.channel}"`);
|
||||
executable = registryExecutable.executablePathOrDie(this.attribution.playwright.options.sdkLanguage);
|
||||
await _registry.registry.validateHostRequirementsForExecutablesIfNeeded([registryExecutable], this.attribution.playwright.options.sdkLanguage);
|
||||
}
|
||||
const readyState = this.readyState(options);
|
||||
// Note: it is important to define these variables before launchProcess, so that we don't get
|
||||
// "Cannot access 'browserServer' before initialization" if something went wrong.
|
||||
let transport = undefined;
|
||||
let browserProcess = undefined;
|
||||
const {
|
||||
launchedProcess,
|
||||
gracefullyClose,
|
||||
kill
|
||||
} = await (0, _processLauncher.launchProcess)({
|
||||
command: executable,
|
||||
args: browserArguments,
|
||||
env: this.amendEnvironment(env, userDataDir, executable, browserArguments),
|
||||
handleSIGINT,
|
||||
handleSIGTERM,
|
||||
handleSIGHUP,
|
||||
log: message => {
|
||||
readyState === null || readyState === void 0 || readyState.onBrowserOutput(message);
|
||||
progress.log(message);
|
||||
browserLogsCollector.log(message);
|
||||
},
|
||||
stdio: 'pipe',
|
||||
tempDirectories,
|
||||
attemptToGracefullyClose: async () => {
|
||||
if (options.__testHookGracefullyClose) await options.__testHookGracefullyClose();
|
||||
// We try to gracefully close to prevent crash reporting and core dumps.
|
||||
// Note that it's fine to reuse the pipe transport, since
|
||||
// our connection ignores kBrowserCloseMessageId.
|
||||
this.attemptToGracefullyCloseBrowser(transport);
|
||||
},
|
||||
onExit: (exitCode, signal) => {
|
||||
// Unblock launch when browser prematurely exits.
|
||||
readyState === null || readyState === void 0 || readyState.onBrowserExit();
|
||||
if (browserProcess && browserProcess.onclose) browserProcess.onclose(exitCode, signal);
|
||||
}
|
||||
});
|
||||
async function closeOrKill(timeout) {
|
||||
let timer;
|
||||
try {
|
||||
await Promise.race([gracefullyClose(), new Promise((resolve, reject) => timer = setTimeout(reject, timeout))]);
|
||||
} catch (ignored) {
|
||||
await kill().catch(ignored => {}); // Make sure to await actual process exit.
|
||||
} finally {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
}
|
||||
browserProcess = {
|
||||
onclose: undefined,
|
||||
process: launchedProcess,
|
||||
close: () => closeOrKill(options.__testHookBrowserCloseTimeout || _timeoutSettings.DEFAULT_TIMEOUT),
|
||||
kill
|
||||
};
|
||||
progress.cleanupWhenAborted(() => closeOrKill(progress.timeUntilDeadline()));
|
||||
const wsEndpoint = (_await$readyState$wai = await (readyState === null || readyState === void 0 ? void 0 : readyState.waitUntilReady())) === null || _await$readyState$wai === void 0 ? void 0 : _await$readyState$wai.wsEndpoint;
|
||||
if (options.useWebSocket) {
|
||||
transport = await _transport.WebSocketTransport.connect(progress, wsEndpoint);
|
||||
} else {
|
||||
const stdio = launchedProcess.stdio;
|
||||
transport = new _pipeTransport.PipeTransport(stdio[3], stdio[4]);
|
||||
}
|
||||
return {
|
||||
browserProcess,
|
||||
artifactsDir,
|
||||
userDataDir,
|
||||
transport
|
||||
};
|
||||
}
|
||||
async _createArtifactDirs(options) {
|
||||
if (options.downloadsPath) await _fs.default.promises.mkdir(options.downloadsPath, {
|
||||
recursive: true
|
||||
});
|
||||
if (options.tracesDir) await _fs.default.promises.mkdir(options.tracesDir, {
|
||||
recursive: true
|
||||
});
|
||||
}
|
||||
async connectOverCDP(metadata, endpointURL, options, timeout) {
|
||||
throw new Error('CDP connections are only supported by Chromium');
|
||||
}
|
||||
async _launchWithSeleniumHub(progress, hubUrl, options) {
|
||||
throw new Error('Connecting to SELENIUM_REMOTE_URL is only supported by Chromium');
|
||||
}
|
||||
_validateLaunchOptions(options) {
|
||||
const {
|
||||
devtools = false
|
||||
} = options;
|
||||
let {
|
||||
headless = !devtools,
|
||||
downloadsPath,
|
||||
proxy
|
||||
} = options;
|
||||
if ((0, _debug.debugMode)()) headless = false;
|
||||
if (downloadsPath && !_path.default.isAbsolute(downloadsPath)) downloadsPath = _path.default.join(process.cwd(), downloadsPath);
|
||||
if (this.attribution.playwright.options.socksProxyPort) proxy = {
|
||||
server: `socks5://127.0.0.1:${this.attribution.playwright.options.socksProxyPort}`
|
||||
};
|
||||
return {
|
||||
...options,
|
||||
devtools,
|
||||
headless,
|
||||
downloadsPath,
|
||||
proxy
|
||||
};
|
||||
}
|
||||
_createUserDataDirArgMisuseError(userDataDirArg) {
|
||||
switch (this.attribution.playwright.options.sdkLanguage) {
|
||||
case 'java':
|
||||
return new Error(`Pass userDataDir parameter to 'BrowserType.launchPersistentContext(userDataDir, options)' instead of specifying '${userDataDirArg}' argument`);
|
||||
case 'python':
|
||||
return new Error(`Pass user_data_dir parameter to 'browser_type.launch_persistent_context(user_data_dir, **kwargs)' instead of specifying '${userDataDirArg}' argument`);
|
||||
case 'csharp':
|
||||
return new Error(`Pass userDataDir parameter to 'BrowserType.LaunchPersistentContextAsync(userDataDir, options)' instead of specifying '${userDataDirArg}' argument`);
|
||||
default:
|
||||
return new Error(`Pass userDataDir parameter to 'browserType.launchPersistentContext(userDataDir, options)' instead of specifying '${userDataDirArg}' argument`);
|
||||
}
|
||||
}
|
||||
_rewriteStartupLog(error) {
|
||||
if (!(0, _protocolError.isProtocolError)(error)) return error;
|
||||
return this.doRewriteStartupLog(error);
|
||||
}
|
||||
readyState(options) {
|
||||
return undefined;
|
||||
}
|
||||
async prepareUserDataDir(options, userDataDir) {}
|
||||
getExecutableName(options) {
|
||||
return options.channel || this._name;
|
||||
}
|
||||
}
|
||||
exports.BrowserType = BrowserType;
|
||||
function copyTestHooks(from, to) {
|
||||
for (const [key, value] of Object.entries(from)) {
|
||||
if (key.startsWith('__testHook')) to[key] = value;
|
||||
}
|
||||
}
|
||||
79
node_modules/playwright-core/lib/server/callLog.js
generated
vendored
Normal file
79
node_modules/playwright-core/lib/server/callLog.js
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.compressCallLog = compressCallLog;
|
||||
exports.findRepeatedSubsequencesForTest = void 0;
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
function compressCallLog(log) {
|
||||
const lines = [];
|
||||
for (const block of findRepeatedSubsequences(log)) {
|
||||
for (let i = 0; i < block.sequence.length; i++) {
|
||||
const line = block.sequence[i];
|
||||
const leadingWhitespace = line.match(/^\s*/);
|
||||
const whitespacePrefix = ' ' + (leadingWhitespace === null || leadingWhitespace === void 0 ? void 0 : leadingWhitespace[0]) || '';
|
||||
const countPrefix = `${block.count} × `;
|
||||
if (block.count > 1 && i === 0) lines.push(whitespacePrefix + countPrefix + line.trim());else if (block.count > 1) lines.push(whitespacePrefix + ' '.repeat(countPrefix.length - 2) + '- ' + line.trim());else lines.push(whitespacePrefix + '- ' + line.trim());
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
function findRepeatedSubsequences(s) {
|
||||
const n = s.length;
|
||||
const result = [];
|
||||
let i = 0;
|
||||
const arraysEqual = (a1, a2) => {
|
||||
if (a1.length !== a2.length) return false;
|
||||
for (let j = 0; j < a1.length; j++) {
|
||||
if (a1[j] !== a2[j]) return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
while (i < n) {
|
||||
let maxRepeatCount = 1;
|
||||
let maxRepeatSubstr = [s[i]]; // Initialize with the element at index i
|
||||
let maxRepeatLength = 1;
|
||||
|
||||
// Try substrings of length from 1 to the remaining length of the array
|
||||
for (let p = 1; p <= n - i; p++) {
|
||||
const substr = s.slice(i, i + p); // Extract substring as array
|
||||
let k = 1;
|
||||
|
||||
// Count how many times the substring repeats consecutively
|
||||
while (i + p * k <= n && arraysEqual(s.slice(i + p * (k - 1), i + p * k), substr)) k += 1;
|
||||
k -= 1; // Adjust k since it increments one extra time in the loop
|
||||
|
||||
// Update the maximal repeating substring if necessary
|
||||
if (k > 1 && k * p > maxRepeatCount * maxRepeatLength) {
|
||||
maxRepeatCount = k;
|
||||
maxRepeatSubstr = substr;
|
||||
maxRepeatLength = p;
|
||||
}
|
||||
}
|
||||
|
||||
// Record the substring and its count
|
||||
result.push({
|
||||
sequence: maxRepeatSubstr,
|
||||
count: maxRepeatCount
|
||||
});
|
||||
i += maxRepeatLength * maxRepeatCount; // Move index forward
|
||||
}
|
||||
return result;
|
||||
}
|
||||
const findRepeatedSubsequencesForTest = exports.findRepeatedSubsequencesForTest = findRepeatedSubsequences;
|
||||
BIN
node_modules/playwright-core/lib/server/chromium/appIcon.png
generated
vendored
Normal file
BIN
node_modules/playwright-core/lib/server/chromium/appIcon.png
generated
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
354
node_modules/playwright-core/lib/server/chromium/chromium.js
generated
vendored
Normal file
354
node_modules/playwright-core/lib/server/chromium/chromium.js
generated
vendored
Normal file
@@ -0,0 +1,354 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.Chromium = void 0;
|
||||
var _fs = _interopRequireDefault(require("fs"));
|
||||
var _os = _interopRequireDefault(require("os"));
|
||||
var _path = _interopRequireDefault(require("path"));
|
||||
var _chromiumSwitches = require("./chromiumSwitches");
|
||||
var _crBrowser = require("./crBrowser");
|
||||
var _crConnection = require("./crConnection");
|
||||
var _timeoutSettings = require("../timeoutSettings");
|
||||
var _utils = require("../../utils");
|
||||
var _ascii = require("../utils/ascii");
|
||||
var _debugLogger = require("../utils/debugLogger");
|
||||
var _manualPromise = require("../../utils/isomorphic/manualPromise");
|
||||
var _network = require("../utils/network");
|
||||
var _userAgent = require("../utils/userAgent");
|
||||
var _browserContext = require("../browserContext");
|
||||
var _browserType = require("../browserType");
|
||||
var _helper = require("../helper");
|
||||
var _registry = require("../registry");
|
||||
var _transport = require("../transport");
|
||||
var _crDevTools = require("./crDevTools");
|
||||
var _browser = require("../browser");
|
||||
var _fileUtils = require("../utils/fileUtils");
|
||||
var _processLauncher = require("../utils/processLauncher");
|
||||
var _progress = require("../progress");
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const ARTIFACTS_FOLDER = _path.default.join(_os.default.tmpdir(), 'playwright-artifacts-');
|
||||
class Chromium extends _browserType.BrowserType {
|
||||
constructor(parent) {
|
||||
super(parent, 'chromium');
|
||||
this._devtools = void 0;
|
||||
if ((0, _utils.debugMode)()) this._devtools = this._createDevTools();
|
||||
}
|
||||
async connectOverCDP(metadata, endpointURL, options, timeout) {
|
||||
const controller = new _progress.ProgressController(metadata, this);
|
||||
controller.setLogName('browser');
|
||||
return controller.run(async progress => {
|
||||
return await this._connectOverCDPInternal(progress, endpointURL, options);
|
||||
}, _timeoutSettings.TimeoutSettings.timeout({
|
||||
timeout
|
||||
}));
|
||||
}
|
||||
async _connectOverCDPInternal(progress, endpointURL, options, onClose) {
|
||||
let headersMap;
|
||||
if (options.headers) headersMap = (0, _utils.headersArrayToObject)(options.headers, false);
|
||||
if (!headersMap) headersMap = {
|
||||
'User-Agent': (0, _userAgent.getUserAgent)()
|
||||
};else if (headersMap && !Object.keys(headersMap).some(key => key.toLowerCase() === 'user-agent')) headersMap['User-Agent'] = (0, _userAgent.getUserAgent)();
|
||||
const artifactsDir = await _fs.default.promises.mkdtemp(ARTIFACTS_FOLDER);
|
||||
const wsEndpoint = await urlToWSEndpoint(progress, endpointURL, headersMap);
|
||||
progress.throwIfAborted();
|
||||
const chromeTransport = await _transport.WebSocketTransport.connect(progress, wsEndpoint, headersMap);
|
||||
const cleanedUp = new _manualPromise.ManualPromise();
|
||||
const doCleanup = async () => {
|
||||
await (0, _fileUtils.removeFolders)([artifactsDir]);
|
||||
await (onClose === null || onClose === void 0 ? void 0 : onClose());
|
||||
cleanedUp.resolve();
|
||||
};
|
||||
const doClose = async () => {
|
||||
await chromeTransport.closeAndWait();
|
||||
await cleanedUp;
|
||||
};
|
||||
const browserProcess = {
|
||||
close: doClose,
|
||||
kill: doClose
|
||||
};
|
||||
const persistent = {
|
||||
noDefaultViewport: true
|
||||
};
|
||||
const browserOptions = {
|
||||
slowMo: options.slowMo,
|
||||
name: 'chromium',
|
||||
isChromium: true,
|
||||
persistent,
|
||||
browserProcess,
|
||||
protocolLogger: _helper.helper.debugProtocolLogger(),
|
||||
browserLogsCollector: new _debugLogger.RecentLogsCollector(),
|
||||
artifactsDir,
|
||||
downloadsPath: options.downloadsPath || artifactsDir,
|
||||
tracesDir: options.tracesDir || artifactsDir,
|
||||
originalLaunchOptions: {}
|
||||
};
|
||||
(0, _browserContext.validateBrowserContextOptions)(persistent, browserOptions);
|
||||
progress.throwIfAborted();
|
||||
const browser = await _crBrowser.CRBrowser.connect(this.attribution.playwright, chromeTransport, browserOptions);
|
||||
browser._isCollocatedWithServer = false;
|
||||
browser.on(_browser.Browser.Events.Disconnected, doCleanup);
|
||||
return browser;
|
||||
}
|
||||
_createDevTools() {
|
||||
// TODO: this is totally wrong when using channels.
|
||||
const directory = _registry.registry.findExecutable('chromium').directory;
|
||||
return directory ? new _crDevTools.CRDevTools(_path.default.join(directory, 'devtools-preferences.json')) : undefined;
|
||||
}
|
||||
async connectToTransport(transport, options) {
|
||||
let devtools = this._devtools;
|
||||
if (options.__testHookForDevTools) {
|
||||
devtools = this._createDevTools();
|
||||
await options.__testHookForDevTools(devtools);
|
||||
}
|
||||
return _crBrowser.CRBrowser.connect(this.attribution.playwright, transport, options, devtools);
|
||||
}
|
||||
doRewriteStartupLog(error) {
|
||||
if (!error.logs) return error;
|
||||
if (error.logs.includes('Missing X server')) error.logs = '\n' + (0, _ascii.wrapInASCIIBox)(_browserType.kNoXServerRunningError, 1);
|
||||
// These error messages are taken from Chromium source code as of July, 2020:
|
||||
// https://github.com/chromium/chromium/blob/70565f67e79f79e17663ad1337dc6e63ee207ce9/content/browser/zygote_host/zygote_host_impl_linux.cc
|
||||
if (!error.logs.includes('crbug.com/357670') && !error.logs.includes('No usable sandbox!') && !error.logs.includes('crbug.com/638180')) return error;
|
||||
error.logs = [`Chromium sandboxing failed!`, `================================`, `To avoid the sandboxing issue, do either of the following:`, ` - (preferred): Configure your environment to support sandboxing`, ` - (alternative): Launch Chromium without sandbox using 'chromiumSandbox: false' option`, `================================`, ``].join('\n');
|
||||
return error;
|
||||
}
|
||||
amendEnvironment(env, userDataDir, executable, browserArguments) {
|
||||
return env;
|
||||
}
|
||||
attemptToGracefullyCloseBrowser(transport) {
|
||||
const message = {
|
||||
method: 'Browser.close',
|
||||
id: _crConnection.kBrowserCloseMessageId,
|
||||
params: {}
|
||||
};
|
||||
transport.send(message);
|
||||
}
|
||||
async _launchWithSeleniumHub(progress, hubUrl, options) {
|
||||
await this._createArtifactDirs(options);
|
||||
if (!hubUrl.endsWith('/')) hubUrl = hubUrl + '/';
|
||||
const args = this._innerDefaultArgs(options);
|
||||
args.push('--remote-debugging-port=0');
|
||||
const isEdge = options.channel && options.channel.startsWith('msedge');
|
||||
let desiredCapabilities = {
|
||||
'browserName': isEdge ? 'MicrosoftEdge' : 'chrome',
|
||||
[isEdge ? 'ms:edgeOptions' : 'goog:chromeOptions']: {
|
||||
args
|
||||
}
|
||||
};
|
||||
if (process.env.SELENIUM_REMOTE_CAPABILITIES) {
|
||||
const remoteCapabilities = parseSeleniumRemoteParams({
|
||||
name: 'capabilities',
|
||||
value: process.env.SELENIUM_REMOTE_CAPABILITIES
|
||||
}, progress);
|
||||
if (remoteCapabilities) desiredCapabilities = {
|
||||
...desiredCapabilities,
|
||||
...remoteCapabilities
|
||||
};
|
||||
}
|
||||
let headers = {};
|
||||
if (process.env.SELENIUM_REMOTE_HEADERS) {
|
||||
const remoteHeaders = parseSeleniumRemoteParams({
|
||||
name: 'headers',
|
||||
value: process.env.SELENIUM_REMOTE_HEADERS
|
||||
}, progress);
|
||||
if (remoteHeaders) headers = remoteHeaders;
|
||||
}
|
||||
progress.log(`<selenium> connecting to ${hubUrl}`);
|
||||
const response = await (0, _network.fetchData)({
|
||||
url: hubUrl + 'session',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
...headers
|
||||
},
|
||||
data: JSON.stringify({
|
||||
capabilities: {
|
||||
alwaysMatch: desiredCapabilities
|
||||
}
|
||||
}),
|
||||
timeout: progress.timeUntilDeadline()
|
||||
}, seleniumErrorHandler);
|
||||
const value = JSON.parse(response).value;
|
||||
const sessionId = value.sessionId;
|
||||
progress.log(`<selenium> connected to sessionId=${sessionId}`);
|
||||
const disconnectFromSelenium = async () => {
|
||||
progress.log(`<selenium> disconnecting from sessionId=${sessionId}`);
|
||||
await (0, _network.fetchData)({
|
||||
url: hubUrl + 'session/' + sessionId,
|
||||
method: 'DELETE',
|
||||
headers
|
||||
}).catch(error => progress.log(`<error disconnecting from selenium>: ${error}`));
|
||||
progress.log(`<selenium> disconnected from sessionId=${sessionId}`);
|
||||
_processLauncher.gracefullyCloseSet.delete(disconnectFromSelenium);
|
||||
};
|
||||
_processLauncher.gracefullyCloseSet.add(disconnectFromSelenium);
|
||||
try {
|
||||
const capabilities = value.capabilities;
|
||||
let endpointURL;
|
||||
if (capabilities['se:cdp']) {
|
||||
// Selenium 4 - use built-in CDP websocket proxy.
|
||||
progress.log(`<selenium> using selenium v4`);
|
||||
const endpointURLString = addProtocol(capabilities['se:cdp']);
|
||||
endpointURL = new URL(endpointURLString);
|
||||
if (endpointURL.hostname === 'localhost' || endpointURL.hostname === '127.0.0.1') endpointURL.hostname = new URL(hubUrl).hostname;
|
||||
progress.log(`<selenium> retrieved endpoint ${endpointURL.toString()} for sessionId=${sessionId}`);
|
||||
} else {
|
||||
// Selenium 3 - resolve target node IP to use instead of localhost ws url.
|
||||
progress.log(`<selenium> using selenium v3`);
|
||||
const maybeChromeOptions = capabilities['goog:chromeOptions'];
|
||||
const chromeOptions = maybeChromeOptions && typeof maybeChromeOptions === 'object' ? maybeChromeOptions : undefined;
|
||||
const debuggerAddress = chromeOptions && typeof chromeOptions.debuggerAddress === 'string' ? chromeOptions.debuggerAddress : undefined;
|
||||
const chromeOptionsURL = typeof maybeChromeOptions === 'string' ? maybeChromeOptions : undefined;
|
||||
// TODO(dgozman): figure out if we can make ChromeDriver to return 127.0.0.1 instead of localhost.
|
||||
const endpointURLString = addProtocol(debuggerAddress || chromeOptionsURL).replace('localhost', '127.0.0.1');
|
||||
progress.log(`<selenium> retrieved endpoint ${endpointURLString} for sessionId=${sessionId}`);
|
||||
endpointURL = new URL(endpointURLString);
|
||||
if (endpointURL.hostname === 'localhost' || endpointURL.hostname === '127.0.0.1') {
|
||||
const sessionInfoUrl = new URL(hubUrl).origin + '/grid/api/testsession?session=' + sessionId;
|
||||
try {
|
||||
const sessionResponse = await (0, _network.fetchData)({
|
||||
url: sessionInfoUrl,
|
||||
method: 'GET',
|
||||
timeout: progress.timeUntilDeadline(),
|
||||
headers
|
||||
}, seleniumErrorHandler);
|
||||
const proxyId = JSON.parse(sessionResponse).proxyId;
|
||||
endpointURL.hostname = new URL(proxyId).hostname;
|
||||
progress.log(`<selenium> resolved endpoint ip ${endpointURL.toString()} for sessionId=${sessionId}`);
|
||||
} catch (e) {
|
||||
progress.log(`<selenium> unable to resolve endpoint ip for sessionId=${sessionId}, running in standalone?`);
|
||||
}
|
||||
}
|
||||
}
|
||||
return await this._connectOverCDPInternal(progress, endpointURL.toString(), {
|
||||
...options,
|
||||
headers: (0, _utils.headersObjectToArray)(headers)
|
||||
}, disconnectFromSelenium);
|
||||
} catch (e) {
|
||||
await disconnectFromSelenium();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
defaultArgs(options, isPersistent, userDataDir) {
|
||||
const chromeArguments = this._innerDefaultArgs(options);
|
||||
chromeArguments.push(`--user-data-dir=${userDataDir}`);
|
||||
if (options.useWebSocket) chromeArguments.push('--remote-debugging-port=0');else chromeArguments.push('--remote-debugging-pipe');
|
||||
if (isPersistent) chromeArguments.push('about:blank');else chromeArguments.push('--no-startup-window');
|
||||
return chromeArguments;
|
||||
}
|
||||
_innerDefaultArgs(options) {
|
||||
const {
|
||||
args = []
|
||||
} = options;
|
||||
const userDataDirArg = args.find(arg => arg.startsWith('--user-data-dir'));
|
||||
if (userDataDirArg) throw this._createUserDataDirArgMisuseError('--user-data-dir');
|
||||
if (args.find(arg => arg.startsWith('--remote-debugging-pipe'))) throw new Error('Playwright manages remote debugging connection itself.');
|
||||
if (args.find(arg => !arg.startsWith('-'))) throw new Error('Arguments can not specify page to be opened');
|
||||
const chromeArguments = [..._chromiumSwitches.chromiumSwitches];
|
||||
if (_os.default.platform() === 'darwin') {
|
||||
// See https://github.com/microsoft/playwright/issues/7362
|
||||
chromeArguments.push('--enable-use-zoom-for-dsf=false');
|
||||
// See https://bugs.chromium.org/p/chromium/issues/detail?id=1407025.
|
||||
if (options.headless && (!options.channel || options.channel === 'chromium-headless-shell')) chromeArguments.push('--use-angle');
|
||||
}
|
||||
if (options.devtools) chromeArguments.push('--auto-open-devtools-for-tabs');
|
||||
if (options.headless) {
|
||||
chromeArguments.push('--headless');
|
||||
chromeArguments.push('--hide-scrollbars', '--mute-audio', '--blink-settings=primaryHoverType=2,availableHoverTypes=2,primaryPointerType=4,availablePointerTypes=4');
|
||||
}
|
||||
if (options.chromiumSandbox !== true) chromeArguments.push('--no-sandbox');
|
||||
const proxy = options.proxyOverride || options.proxy;
|
||||
if (proxy) {
|
||||
const proxyURL = new URL(proxy.server);
|
||||
const isSocks = proxyURL.protocol === 'socks5:';
|
||||
// https://www.chromium.org/developers/design-documents/network-settings
|
||||
if (isSocks && !this.attribution.playwright.options.socksProxyPort) {
|
||||
// https://www.chromium.org/developers/design-documents/network-stack/socks-proxy
|
||||
chromeArguments.push(`--host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE ${proxyURL.hostname}"`);
|
||||
}
|
||||
chromeArguments.push(`--proxy-server=${proxy.server}`);
|
||||
const proxyBypassRules = [];
|
||||
// https://source.chromium.org/chromium/chromium/src/+/master:net/docs/proxy.md;l=548;drc=71698e610121078e0d1a811054dcf9fd89b49578
|
||||
if (this.attribution.playwright.options.socksProxyPort) proxyBypassRules.push('<-loopback>');
|
||||
if (proxy.bypass) proxyBypassRules.push(...proxy.bypass.split(',').map(t => t.trim()).map(t => t.startsWith('.') ? '*' + t : t));
|
||||
if (!process.env.PLAYWRIGHT_DISABLE_FORCED_CHROMIUM_PROXIED_LOOPBACK && !proxyBypassRules.includes('<-loopback>')) proxyBypassRules.push('<-loopback>');
|
||||
if (proxyBypassRules.length > 0) chromeArguments.push(`--proxy-bypass-list=${proxyBypassRules.join(';')}`);
|
||||
}
|
||||
chromeArguments.push(...args);
|
||||
return chromeArguments;
|
||||
}
|
||||
readyState(options) {
|
||||
var _options$args;
|
||||
if (options.useWebSocket || (_options$args = options.args) !== null && _options$args !== void 0 && _options$args.some(a => a.startsWith('--remote-debugging-port'))) return new ChromiumReadyState();
|
||||
return undefined;
|
||||
}
|
||||
getExecutableName(options) {
|
||||
if (options.channel) return options.channel;
|
||||
return options.headless ? 'chromium-headless-shell' : 'chromium';
|
||||
}
|
||||
}
|
||||
exports.Chromium = Chromium;
|
||||
class ChromiumReadyState extends _browserType.BrowserReadyState {
|
||||
onBrowserOutput(message) {
|
||||
const match = message.match(/DevTools listening on (.*)/);
|
||||
if (match) this._wsEndpoint.resolve(match[1]);
|
||||
}
|
||||
}
|
||||
async function urlToWSEndpoint(progress, endpointURL, headers) {
|
||||
if (endpointURL.startsWith('ws')) return endpointURL;
|
||||
progress.log(`<ws preparing> retrieving websocket url from ${endpointURL}`);
|
||||
const httpURL = endpointURL.endsWith('/') ? `${endpointURL}json/version/` : `${endpointURL}/json/version/`;
|
||||
const json = await (0, _network.fetchData)({
|
||||
url: httpURL,
|
||||
headers
|
||||
}, async (_, resp) => new Error(`Unexpected status ${resp.statusCode} when connecting to ${httpURL}.\n` + `This does not look like a DevTools server, try connecting via ws://.`));
|
||||
return JSON.parse(json).webSocketDebuggerUrl;
|
||||
}
|
||||
async function seleniumErrorHandler(params, response) {
|
||||
const body = await streamToString(response);
|
||||
let message = body;
|
||||
try {
|
||||
const json = JSON.parse(body);
|
||||
message = json.value.localizedMessage || json.value.message;
|
||||
} catch (e) {}
|
||||
return new Error(`Error connecting to Selenium at ${params.url}: ${message}`);
|
||||
}
|
||||
function addProtocol(url) {
|
||||
if (!['ws://', 'wss://', 'http://', 'https://'].some(protocol => url.startsWith(protocol))) return 'http://' + url;
|
||||
return url;
|
||||
}
|
||||
function streamToString(stream) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const chunks = [];
|
||||
stream.on('data', chunk => chunks.push(Buffer.from(chunk)));
|
||||
stream.on('error', reject);
|
||||
stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
|
||||
});
|
||||
}
|
||||
function parseSeleniumRemoteParams(env, progress) {
|
||||
try {
|
||||
const parsed = JSON.parse(env.value);
|
||||
progress.log(`<selenium> using additional ${env.name} "${env.value}"`);
|
||||
return parsed;
|
||||
} catch (e) {
|
||||
progress.log(`<selenium> ignoring additional ${env.name} "${env.value}": ${e}`);
|
||||
}
|
||||
}
|
||||
69
node_modules/playwright-core/lib/server/chromium/chromiumSwitches.js
generated
vendored
Normal file
69
node_modules/playwright-core/lib/server/chromium/chromiumSwitches.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.chromiumSwitches = void 0;
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// No dependencies as it is used from the Electron loader.
|
||||
|
||||
const disabledFeatures = [
|
||||
// See https://github.com/microsoft/playwright/pull/10380
|
||||
'AcceptCHFrame',
|
||||
// See https://github.com/microsoft/playwright/pull/10679
|
||||
'AutoExpandDetailsElement',
|
||||
// See https://github.com/microsoft/playwright/issues/14047
|
||||
'AvoidUnnecessaryBeforeUnloadCheckSync',
|
||||
// See https://github.com/microsoft/playwright/pull/12992
|
||||
'CertificateTransparencyComponentUpdater',
|
||||
// This makes Page.frameScheduledNavigation arrive much later after a click,
|
||||
// making our navigation auto-wait after click not working.
|
||||
// Can be removed once we deperecate noWaitAfter.
|
||||
// See https://github.com/microsoft/playwright/pull/34372.
|
||||
'DeferRendererTasksAfterInput', 'DestroyProfileOnBrowserClose',
|
||||
// See https://github.com/microsoft/playwright/pull/13854
|
||||
'DialMediaRouteProvider',
|
||||
// Chromium is disabling manifest version 2. Allow testing it as long as Chromium can actually run it.
|
||||
// Disabled in https://chromium-review.googlesource.com/c/chromium/src/+/6265903.
|
||||
'ExtensionManifestV2Disabled', 'GlobalMediaControls',
|
||||
// See https://github.com/microsoft/playwright/pull/27605
|
||||
'HttpsUpgrades', 'ImprovedCookieControls', 'LazyFrameLoading',
|
||||
// Hides the Lens feature in the URL address bar. Its not working in unofficial builds.
|
||||
'LensOverlay',
|
||||
// See https://github.com/microsoft/playwright/pull/8162
|
||||
'MediaRouter',
|
||||
// See https://github.com/microsoft/playwright/issues/28023
|
||||
'PaintHolding',
|
||||
// See https://github.com/microsoft/playwright/issues/32230
|
||||
'ThirdPartyStoragePartitioning',
|
||||
// See https://github.com/microsoft/playwright/issues/16126
|
||||
'Translate'];
|
||||
const chromiumSwitches = exports.chromiumSwitches = ['--disable-field-trial-config',
|
||||
// https://source.chromium.org/chromium/chromium/src/+/main:testing/variations/README.md
|
||||
'--disable-background-networking', '--disable-background-timer-throttling', '--disable-backgrounding-occluded-windows', '--disable-back-forward-cache',
|
||||
// Avoids surprises like main request not being intercepted during page.goBack().
|
||||
'--disable-breakpad', '--disable-client-side-phishing-detection', '--disable-component-extensions-with-background-pages', '--disable-component-update',
|
||||
// Avoids unneeded network activity after startup.
|
||||
'--no-default-browser-check', '--disable-default-apps', '--disable-dev-shm-usage', '--disable-extensions', '--disable-features=' + disabledFeatures.join(','), '--allow-pre-commit-input', '--disable-hang-monitor', '--disable-ipc-flooding-protection', '--disable-popup-blocking', '--disable-prompt-on-repost', '--disable-renderer-backgrounding', '--force-color-profile=srgb', '--metrics-recording-only', '--no-first-run', '--enable-automation', '--password-store=basic', '--use-mock-keychain',
|
||||
// See https://chromium-review.googlesource.com/c/chromium/src/+/2436773
|
||||
'--no-service-autorun', '--export-tagged-pdf',
|
||||
// https://chromium-review.googlesource.com/c/chromium/src/+/4853540
|
||||
'--disable-search-engine-choice-screen',
|
||||
// https://issues.chromium.org/41491762
|
||||
'--unsafely-disable-devtools-self-xss-warnings'];
|
||||
237
node_modules/playwright-core/lib/server/chromium/crAccessibility.js
generated
vendored
Normal file
237
node_modules/playwright-core/lib/server/chromium/crAccessibility.js
generated
vendored
Normal file
@@ -0,0 +1,237 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.getAccessibilityTree = getAccessibilityTree;
|
||||
/**
|
||||
* Copyright 2018 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
async function getAccessibilityTree(client, needle) {
|
||||
const {
|
||||
nodes
|
||||
} = await client.send('Accessibility.getFullAXTree');
|
||||
const tree = CRAXNode.createTree(client, nodes);
|
||||
return {
|
||||
tree,
|
||||
needle: needle ? await tree._findElement(needle) : null
|
||||
};
|
||||
}
|
||||
class CRAXNode {
|
||||
constructor(client, payload) {
|
||||
this._payload = void 0;
|
||||
this._children = [];
|
||||
this._richlyEditable = false;
|
||||
this._editable = false;
|
||||
this._focusable = false;
|
||||
this._expanded = false;
|
||||
this._hidden = false;
|
||||
this._name = void 0;
|
||||
this._role = void 0;
|
||||
this._cachedHasFocusableChild = void 0;
|
||||
this._client = void 0;
|
||||
this._client = client;
|
||||
this._payload = payload;
|
||||
this._name = this._payload.name ? this._payload.name.value : '';
|
||||
this._role = this._payload.role ? this._payload.role.value : 'Unknown';
|
||||
for (const property of this._payload.properties || []) {
|
||||
if (property.name === 'editable') {
|
||||
this._richlyEditable = property.value.value === 'richtext';
|
||||
this._editable = true;
|
||||
}
|
||||
if (property.name === 'focusable') this._focusable = property.value.value;
|
||||
if (property.name === 'expanded') this._expanded = property.value.value;
|
||||
if (property.name === 'hidden') this._hidden = property.value.value;
|
||||
}
|
||||
}
|
||||
_isPlainTextField() {
|
||||
if (this._richlyEditable) return false;
|
||||
if (this._editable) return true;
|
||||
return this._role === 'textbox' || this._role === 'ComboBox' || this._role === 'searchbox';
|
||||
}
|
||||
_isTextOnlyObject() {
|
||||
const role = this._role;
|
||||
return role === 'LineBreak' || role === 'text' || role === 'InlineTextBox' || role === 'StaticText';
|
||||
}
|
||||
_hasFocusableChild() {
|
||||
if (this._cachedHasFocusableChild === undefined) {
|
||||
this._cachedHasFocusableChild = false;
|
||||
for (const child of this._children) {
|
||||
if (child._focusable || child._hasFocusableChild()) {
|
||||
this._cachedHasFocusableChild = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this._cachedHasFocusableChild;
|
||||
}
|
||||
children() {
|
||||
return this._children;
|
||||
}
|
||||
async _findElement(element) {
|
||||
const objectId = element._objectId;
|
||||
const {
|
||||
node: {
|
||||
backendNodeId
|
||||
}
|
||||
} = await this._client.send('DOM.describeNode', {
|
||||
objectId
|
||||
});
|
||||
const needle = this.find(node => node._payload.backendDOMNodeId === backendNodeId);
|
||||
return needle || null;
|
||||
}
|
||||
find(predicate) {
|
||||
if (predicate(this)) return this;
|
||||
for (const child of this._children) {
|
||||
const result = child.find(predicate);
|
||||
if (result) return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
isLeafNode() {
|
||||
if (!this._children.length) return true;
|
||||
|
||||
// These types of objects may have children that we use as internal
|
||||
// implementation details, but we want to expose them as leaves to platform
|
||||
// accessibility APIs because screen readers might be confused if they find
|
||||
// any children.
|
||||
if (this._isPlainTextField() || this._isTextOnlyObject()) return true;
|
||||
|
||||
// Roles whose children are only presentational according to the ARIA and
|
||||
// HTML5 Specs should be hidden from screen readers.
|
||||
// (Note that whilst ARIA buttons can have only presentational children, HTML5
|
||||
// buttons are allowed to have content.)
|
||||
switch (this._role) {
|
||||
case 'doc-cover':
|
||||
case 'graphics-symbol':
|
||||
case 'img':
|
||||
case 'Meter':
|
||||
case 'scrollbar':
|
||||
case 'slider':
|
||||
case 'separator':
|
||||
case 'progressbar':
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Here and below: Android heuristics
|
||||
if (this._hasFocusableChild()) return false;
|
||||
if (this._focusable && this._role !== 'WebArea' && this._role !== 'RootWebArea' && this._name) return true;
|
||||
if (this._role === 'heading' && this._name) return true;
|
||||
return false;
|
||||
}
|
||||
isControl() {
|
||||
switch (this._role) {
|
||||
case 'button':
|
||||
case 'checkbox':
|
||||
case 'ColorWell':
|
||||
case 'combobox':
|
||||
case 'DisclosureTriangle':
|
||||
case 'listbox':
|
||||
case 'menu':
|
||||
case 'menubar':
|
||||
case 'menuitem':
|
||||
case 'menuitemcheckbox':
|
||||
case 'menuitemradio':
|
||||
case 'radio':
|
||||
case 'scrollbar':
|
||||
case 'searchbox':
|
||||
case 'slider':
|
||||
case 'spinbutton':
|
||||
case 'switch':
|
||||
case 'tab':
|
||||
case 'textbox':
|
||||
case 'tree':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
isInteresting(insideControl) {
|
||||
const role = this._role;
|
||||
if (role === 'Ignored' || this._hidden) return false;
|
||||
if (this._focusable || this._richlyEditable) return true;
|
||||
|
||||
// If it's not focusable but has a control role, then it's interesting.
|
||||
if (this.isControl()) return true;
|
||||
|
||||
// A non focusable child of a control is not interesting
|
||||
if (insideControl) return false;
|
||||
return this.isLeafNode() && !!this._name;
|
||||
}
|
||||
normalizedRole() {
|
||||
switch (this._role) {
|
||||
case 'RootWebArea':
|
||||
return 'WebArea';
|
||||
case 'StaticText':
|
||||
return 'text';
|
||||
default:
|
||||
return this._role;
|
||||
}
|
||||
}
|
||||
serialize() {
|
||||
const properties = new Map();
|
||||
for (const property of this._payload.properties || []) properties.set(property.name.toLowerCase(), property.value.value);
|
||||
if (this._payload.description) properties.set('description', this._payload.description.value);
|
||||
const node = {
|
||||
role: this.normalizedRole(),
|
||||
name: this._payload.name ? this._payload.name.value || '' : ''
|
||||
};
|
||||
const userStringProperties = ['description', 'keyshortcuts', 'roledescription', 'valuetext'];
|
||||
for (const userStringProperty of userStringProperties) {
|
||||
if (!properties.has(userStringProperty)) continue;
|
||||
node[userStringProperty] = properties.get(userStringProperty);
|
||||
}
|
||||
const booleanProperties = ['disabled', 'expanded', 'focused', 'modal', 'multiline', 'multiselectable', 'readonly', 'required', 'selected'];
|
||||
for (const booleanProperty of booleanProperties) {
|
||||
// WebArea's treat focus differently than other nodes. They report whether their frame has focus,
|
||||
// not whether focus is specifically on the root node.
|
||||
if (booleanProperty === 'focused' && (this._role === 'WebArea' || this._role === 'RootWebArea')) continue;
|
||||
const value = properties.get(booleanProperty);
|
||||
if (!value) continue;
|
||||
node[booleanProperty] = value;
|
||||
}
|
||||
const numericalProperties = ['level', 'valuemax', 'valuemin'];
|
||||
for (const numericalProperty of numericalProperties) {
|
||||
if (!properties.has(numericalProperty)) continue;
|
||||
node[numericalProperty] = properties.get(numericalProperty);
|
||||
}
|
||||
const tokenProperties = ['autocomplete', 'haspopup', 'invalid', 'orientation'];
|
||||
for (const tokenProperty of tokenProperties) {
|
||||
const value = properties.get(tokenProperty);
|
||||
if (!value || value === 'false') continue;
|
||||
node[tokenProperty] = value;
|
||||
}
|
||||
const axNode = node;
|
||||
if (this._payload.value) {
|
||||
if (typeof this._payload.value.value === 'string') axNode.valueString = this._payload.value.value;
|
||||
if (typeof this._payload.value.value === 'number') axNode.valueNumber = this._payload.value.value;
|
||||
}
|
||||
if (properties.has('checked')) axNode.checked = properties.get('checked') === 'true' ? 'checked' : properties.get('checked') === 'false' ? 'unchecked' : 'mixed';
|
||||
if (properties.has('pressed')) axNode.pressed = properties.get('pressed') === 'true' ? 'pressed' : properties.get('pressed') === 'false' ? 'released' : 'mixed';
|
||||
return axNode;
|
||||
}
|
||||
static createTree(client, payloads) {
|
||||
const nodeById = new Map();
|
||||
for (const payload of payloads) nodeById.set(payload.nodeId, new CRAXNode(client, payload));
|
||||
for (const node of nodeById.values()) {
|
||||
for (const childId of node._payload.childIds || []) node._children.push(nodeById.get(childId));
|
||||
}
|
||||
return nodeById.values().next().value;
|
||||
}
|
||||
}
|
||||
517
node_modules/playwright-core/lib/server/chromium/crBrowser.js
generated
vendored
Normal file
517
node_modules/playwright-core/lib/server/chromium/crBrowser.js
generated
vendored
Normal file
@@ -0,0 +1,517 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.CRBrowserContext = exports.CRBrowser = void 0;
|
||||
var _path = _interopRequireDefault(require("path"));
|
||||
var _assert = require("../../utils/isomorphic/assert");
|
||||
var _crypto = require("../utils/crypto");
|
||||
var _artifact = require("../artifact");
|
||||
var _browser = require("../browser");
|
||||
var _browserContext = require("../browserContext");
|
||||
var _frames = require("../frames");
|
||||
var network = _interopRequireWildcard(require("../network"));
|
||||
var _page = require("../page");
|
||||
var _crConnection = require("./crConnection");
|
||||
var _crPage = require("./crPage");
|
||||
var _crProtocolHelper = require("./crProtocolHelper");
|
||||
var _crServiceWorker = require("./crServiceWorker");
|
||||
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
||||
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class CRBrowser extends _browser.Browser {
|
||||
static async connect(parent, transport, options, devtools) {
|
||||
// Make a copy in case we need to update `headful` property below.
|
||||
options = {
|
||||
...options
|
||||
};
|
||||
const connection = new _crConnection.CRConnection(transport, options.protocolLogger, options.browserLogsCollector);
|
||||
const browser = new CRBrowser(parent, connection, options);
|
||||
browser._devtools = devtools;
|
||||
if (browser.isClank()) browser._isCollocatedWithServer = false;
|
||||
const session = connection.rootSession;
|
||||
if (options.__testHookOnConnectToBrowser) await options.__testHookOnConnectToBrowser();
|
||||
const version = await session.send('Browser.getVersion');
|
||||
browser._version = version.product.substring(version.product.indexOf('/') + 1);
|
||||
browser._userAgent = version.userAgent;
|
||||
// We don't trust the option as it may lie in case of connectOverCDP where remote browser
|
||||
// may have been launched with different options.
|
||||
browser.options.headful = !version.userAgent.includes('Headless');
|
||||
if (!options.persistent) {
|
||||
await session.send('Target.setAutoAttach', {
|
||||
autoAttach: true,
|
||||
waitForDebuggerOnStart: true,
|
||||
flatten: true
|
||||
});
|
||||
return browser;
|
||||
}
|
||||
browser._defaultContext = new CRBrowserContext(browser, undefined, options.persistent);
|
||||
await Promise.all([session.send('Target.setAutoAttach', {
|
||||
autoAttach: true,
|
||||
waitForDebuggerOnStart: true,
|
||||
flatten: true
|
||||
}).then(async () => {
|
||||
// Target.setAutoAttach has a bug where it does not wait for new Targets being attached.
|
||||
// However making a dummy call afterwards fixes this.
|
||||
// This can be removed after https://chromium-review.googlesource.com/c/chromium/src/+/2885888 lands in stable.
|
||||
await session.send('Target.getTargetInfo');
|
||||
}), browser._defaultContext._initialize()]);
|
||||
await browser._waitForAllPagesToBeInitialized();
|
||||
return browser;
|
||||
}
|
||||
constructor(parent, connection, options) {
|
||||
super(parent, options);
|
||||
this._connection = void 0;
|
||||
this._session = void 0;
|
||||
this._clientRootSessionPromise = null;
|
||||
this._contexts = new Map();
|
||||
this._crPages = new Map();
|
||||
this._backgroundPages = new Map();
|
||||
this._serviceWorkers = new Map();
|
||||
this._devtools = void 0;
|
||||
this._version = '';
|
||||
this._tracingRecording = false;
|
||||
this._tracingClient = void 0;
|
||||
this._userAgent = '';
|
||||
this._connection = connection;
|
||||
this._session = this._connection.rootSession;
|
||||
this._connection.on(_crConnection.ConnectionEvents.Disconnected, () => this._didDisconnect());
|
||||
this._session.on('Target.attachedToTarget', this._onAttachedToTarget.bind(this));
|
||||
this._session.on('Target.detachedFromTarget', this._onDetachedFromTarget.bind(this));
|
||||
this._session.on('Browser.downloadWillBegin', this._onDownloadWillBegin.bind(this));
|
||||
this._session.on('Browser.downloadProgress', this._onDownloadProgress.bind(this));
|
||||
}
|
||||
async doCreateNewContext(options) {
|
||||
const proxy = options.proxyOverride || options.proxy;
|
||||
let proxyBypassList = undefined;
|
||||
if (proxy) {
|
||||
if (process.env.PLAYWRIGHT_DISABLE_FORCED_CHROMIUM_PROXIED_LOOPBACK) proxyBypassList = proxy.bypass;else proxyBypassList = '<-loopback>' + (proxy.bypass ? `,${proxy.bypass}` : '');
|
||||
}
|
||||
const {
|
||||
browserContextId
|
||||
} = await this._session.send('Target.createBrowserContext', {
|
||||
disposeOnDetach: true,
|
||||
proxyServer: proxy ? proxy.server : undefined,
|
||||
proxyBypassList
|
||||
});
|
||||
const context = new CRBrowserContext(this, browserContextId, options);
|
||||
await context._initialize();
|
||||
this._contexts.set(browserContextId, context);
|
||||
return context;
|
||||
}
|
||||
contexts() {
|
||||
return Array.from(this._contexts.values());
|
||||
}
|
||||
version() {
|
||||
return this._version;
|
||||
}
|
||||
userAgent() {
|
||||
return this._userAgent;
|
||||
}
|
||||
_platform() {
|
||||
if (this._userAgent.includes('Windows')) return 'win';
|
||||
if (this._userAgent.includes('Macintosh')) return 'mac';
|
||||
return 'linux';
|
||||
}
|
||||
isClank() {
|
||||
return this.options.name === 'clank';
|
||||
}
|
||||
async _waitForAllPagesToBeInitialized() {
|
||||
await Promise.all([...this._crPages.values()].map(crPage => crPage._page.waitForInitializedOrError()));
|
||||
}
|
||||
_onAttachedToTarget({
|
||||
targetInfo,
|
||||
sessionId,
|
||||
waitingForDebugger
|
||||
}) {
|
||||
if (targetInfo.type === 'browser') return;
|
||||
const session = this._session.createChildSession(sessionId);
|
||||
(0, _assert.assert)(targetInfo.browserContextId, 'targetInfo: ' + JSON.stringify(targetInfo, null, 2));
|
||||
let context = this._contexts.get(targetInfo.browserContextId) || null;
|
||||
if (!context) {
|
||||
// TODO: auto attach only to pages from our contexts.
|
||||
// assert(this._defaultContext);
|
||||
context = this._defaultContext;
|
||||
}
|
||||
if (targetInfo.type === 'other' && targetInfo.url.startsWith('devtools://devtools') && this._devtools) {
|
||||
this._devtools.install(session);
|
||||
return;
|
||||
}
|
||||
const treatOtherAsPage = targetInfo.type === 'other' && process.env.PW_CHROMIUM_ATTACH_TO_OTHER;
|
||||
if (!context || targetInfo.type === 'other' && !treatOtherAsPage) {
|
||||
session.detach().catch(() => {});
|
||||
return;
|
||||
}
|
||||
(0, _assert.assert)(!this._crPages.has(targetInfo.targetId), 'Duplicate target ' + targetInfo.targetId);
|
||||
(0, _assert.assert)(!this._backgroundPages.has(targetInfo.targetId), 'Duplicate target ' + targetInfo.targetId);
|
||||
(0, _assert.assert)(!this._serviceWorkers.has(targetInfo.targetId), 'Duplicate target ' + targetInfo.targetId);
|
||||
if (targetInfo.type === 'background_page') {
|
||||
const backgroundPage = new _crPage.CRPage(session, targetInfo.targetId, context, null, {
|
||||
hasUIWindow: false,
|
||||
isBackgroundPage: true
|
||||
});
|
||||
this._backgroundPages.set(targetInfo.targetId, backgroundPage);
|
||||
return;
|
||||
}
|
||||
if (targetInfo.type === 'page' || treatOtherAsPage) {
|
||||
const opener = targetInfo.openerId ? this._crPages.get(targetInfo.openerId) || null : null;
|
||||
const crPage = new _crPage.CRPage(session, targetInfo.targetId, context, opener, {
|
||||
hasUIWindow: targetInfo.type === 'page',
|
||||
isBackgroundPage: false
|
||||
});
|
||||
this._crPages.set(targetInfo.targetId, crPage);
|
||||
return;
|
||||
}
|
||||
if (targetInfo.type === 'service_worker') {
|
||||
const serviceWorker = new _crServiceWorker.CRServiceWorker(context, session, targetInfo.url);
|
||||
this._serviceWorkers.set(targetInfo.targetId, serviceWorker);
|
||||
context.emit(CRBrowserContext.CREvents.ServiceWorker, serviceWorker);
|
||||
return;
|
||||
}
|
||||
|
||||
// Detach from any targets we are not interested in, to avoid side-effects.
|
||||
//
|
||||
// One example of a side effect: upon shared worker restart, we receive
|
||||
// Inspector.targetReloadedAfterCrash and backend waits for Runtime.runIfWaitingForDebugger
|
||||
// from any attached client. If we do not resume, shared worker will stall.
|
||||
session.detach().catch(() => {});
|
||||
}
|
||||
_onDetachedFromTarget(payload) {
|
||||
const targetId = payload.targetId;
|
||||
const crPage = this._crPages.get(targetId);
|
||||
if (crPage) {
|
||||
this._crPages.delete(targetId);
|
||||
crPage.didClose();
|
||||
return;
|
||||
}
|
||||
const backgroundPage = this._backgroundPages.get(targetId);
|
||||
if (backgroundPage) {
|
||||
this._backgroundPages.delete(targetId);
|
||||
backgroundPage.didClose();
|
||||
return;
|
||||
}
|
||||
const serviceWorker = this._serviceWorkers.get(targetId);
|
||||
if (serviceWorker) {
|
||||
this._serviceWorkers.delete(targetId);
|
||||
serviceWorker.didClose();
|
||||
return;
|
||||
}
|
||||
}
|
||||
_didDisconnect() {
|
||||
for (const crPage of this._crPages.values()) crPage.didClose();
|
||||
this._crPages.clear();
|
||||
for (const backgroundPage of this._backgroundPages.values()) backgroundPage.didClose();
|
||||
this._backgroundPages.clear();
|
||||
for (const serviceWorker of this._serviceWorkers.values()) serviceWorker.didClose();
|
||||
this._serviceWorkers.clear();
|
||||
this._didClose();
|
||||
}
|
||||
_findOwningPage(frameId) {
|
||||
for (const crPage of this._crPages.values()) {
|
||||
const frame = crPage._page._frameManager.frame(frameId);
|
||||
if (frame) return crPage;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
_onDownloadWillBegin(payload) {
|
||||
const page = this._findOwningPage(payload.frameId);
|
||||
if (!page) {
|
||||
// There might be no page when download originates from something unusual, like
|
||||
// a DevTools window or maybe an extension page.
|
||||
// See https://github.com/microsoft/playwright/issues/22551.
|
||||
return;
|
||||
}
|
||||
page.willBeginDownload();
|
||||
let originPage = page._page.initializedOrUndefined();
|
||||
// If it's a new window download, report it on the opener page.
|
||||
if (!originPage && page._opener) originPage = page._opener._page.initializedOrUndefined();
|
||||
if (!originPage) return;
|
||||
this._downloadCreated(originPage, payload.guid, payload.url, payload.suggestedFilename);
|
||||
}
|
||||
_onDownloadProgress(payload) {
|
||||
if (payload.state === 'completed') this._downloadFinished(payload.guid, '');
|
||||
if (payload.state === 'canceled') this._downloadFinished(payload.guid, this._closeReason || 'canceled');
|
||||
}
|
||||
async _closePage(crPage) {
|
||||
await this._session.send('Target.closeTarget', {
|
||||
targetId: crPage._targetId
|
||||
});
|
||||
}
|
||||
async newBrowserCDPSession() {
|
||||
return await this._connection.createBrowserSession();
|
||||
}
|
||||
async startTracing(page, options = {}) {
|
||||
(0, _assert.assert)(!this._tracingRecording, 'Cannot start recording trace while already recording trace.');
|
||||
this._tracingClient = page ? page._delegate._mainFrameSession._client : this._session;
|
||||
const defaultCategories = ['-*', 'devtools.timeline', 'v8.execute', 'disabled-by-default-devtools.timeline', 'disabled-by-default-devtools.timeline.frame', 'toplevel', 'blink.console', 'blink.user_timing', 'latencyInfo', 'disabled-by-default-devtools.timeline.stack', 'disabled-by-default-v8.cpu_profiler', 'disabled-by-default-v8.cpu_profiler.hires'];
|
||||
const {
|
||||
screenshots = false,
|
||||
categories = defaultCategories
|
||||
} = options;
|
||||
if (screenshots) categories.push('disabled-by-default-devtools.screenshot');
|
||||
this._tracingRecording = true;
|
||||
await this._tracingClient.send('Tracing.start', {
|
||||
transferMode: 'ReturnAsStream',
|
||||
categories: categories.join(',')
|
||||
});
|
||||
}
|
||||
async stopTracing() {
|
||||
(0, _assert.assert)(this._tracingClient, 'Tracing was not started.');
|
||||
const [event] = await Promise.all([new Promise(f => this._tracingClient.once('Tracing.tracingComplete', f)), this._tracingClient.send('Tracing.end')]);
|
||||
const tracingPath = _path.default.join(this.options.artifactsDir, (0, _crypto.createGuid)() + '.crtrace');
|
||||
await (0, _crProtocolHelper.saveProtocolStream)(this._tracingClient, event.stream, tracingPath);
|
||||
this._tracingRecording = false;
|
||||
const artifact = new _artifact.Artifact(this, tracingPath);
|
||||
artifact.reportFinished();
|
||||
return artifact;
|
||||
}
|
||||
isConnected() {
|
||||
return !this._connection._closed;
|
||||
}
|
||||
async _clientRootSession() {
|
||||
if (!this._clientRootSessionPromise) this._clientRootSessionPromise = this._connection.createBrowserSession();
|
||||
return this._clientRootSessionPromise;
|
||||
}
|
||||
}
|
||||
exports.CRBrowser = CRBrowser;
|
||||
class CRBrowserContext extends _browserContext.BrowserContext {
|
||||
constructor(browser, browserContextId, options) {
|
||||
super(browser, options, browserContextId);
|
||||
this._authenticateProxyViaCredentials();
|
||||
}
|
||||
async _initialize() {
|
||||
(0, _assert.assert)(!Array.from(this._browser._crPages.values()).some(page => page._browserContext === this));
|
||||
const promises = [super._initialize()];
|
||||
if (this._browser.options.name !== 'clank' && this._options.acceptDownloads !== 'internal-browser-default') {
|
||||
promises.push(this._browser._session.send('Browser.setDownloadBehavior', {
|
||||
behavior: this._options.acceptDownloads === 'accept' ? 'allowAndName' : 'deny',
|
||||
browserContextId: this._browserContextId,
|
||||
downloadPath: this._browser.options.downloadsPath,
|
||||
eventsEnabled: true
|
||||
}));
|
||||
}
|
||||
await Promise.all(promises);
|
||||
}
|
||||
_crPages() {
|
||||
return [...this._browser._crPages.values()].filter(crPage => crPage._browserContext === this);
|
||||
}
|
||||
possiblyUninitializedPages() {
|
||||
return this._crPages().map(crPage => crPage._page);
|
||||
}
|
||||
async doCreateNewPage() {
|
||||
(0, _browserContext.assertBrowserContextIsNotOwned)(this);
|
||||
const oldKeys = this._browser.isClank() ? new Set(this._browser._crPages.keys()) : undefined;
|
||||
let {
|
||||
targetId
|
||||
} = await this._browser._session.send('Target.createTarget', {
|
||||
url: 'about:blank',
|
||||
browserContextId: this._browserContextId
|
||||
});
|
||||
if (oldKeys) {
|
||||
// Chrome for Android returns tab ids (1, 2, 3, 4, 5) instead of content target ids here, work around it via the
|
||||
// heuristic assuming that there is only one page created at a time.
|
||||
const newKeys = new Set(this._browser._crPages.keys());
|
||||
// Remove old keys.
|
||||
for (const key of oldKeys) newKeys.delete(key);
|
||||
// Remove potential concurrent popups.
|
||||
for (const key of newKeys) {
|
||||
const page = this._browser._crPages.get(key);
|
||||
if (page._opener) newKeys.delete(key);
|
||||
}
|
||||
(0, _assert.assert)(newKeys.size === 1);
|
||||
[targetId] = [...newKeys];
|
||||
}
|
||||
return this._browser._crPages.get(targetId)._page;
|
||||
}
|
||||
async doGetCookies(urls) {
|
||||
const {
|
||||
cookies
|
||||
} = await this._browser._session.send('Storage.getCookies', {
|
||||
browserContextId: this._browserContextId
|
||||
});
|
||||
return network.filterCookies(cookies.map(c => {
|
||||
const copy = {
|
||||
sameSite: 'Lax',
|
||||
...c
|
||||
};
|
||||
delete copy.size;
|
||||
delete copy.priority;
|
||||
delete copy.session;
|
||||
delete copy.sameParty;
|
||||
delete copy.sourceScheme;
|
||||
delete copy.sourcePort;
|
||||
return copy;
|
||||
}), urls);
|
||||
}
|
||||
async addCookies(cookies) {
|
||||
await this._browser._session.send('Storage.setCookies', {
|
||||
cookies: network.rewriteCookies(cookies),
|
||||
browserContextId: this._browserContextId
|
||||
});
|
||||
}
|
||||
async doClearCookies() {
|
||||
await this._browser._session.send('Storage.clearCookies', {
|
||||
browserContextId: this._browserContextId
|
||||
});
|
||||
}
|
||||
async doGrantPermissions(origin, permissions) {
|
||||
const webPermissionToProtocol = new Map([['geolocation', 'geolocation'], ['midi', 'midi'], ['notifications', 'notifications'], ['camera', 'videoCapture'], ['microphone', 'audioCapture'], ['background-sync', 'backgroundSync'], ['ambient-light-sensor', 'sensors'], ['accelerometer', 'sensors'], ['gyroscope', 'sensors'], ['magnetometer', 'sensors'], ['clipboard-read', 'clipboardReadWrite'], ['clipboard-write', 'clipboardSanitizedWrite'], ['payment-handler', 'paymentHandler'],
|
||||
// chrome-specific permissions we have.
|
||||
['midi-sysex', 'midiSysex'], ['storage-access', 'storageAccess']]);
|
||||
const filtered = permissions.map(permission => {
|
||||
const protocolPermission = webPermissionToProtocol.get(permission);
|
||||
if (!protocolPermission) throw new Error('Unknown permission: ' + permission);
|
||||
return protocolPermission;
|
||||
});
|
||||
await this._browser._session.send('Browser.grantPermissions', {
|
||||
origin: origin === '*' ? undefined : origin,
|
||||
browserContextId: this._browserContextId,
|
||||
permissions: filtered
|
||||
});
|
||||
}
|
||||
async doClearPermissions() {
|
||||
await this._browser._session.send('Browser.resetPermissions', {
|
||||
browserContextId: this._browserContextId
|
||||
});
|
||||
}
|
||||
async setGeolocation(geolocation) {
|
||||
(0, _browserContext.verifyGeolocation)(geolocation);
|
||||
this._options.geolocation = geolocation;
|
||||
for (const page of this.pages()) await page._delegate.updateGeolocation();
|
||||
}
|
||||
async setExtraHTTPHeaders(headers) {
|
||||
this._options.extraHTTPHeaders = headers;
|
||||
for (const page of this.pages()) await page._delegate.updateExtraHTTPHeaders();
|
||||
for (const sw of this.serviceWorkers()) await sw.updateExtraHTTPHeaders();
|
||||
}
|
||||
async setUserAgent(userAgent) {
|
||||
this._options.userAgent = userAgent;
|
||||
for (const page of this.pages()) await page._delegate.updateUserAgent();
|
||||
// TODO: service workers don't have Emulation domain?
|
||||
}
|
||||
async setOffline(offline) {
|
||||
this._options.offline = offline;
|
||||
for (const page of this.pages()) await page._delegate.updateOffline();
|
||||
for (const sw of this.serviceWorkers()) await sw.updateOffline();
|
||||
}
|
||||
async doSetHTTPCredentials(httpCredentials) {
|
||||
this._options.httpCredentials = httpCredentials;
|
||||
for (const page of this.pages()) await page._delegate.updateHttpCredentials();
|
||||
for (const sw of this.serviceWorkers()) await sw.updateHttpCredentials();
|
||||
}
|
||||
async doAddInitScript(initScript) {
|
||||
for (const page of this.pages()) await page._delegate.addInitScript(initScript);
|
||||
}
|
||||
async doRemoveNonInternalInitScripts() {
|
||||
for (const page of this.pages()) await page._delegate.removeNonInternalInitScripts();
|
||||
}
|
||||
async doUpdateRequestInterception() {
|
||||
for (const page of this.pages()) await page._delegate.updateRequestInterception();
|
||||
for (const sw of this.serviceWorkers()) await sw.updateRequestInterception();
|
||||
}
|
||||
async doClose(reason) {
|
||||
// Headful chrome cannot dispose browser context with opened 'beforeunload'
|
||||
// dialogs, so we should close all that are currently opened.
|
||||
// We also won't get new ones since `Target.disposeBrowserContext` does not trigger
|
||||
// beforeunload.
|
||||
const openedBeforeUnloadDialogs = [];
|
||||
for (const crPage of this._crPages()) {
|
||||
const dialogs = [...crPage._page._frameManager._openedDialogs].filter(dialog => dialog.type() === 'beforeunload');
|
||||
openedBeforeUnloadDialogs.push(...dialogs);
|
||||
}
|
||||
await Promise.all(openedBeforeUnloadDialogs.map(dialog => dialog.dismiss()));
|
||||
if (!this._browserContextId) {
|
||||
await this.stopVideoRecording();
|
||||
// Closing persistent context should close the browser.
|
||||
await this._browser.close({
|
||||
reason
|
||||
});
|
||||
return;
|
||||
}
|
||||
await this._browser._session.send('Target.disposeBrowserContext', {
|
||||
browserContextId: this._browserContextId
|
||||
});
|
||||
this._browser._contexts.delete(this._browserContextId);
|
||||
for (const [targetId, serviceWorker] of this._browser._serviceWorkers) {
|
||||
if (serviceWorker._browserContext !== this) continue;
|
||||
// When closing a browser context, service workers are shutdown
|
||||
// asynchronously and we get detached from them later.
|
||||
// To avoid the wrong order of notifications, we manually fire
|
||||
// "close" event here and forget about the service worker.
|
||||
serviceWorker.didClose();
|
||||
this._browser._serviceWorkers.delete(targetId);
|
||||
}
|
||||
}
|
||||
async stopVideoRecording() {
|
||||
await Promise.all(this._crPages().map(crPage => crPage._mainFrameSession._stopVideoRecording()));
|
||||
}
|
||||
onClosePersistent() {
|
||||
// When persistent context is closed, we do not necessary get Target.detachedFromTarget
|
||||
// for all the background pages.
|
||||
for (const [targetId, backgroundPage] of this._browser._backgroundPages.entries()) {
|
||||
if (backgroundPage._browserContext === this && backgroundPage._page.initializedOrUndefined()) {
|
||||
backgroundPage.didClose();
|
||||
this._browser._backgroundPages.delete(targetId);
|
||||
}
|
||||
}
|
||||
}
|
||||
async clearCache() {
|
||||
for (const page of this._crPages()) await page._networkManager.clearCache();
|
||||
}
|
||||
async cancelDownload(guid) {
|
||||
// The upstream CDP method is implemented in a way that no explicit error would be given
|
||||
// regarding the requested `guid`, even if the download is in a state not suitable for
|
||||
// cancellation (finished, cancelled, etc.) or the guid is invalid at all.
|
||||
await this._browser._session.send('Browser.cancelDownload', {
|
||||
guid: guid,
|
||||
browserContextId: this._browserContextId
|
||||
});
|
||||
}
|
||||
backgroundPages() {
|
||||
const result = [];
|
||||
for (const backgroundPage of this._browser._backgroundPages.values()) {
|
||||
if (backgroundPage._browserContext === this && backgroundPage._page.initializedOrUndefined()) result.push(backgroundPage._page);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
serviceWorkers() {
|
||||
return Array.from(this._browser._serviceWorkers.values()).filter(serviceWorker => serviceWorker._browserContext === this);
|
||||
}
|
||||
async newCDPSession(page) {
|
||||
let targetId = null;
|
||||
if (page instanceof _page.Page) {
|
||||
targetId = page._delegate._targetId;
|
||||
} else if (page instanceof _frames.Frame) {
|
||||
const session = page._page._delegate._sessions.get(page._id);
|
||||
if (!session) throw new Error(`This frame does not have a separate CDP session, it is a part of the parent frame's session`);
|
||||
targetId = session._targetId;
|
||||
} else {
|
||||
throw new Error('page: expected Page or Frame');
|
||||
}
|
||||
const rootSession = await this._browser._clientRootSession();
|
||||
return rootSession.attachToTarget(targetId);
|
||||
}
|
||||
}
|
||||
exports.CRBrowserContext = CRBrowserContext;
|
||||
CRBrowserContext.CREvents = {
|
||||
BackgroundPage: 'backgroundpage',
|
||||
ServiceWorker: 'serviceworker'
|
||||
};
|
||||
228
node_modules/playwright-core/lib/server/chromium/crConnection.js
generated
vendored
Normal file
228
node_modules/playwright-core/lib/server/chromium/crConnection.js
generated
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.kBrowserCloseMessageId = exports.ConnectionEvents = exports.CRSession = exports.CRConnection = exports.CDPSession = void 0;
|
||||
var _events = require("events");
|
||||
var _utils = require("../../utils");
|
||||
var _debugLogger = require("../utils/debugLogger");
|
||||
var _helper = require("../helper");
|
||||
var _protocolError = require("../protocolError");
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const ConnectionEvents = exports.ConnectionEvents = {
|
||||
Disconnected: Symbol('ConnectionEvents.Disconnected')
|
||||
};
|
||||
|
||||
// CRPlaywright uses this special id to issue Browser.close command which we
|
||||
// should ignore.
|
||||
const kBrowserCloseMessageId = exports.kBrowserCloseMessageId = -9999;
|
||||
class CRConnection extends _events.EventEmitter {
|
||||
constructor(transport, protocolLogger, browserLogsCollector) {
|
||||
super();
|
||||
this._lastId = 0;
|
||||
this._transport = void 0;
|
||||
this._sessions = new Map();
|
||||
this._protocolLogger = void 0;
|
||||
this._browserLogsCollector = void 0;
|
||||
this._browserDisconnectedLogs = void 0;
|
||||
this.rootSession = void 0;
|
||||
this._closed = false;
|
||||
this.setMaxListeners(0);
|
||||
this._transport = transport;
|
||||
this._protocolLogger = protocolLogger;
|
||||
this._browserLogsCollector = browserLogsCollector;
|
||||
this.rootSession = new CRSession(this, null, '');
|
||||
this._sessions.set('', this.rootSession);
|
||||
this._transport.onmessage = this._onMessage.bind(this);
|
||||
// onclose should be set last, since it can be immediately called.
|
||||
this._transport.onclose = this._onClose.bind(this);
|
||||
}
|
||||
_rawSend(sessionId, method, params) {
|
||||
const id = ++this._lastId;
|
||||
const message = {
|
||||
id,
|
||||
method,
|
||||
params
|
||||
};
|
||||
if (sessionId) message.sessionId = sessionId;
|
||||
this._protocolLogger('send', message);
|
||||
this._transport.send(message);
|
||||
return id;
|
||||
}
|
||||
async _onMessage(message) {
|
||||
this._protocolLogger('receive', message);
|
||||
if (message.id === kBrowserCloseMessageId) return;
|
||||
const session = this._sessions.get(message.sessionId || '');
|
||||
if (session) session._onMessage(message);
|
||||
}
|
||||
_onClose(reason) {
|
||||
this._closed = true;
|
||||
this._transport.onmessage = undefined;
|
||||
this._transport.onclose = undefined;
|
||||
this._browserDisconnectedLogs = _helper.helper.formatBrowserLogs(this._browserLogsCollector.recentLogs(), reason);
|
||||
this.rootSession.dispose();
|
||||
Promise.resolve().then(() => this.emit(ConnectionEvents.Disconnected));
|
||||
}
|
||||
close() {
|
||||
if (!this._closed) this._transport.close();
|
||||
}
|
||||
async createBrowserSession() {
|
||||
const {
|
||||
sessionId
|
||||
} = await this.rootSession.send('Target.attachToBrowserTarget');
|
||||
return new CDPSession(this.rootSession, sessionId);
|
||||
}
|
||||
}
|
||||
exports.CRConnection = CRConnection;
|
||||
class CRSession extends _events.EventEmitter {
|
||||
constructor(connection, parentSession, sessionId, eventListener) {
|
||||
super();
|
||||
this._connection = void 0;
|
||||
this._eventListener = void 0;
|
||||
this._callbacks = new Map();
|
||||
this._sessionId = void 0;
|
||||
this._parentSession = void 0;
|
||||
this._crashed = false;
|
||||
this._closed = false;
|
||||
this.on = void 0;
|
||||
this.addListener = void 0;
|
||||
this.off = void 0;
|
||||
this.removeListener = void 0;
|
||||
this.once = void 0;
|
||||
this.setMaxListeners(0);
|
||||
this._connection = connection;
|
||||
this._parentSession = parentSession;
|
||||
this._sessionId = sessionId;
|
||||
this._eventListener = eventListener;
|
||||
this.on = super.on;
|
||||
this.addListener = super.addListener;
|
||||
this.off = super.removeListener;
|
||||
this.removeListener = super.removeListener;
|
||||
this.once = super.once;
|
||||
}
|
||||
_markAsCrashed() {
|
||||
this._crashed = true;
|
||||
}
|
||||
createChildSession(sessionId, eventListener) {
|
||||
const session = new CRSession(this._connection, this, sessionId, eventListener);
|
||||
this._connection._sessions.set(sessionId, session);
|
||||
return session;
|
||||
}
|
||||
async send(method, params) {
|
||||
if (this._crashed || this._closed || this._connection._closed || this._connection._browserDisconnectedLogs) throw new _protocolError.ProtocolError(this._crashed ? 'crashed' : 'closed', undefined, this._connection._browserDisconnectedLogs);
|
||||
const id = this._connection._rawSend(this._sessionId, method, params);
|
||||
return new Promise((resolve, reject) => {
|
||||
this._callbacks.set(id, {
|
||||
resolve,
|
||||
reject,
|
||||
error: new _protocolError.ProtocolError('error', method)
|
||||
});
|
||||
});
|
||||
}
|
||||
_sendMayFail(method, params) {
|
||||
return this.send(method, params).catch(error => _debugLogger.debugLogger.log('error', error));
|
||||
}
|
||||
_onMessage(object) {
|
||||
var _object$error;
|
||||
if (object.id && this._callbacks.has(object.id)) {
|
||||
const callback = this._callbacks.get(object.id);
|
||||
this._callbacks.delete(object.id);
|
||||
if (object.error) {
|
||||
callback.error.setMessage(object.error.message);
|
||||
callback.reject(callback.error);
|
||||
} else {
|
||||
callback.resolve(object.result);
|
||||
}
|
||||
} else if (object.id && ((_object$error = object.error) === null || _object$error === void 0 ? void 0 : _object$error.code) === -32001) {
|
||||
// Message to a closed session, just ignore it.
|
||||
} else {
|
||||
var _object$error2;
|
||||
(0, _utils.assert)(!object.id, (object === null || object === void 0 || (_object$error2 = object.error) === null || _object$error2 === void 0 ? void 0 : _object$error2.message) || undefined);
|
||||
Promise.resolve().then(() => {
|
||||
if (this._eventListener) this._eventListener(object.method, object.params);
|
||||
this.emit(object.method, object.params);
|
||||
});
|
||||
}
|
||||
}
|
||||
async detach() {
|
||||
if (this._closed) throw new Error(`Session already detached. Most likely the page has been closed.`);
|
||||
if (!this._parentSession) throw new Error('Root session cannot be closed');
|
||||
// Ideally, detaching should resume any target, but there is a bug in the backend,
|
||||
// so we must Runtime.runIfWaitingForDebugger first.
|
||||
await this._sendMayFail('Runtime.runIfWaitingForDebugger');
|
||||
await this._parentSession.send('Target.detachFromTarget', {
|
||||
sessionId: this._sessionId
|
||||
});
|
||||
this.dispose();
|
||||
}
|
||||
dispose() {
|
||||
this._closed = true;
|
||||
this._connection._sessions.delete(this._sessionId);
|
||||
for (const callback of this._callbacks.values()) {
|
||||
callback.error.setMessage(`Internal server error, session closed.`);
|
||||
callback.error.type = this._crashed ? 'crashed' : 'closed';
|
||||
callback.error.logs = this._connection._browserDisconnectedLogs;
|
||||
callback.reject(callback.error);
|
||||
}
|
||||
this._callbacks.clear();
|
||||
}
|
||||
}
|
||||
exports.CRSession = CRSession;
|
||||
class CDPSession extends _events.EventEmitter {
|
||||
constructor(parentSession, sessionId) {
|
||||
super();
|
||||
this.guid = void 0;
|
||||
this._session = void 0;
|
||||
this._listeners = [];
|
||||
this.guid = `cdp-session@${sessionId}`;
|
||||
this._session = parentSession.createChildSession(sessionId, (method, params) => this.emit(CDPSession.Events.Event, {
|
||||
method,
|
||||
params
|
||||
}));
|
||||
this._listeners = [_utils.eventsHelper.addEventListener(parentSession, 'Target.detachedFromTarget', event => {
|
||||
if (event.sessionId === sessionId) this._onClose();
|
||||
})];
|
||||
}
|
||||
async send(method, params) {
|
||||
return await this._session.send(method, params);
|
||||
}
|
||||
async detach() {
|
||||
return await this._session.detach();
|
||||
}
|
||||
async attachToTarget(targetId) {
|
||||
const {
|
||||
sessionId
|
||||
} = await this.send('Target.attachToTarget', {
|
||||
targetId,
|
||||
flatten: true
|
||||
});
|
||||
return new CDPSession(this._session, sessionId);
|
||||
}
|
||||
_onClose() {
|
||||
_utils.eventsHelper.removeEventListeners(this._listeners);
|
||||
this._session.dispose();
|
||||
this.emit(CDPSession.Events.Closed);
|
||||
}
|
||||
}
|
||||
exports.CDPSession = CDPSession;
|
||||
CDPSession.Events = {
|
||||
Event: 'event',
|
||||
Closed: 'close'
|
||||
};
|
||||
246
node_modules/playwright-core/lib/server/chromium/crCoverage.js
generated
vendored
Normal file
246
node_modules/playwright-core/lib/server/chromium/crCoverage.js
generated
vendored
Normal file
@@ -0,0 +1,246 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.CRCoverage = void 0;
|
||||
var _utils = require("../../utils");
|
||||
var _eventsHelper = require("../utils/eventsHelper");
|
||||
/**
|
||||
* Copyright 2017 Google Inc. All rights reserved.
|
||||
* Modifications copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class CRCoverage {
|
||||
constructor(client) {
|
||||
this._jsCoverage = void 0;
|
||||
this._cssCoverage = void 0;
|
||||
this._jsCoverage = new JSCoverage(client);
|
||||
this._cssCoverage = new CSSCoverage(client);
|
||||
}
|
||||
async startJSCoverage(options) {
|
||||
return await this._jsCoverage.start(options);
|
||||
}
|
||||
async stopJSCoverage() {
|
||||
return await this._jsCoverage.stop();
|
||||
}
|
||||
async startCSSCoverage(options) {
|
||||
return await this._cssCoverage.start(options);
|
||||
}
|
||||
async stopCSSCoverage() {
|
||||
return await this._cssCoverage.stop();
|
||||
}
|
||||
}
|
||||
exports.CRCoverage = CRCoverage;
|
||||
class JSCoverage {
|
||||
constructor(client) {
|
||||
this._client = void 0;
|
||||
this._enabled = void 0;
|
||||
this._scriptIds = void 0;
|
||||
this._scriptSources = void 0;
|
||||
this._eventListeners = void 0;
|
||||
this._resetOnNavigation = void 0;
|
||||
this._reportAnonymousScripts = false;
|
||||
this._client = client;
|
||||
this._enabled = false;
|
||||
this._scriptIds = new Set();
|
||||
this._scriptSources = new Map();
|
||||
this._eventListeners = [];
|
||||
this._resetOnNavigation = false;
|
||||
}
|
||||
async start(options) {
|
||||
(0, _utils.assert)(!this._enabled, 'JSCoverage is already enabled');
|
||||
const {
|
||||
resetOnNavigation = true,
|
||||
reportAnonymousScripts = false
|
||||
} = options;
|
||||
this._resetOnNavigation = resetOnNavigation;
|
||||
this._reportAnonymousScripts = reportAnonymousScripts;
|
||||
this._enabled = true;
|
||||
this._scriptIds.clear();
|
||||
this._scriptSources.clear();
|
||||
this._eventListeners = [_eventsHelper.eventsHelper.addEventListener(this._client, 'Debugger.scriptParsed', this._onScriptParsed.bind(this)), _eventsHelper.eventsHelper.addEventListener(this._client, 'Runtime.executionContextsCleared', this._onExecutionContextsCleared.bind(this)), _eventsHelper.eventsHelper.addEventListener(this._client, 'Debugger.paused', this._onDebuggerPaused.bind(this))];
|
||||
await Promise.all([this._client.send('Profiler.enable'), this._client.send('Profiler.startPreciseCoverage', {
|
||||
callCount: true,
|
||||
detailed: true
|
||||
}), this._client.send('Debugger.enable'), this._client.send('Debugger.setSkipAllPauses', {
|
||||
skip: true
|
||||
})]);
|
||||
}
|
||||
_onDebuggerPaused() {
|
||||
this._client.send('Debugger.resume');
|
||||
}
|
||||
_onExecutionContextsCleared() {
|
||||
if (!this._resetOnNavigation) return;
|
||||
this._scriptIds.clear();
|
||||
this._scriptSources.clear();
|
||||
}
|
||||
async _onScriptParsed(event) {
|
||||
this._scriptIds.add(event.scriptId);
|
||||
// Ignore other anonymous scripts unless the reportAnonymousScripts option is true.
|
||||
if (!event.url && !this._reportAnonymousScripts) return;
|
||||
// This might fail if the page has already navigated away.
|
||||
const response = await this._client._sendMayFail('Debugger.getScriptSource', {
|
||||
scriptId: event.scriptId
|
||||
});
|
||||
if (response) this._scriptSources.set(event.scriptId, response.scriptSource);
|
||||
}
|
||||
async stop() {
|
||||
(0, _utils.assert)(this._enabled, 'JSCoverage is not enabled');
|
||||
this._enabled = false;
|
||||
const [profileResponse] = await Promise.all([this._client.send('Profiler.takePreciseCoverage'), this._client.send('Profiler.stopPreciseCoverage'), this._client.send('Profiler.disable'), this._client.send('Debugger.disable')]);
|
||||
_eventsHelper.eventsHelper.removeEventListeners(this._eventListeners);
|
||||
const coverage = {
|
||||
entries: []
|
||||
};
|
||||
for (const entry of profileResponse.result) {
|
||||
if (!this._scriptIds.has(entry.scriptId)) continue;
|
||||
if (!entry.url && !this._reportAnonymousScripts) continue;
|
||||
const source = this._scriptSources.get(entry.scriptId);
|
||||
if (source) coverage.entries.push({
|
||||
...entry,
|
||||
source
|
||||
});else coverage.entries.push(entry);
|
||||
}
|
||||
return coverage;
|
||||
}
|
||||
}
|
||||
class CSSCoverage {
|
||||
constructor(client) {
|
||||
this._client = void 0;
|
||||
this._enabled = void 0;
|
||||
this._stylesheetURLs = void 0;
|
||||
this._stylesheetSources = void 0;
|
||||
this._eventListeners = void 0;
|
||||
this._resetOnNavigation = void 0;
|
||||
this._client = client;
|
||||
this._enabled = false;
|
||||
this._stylesheetURLs = new Map();
|
||||
this._stylesheetSources = new Map();
|
||||
this._eventListeners = [];
|
||||
this._resetOnNavigation = false;
|
||||
}
|
||||
async start(options) {
|
||||
(0, _utils.assert)(!this._enabled, 'CSSCoverage is already enabled');
|
||||
const {
|
||||
resetOnNavigation = true
|
||||
} = options;
|
||||
this._resetOnNavigation = resetOnNavigation;
|
||||
this._enabled = true;
|
||||
this._stylesheetURLs.clear();
|
||||
this._stylesheetSources.clear();
|
||||
this._eventListeners = [_eventsHelper.eventsHelper.addEventListener(this._client, 'CSS.styleSheetAdded', this._onStyleSheet.bind(this)), _eventsHelper.eventsHelper.addEventListener(this._client, 'Runtime.executionContextsCleared', this._onExecutionContextsCleared.bind(this))];
|
||||
await Promise.all([this._client.send('DOM.enable'), this._client.send('CSS.enable'), this._client.send('CSS.startRuleUsageTracking')]);
|
||||
}
|
||||
_onExecutionContextsCleared() {
|
||||
if (!this._resetOnNavigation) return;
|
||||
this._stylesheetURLs.clear();
|
||||
this._stylesheetSources.clear();
|
||||
}
|
||||
async _onStyleSheet(event) {
|
||||
const header = event.header;
|
||||
// Ignore anonymous scripts
|
||||
if (!header.sourceURL) return;
|
||||
// This might fail if the page has already navigated away.
|
||||
const response = await this._client._sendMayFail('CSS.getStyleSheetText', {
|
||||
styleSheetId: header.styleSheetId
|
||||
});
|
||||
if (response) {
|
||||
this._stylesheetURLs.set(header.styleSheetId, header.sourceURL);
|
||||
this._stylesheetSources.set(header.styleSheetId, response.text);
|
||||
}
|
||||
}
|
||||
async stop() {
|
||||
(0, _utils.assert)(this._enabled, 'CSSCoverage is not enabled');
|
||||
this._enabled = false;
|
||||
const ruleTrackingResponse = await this._client.send('CSS.stopRuleUsageTracking');
|
||||
await Promise.all([this._client.send('CSS.disable'), this._client.send('DOM.disable')]);
|
||||
_eventsHelper.eventsHelper.removeEventListeners(this._eventListeners);
|
||||
|
||||
// aggregate by styleSheetId
|
||||
const styleSheetIdToCoverage = new Map();
|
||||
for (const entry of ruleTrackingResponse.ruleUsage) {
|
||||
let ranges = styleSheetIdToCoverage.get(entry.styleSheetId);
|
||||
if (!ranges) {
|
||||
ranges = [];
|
||||
styleSheetIdToCoverage.set(entry.styleSheetId, ranges);
|
||||
}
|
||||
ranges.push({
|
||||
startOffset: entry.startOffset,
|
||||
endOffset: entry.endOffset,
|
||||
count: entry.used ? 1 : 0
|
||||
});
|
||||
}
|
||||
const coverage = {
|
||||
entries: []
|
||||
};
|
||||
for (const styleSheetId of this._stylesheetURLs.keys()) {
|
||||
const url = this._stylesheetURLs.get(styleSheetId);
|
||||
const text = this._stylesheetSources.get(styleSheetId);
|
||||
const ranges = convertToDisjointRanges(styleSheetIdToCoverage.get(styleSheetId) || []);
|
||||
coverage.entries.push({
|
||||
url,
|
||||
ranges,
|
||||
text
|
||||
});
|
||||
}
|
||||
return coverage;
|
||||
}
|
||||
}
|
||||
function convertToDisjointRanges(nestedRanges) {
|
||||
const points = [];
|
||||
for (const range of nestedRanges) {
|
||||
points.push({
|
||||
offset: range.startOffset,
|
||||
type: 0,
|
||||
range
|
||||
});
|
||||
points.push({
|
||||
offset: range.endOffset,
|
||||
type: 1,
|
||||
range
|
||||
});
|
||||
}
|
||||
// Sort points to form a valid parenthesis sequence.
|
||||
points.sort((a, b) => {
|
||||
// Sort with increasing offsets.
|
||||
if (a.offset !== b.offset) return a.offset - b.offset;
|
||||
// All "end" points should go before "start" points.
|
||||
if (a.type !== b.type) return b.type - a.type;
|
||||
const aLength = a.range.endOffset - a.range.startOffset;
|
||||
const bLength = b.range.endOffset - b.range.startOffset;
|
||||
// For two "start" points, the one with longer range goes first.
|
||||
if (a.type === 0) return bLength - aLength;
|
||||
// For two "end" points, the one with shorter range goes first.
|
||||
return aLength - bLength;
|
||||
});
|
||||
const hitCountStack = [];
|
||||
const results = [];
|
||||
let lastOffset = 0;
|
||||
// Run scanning line to intersect all ranges.
|
||||
for (const point of points) {
|
||||
if (hitCountStack.length && lastOffset < point.offset && hitCountStack[hitCountStack.length - 1] > 0) {
|
||||
const lastResult = results.length ? results[results.length - 1] : null;
|
||||
if (lastResult && lastResult.end === lastOffset) lastResult.end = point.offset;else results.push({
|
||||
start: lastOffset,
|
||||
end: point.offset
|
||||
});
|
||||
}
|
||||
lastOffset = point.offset;
|
||||
if (point.type === 0) hitCountStack.push(point.range.count);else hitCountStack.pop();
|
||||
}
|
||||
// Filter out empty ranges.
|
||||
return results.filter(range => range.end - range.start > 1);
|
||||
}
|
||||
104
node_modules/playwright-core/lib/server/chromium/crDevTools.js
generated
vendored
Normal file
104
node_modules/playwright-core/lib/server/chromium/crDevTools.js
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.CRDevTools = void 0;
|
||||
var _fs = _interopRequireDefault(require("fs"));
|
||||
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const kBindingName = '__pw_devtools__';
|
||||
|
||||
// This class intercepts preferences-related DevTools embedder methods
|
||||
// and stores preferences as a json file in the browser installation directory.
|
||||
class CRDevTools {
|
||||
constructor(preferencesPath) {
|
||||
this._preferencesPath = void 0;
|
||||
this._prefs = void 0;
|
||||
this._savePromise = void 0;
|
||||
this.__testHookOnBinding = void 0;
|
||||
this._preferencesPath = preferencesPath;
|
||||
this._savePromise = Promise.resolve();
|
||||
}
|
||||
install(session) {
|
||||
session.on('Runtime.bindingCalled', async event => {
|
||||
if (event.name !== kBindingName) return;
|
||||
const parsed = JSON.parse(event.payload);
|
||||
let result = undefined;
|
||||
if (this.__testHookOnBinding) this.__testHookOnBinding(parsed);
|
||||
if (parsed.method === 'getPreferences') {
|
||||
if (this._prefs === undefined) {
|
||||
try {
|
||||
const json = await _fs.default.promises.readFile(this._preferencesPath, 'utf8');
|
||||
this._prefs = JSON.parse(json);
|
||||
} catch (e) {
|
||||
this._prefs = {};
|
||||
}
|
||||
}
|
||||
result = this._prefs;
|
||||
} else if (parsed.method === 'setPreference') {
|
||||
this._prefs[parsed.params[0]] = parsed.params[1];
|
||||
this._save();
|
||||
} else if (parsed.method === 'removePreference') {
|
||||
delete this._prefs[parsed.params[0]];
|
||||
this._save();
|
||||
} else if (parsed.method === 'clearPreferences') {
|
||||
this._prefs = {};
|
||||
this._save();
|
||||
}
|
||||
session.send('Runtime.evaluate', {
|
||||
expression: `window.DevToolsAPI.embedderMessageAck(${parsed.id}, ${JSON.stringify(result)})`,
|
||||
contextId: event.executionContextId
|
||||
}).catch(e => null);
|
||||
});
|
||||
Promise.all([session.send('Runtime.enable'), session.send('Runtime.addBinding', {
|
||||
name: kBindingName
|
||||
}), session.send('Page.enable'), session.send('Page.addScriptToEvaluateOnNewDocument', {
|
||||
source: `
|
||||
(() => {
|
||||
const init = () => {
|
||||
// Lazy init happens when InspectorFrontendHost is initialized.
|
||||
// At this point DevToolsHost is ready to be used.
|
||||
const host = window.DevToolsHost;
|
||||
const old = host.sendMessageToEmbedder.bind(host);
|
||||
host.sendMessageToEmbedder = message => {
|
||||
if (['getPreferences', 'setPreference', 'removePreference', 'clearPreferences'].includes(JSON.parse(message).method))
|
||||
window.${kBindingName}(message);
|
||||
else
|
||||
old(message);
|
||||
};
|
||||
};
|
||||
let value;
|
||||
Object.defineProperty(window, 'InspectorFrontendHost', {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get() { return value; },
|
||||
set(v) { value = v; init(); },
|
||||
});
|
||||
})()
|
||||
`
|
||||
}), session.send('Runtime.runIfWaitingForDebugger')]).catch(e => null);
|
||||
}
|
||||
_save() {
|
||||
// Serialize saves to avoid corruption.
|
||||
this._savePromise = this._savePromise.then(async () => {
|
||||
await _fs.default.promises.writeFile(this._preferencesPath, JSON.stringify(this._prefs)).catch(e => null);
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.CRDevTools = CRDevTools;
|
||||
143
node_modules/playwright-core/lib/server/chromium/crDragDrop.js
generated
vendored
Normal file
143
node_modules/playwright-core/lib/server/chromium/crDragDrop.js
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.DragManager = void 0;
|
||||
var _crProtocolHelper = require("./crProtocolHelper");
|
||||
var _utils = require("../../utils");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class DragManager {
|
||||
constructor(page) {
|
||||
this._crPage = void 0;
|
||||
this._dragState = null;
|
||||
this._lastPosition = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
this._crPage = page;
|
||||
}
|
||||
async cancelDrag() {
|
||||
if (!this._dragState) return false;
|
||||
await this._crPage._mainFrameSession._client.send('Input.dispatchDragEvent', {
|
||||
type: 'dragCancel',
|
||||
x: this._lastPosition.x,
|
||||
y: this._lastPosition.y,
|
||||
data: {
|
||||
items: [],
|
||||
dragOperationsMask: 0xFFFF
|
||||
}
|
||||
});
|
||||
this._dragState = null;
|
||||
return true;
|
||||
}
|
||||
async interceptDragCausedByMove(x, y, button, buttons, modifiers, moveCallback) {
|
||||
this._lastPosition = {
|
||||
x,
|
||||
y
|
||||
};
|
||||
if (this._dragState) {
|
||||
await this._crPage._mainFrameSession._client.send('Input.dispatchDragEvent', {
|
||||
type: 'dragOver',
|
||||
x,
|
||||
y,
|
||||
data: this._dragState,
|
||||
modifiers: (0, _crProtocolHelper.toModifiersMask)(modifiers)
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (button !== 'left') return moveCallback();
|
||||
const client = this._crPage._mainFrameSession._client;
|
||||
let onDragIntercepted;
|
||||
const dragInterceptedPromise = new Promise(x => onDragIntercepted = x);
|
||||
function setupDragListeners() {
|
||||
let didStartDrag = Promise.resolve(false);
|
||||
let dragEvent = null;
|
||||
const dragListener = event => dragEvent = event;
|
||||
const mouseListener = () => {
|
||||
didStartDrag = new Promise(callback => {
|
||||
window.addEventListener('dragstart', dragListener, {
|
||||
once: true,
|
||||
capture: true
|
||||
});
|
||||
setTimeout(() => callback(dragEvent ? !dragEvent.defaultPrevented : false), 0);
|
||||
});
|
||||
};
|
||||
window.addEventListener('mousemove', mouseListener, {
|
||||
once: true,
|
||||
capture: true
|
||||
});
|
||||
window.__cleanupDrag = async () => {
|
||||
const val = await didStartDrag;
|
||||
window.removeEventListener('mousemove', mouseListener, {
|
||||
capture: true
|
||||
});
|
||||
window.removeEventListener('dragstart', dragListener, {
|
||||
capture: true
|
||||
});
|
||||
delete window.__cleanupDrag;
|
||||
return val;
|
||||
};
|
||||
}
|
||||
await this._crPage._page.safeNonStallingEvaluateInAllFrames(`(${setupDragListeners.toString()})()`, 'utility');
|
||||
client.on('Input.dragIntercepted', onDragIntercepted);
|
||||
try {
|
||||
await client.send('Input.setInterceptDrags', {
|
||||
enabled: true
|
||||
});
|
||||
} catch {
|
||||
// If Input.setInterceptDrags is not supported, just do a regular move.
|
||||
// This can be removed once we stop supporting old Electron.
|
||||
client.off('Input.dragIntercepted', onDragIntercepted);
|
||||
return moveCallback();
|
||||
}
|
||||
await moveCallback();
|
||||
const expectingDrag = (await Promise.all(this._crPage._page.frames().map(async frame => {
|
||||
return frame.nonStallingEvaluateInExistingContext('window.__cleanupDrag && window.__cleanupDrag()', 'utility').catch(() => false);
|
||||
}))).some(x => x);
|
||||
this._dragState = expectingDrag ? (await dragInterceptedPromise).data : null;
|
||||
client.off('Input.dragIntercepted', onDragIntercepted);
|
||||
await client.send('Input.setInterceptDrags', {
|
||||
enabled: false
|
||||
});
|
||||
if (this._dragState) {
|
||||
await this._crPage._mainFrameSession._client.send('Input.dispatchDragEvent', {
|
||||
type: 'dragEnter',
|
||||
x,
|
||||
y,
|
||||
data: this._dragState,
|
||||
modifiers: (0, _crProtocolHelper.toModifiersMask)(modifiers)
|
||||
});
|
||||
}
|
||||
}
|
||||
isDragging() {
|
||||
return !!this._dragState;
|
||||
}
|
||||
async drop(x, y, modifiers) {
|
||||
(0, _utils.assert)(this._dragState, 'missing drag state');
|
||||
await this._crPage._mainFrameSession._client.send('Input.dispatchDragEvent', {
|
||||
type: 'drop',
|
||||
x,
|
||||
y,
|
||||
data: this._dragState,
|
||||
modifiers: (0, _crProtocolHelper.toModifiersMask)(modifiers)
|
||||
});
|
||||
this._dragState = null;
|
||||
}
|
||||
}
|
||||
exports.DragManager = DragManager;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user