screenshot/test_1

This commit is contained in:
ramkumarp
2025-03-27 11:21:02 +00:00
commit 616d466383
470 changed files with 144705 additions and 0 deletions

69
node_modules/playwright-core/lib/androidServerImpl.js generated vendored Normal file
View 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
View 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
View 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
View 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`;
}
}
}

View 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();

View 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
View 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
View 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
View 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
View 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;

View 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
View 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
View 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
View 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()}`);
}

View 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, '')}`;
}

View 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];
}
});
}

View 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
View 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
View 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'))}
`;
}

View 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
View 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
View 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
View 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
View 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;

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;

View 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;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

59
node_modules/playwright-core/lib/inProcessFactory.js generated vendored Normal file
View 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
View 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
View 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
View 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']);

View 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

File diff suppressed because it is too large Load Diff

View 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;

View 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'];

View 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);
}
}

View 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];
}

View 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();
}
}

View 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
View 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;

View 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 = {}));

View 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');

View 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;

View 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));
}

View 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');
}
}

View 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);
}

View 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;
}

View 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();
}
}

View 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
View 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;

View 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;

View 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;

View 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 = {}));

View 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;

View 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
View 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'
};

View 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
View 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
View 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;

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View 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}`);
}
}

View 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'];

View 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;
}
}

View 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'
};

View 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'
};

View 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);
}

View 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;

View 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