Socket
Socket
Sign inDemoInstall

puppeteer-core

Package Overview
Dependencies
Maintainers
8
Versions
239
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

puppeteer-core - npm Package Compare versions

Comparing version 5.3.1 to 5.4.0

lib/cjs/puppeteer/common/AriaQueryHandler.d.ts

2

cjs-entry-core.js

@@ -28,3 +28,3 @@ /**

*/
const puppeteerExport = require('./lib/cjs/puppeteer/index-core');
const puppeteerExport = require('./lib/cjs/puppeteer/node-puppeteer-core');
module.exports = puppeteerExport.default;

@@ -28,3 +28,3 @@ /**

*/
const puppeteerExport = require('./lib/cjs/puppeteer/index');
const puppeteerExport = require('./lib/cjs/puppeteer/node');
module.exports = puppeteerExport.default;

@@ -35,3 +35,3 @@ /**

logPolitely,
} = require('./lib/cjs/puppeteer/install');
} = require('./lib/cjs/puppeteer/node/install');

@@ -38,0 +38,0 @@ if (process.env.PUPPETEER_SKIP_DOWNLOAD) {

@@ -19,2 +19,3 @@ /**

export * from './node/BrowserFetcher.js';
export * from './node/Puppeteer.js';
export * from './common/Connection.js';

@@ -33,5 +34,7 @@ export * from './common/ConsoleMessage.js';

export * from './common/Page.js';
export * from './common/Product.js';
export * from './common/Puppeteer.js';
export * from './common/BrowserConnector.js';
export * from './node/Launcher.js';
export * from './node/LaunchOptions.js';
export * from './node/Launcher.js';
export * from './common/HTTPRequest.js';

@@ -50,3 +53,4 @@ export * from './common/HTTPResponse.js';

export * from './common/LifecycleWatcher.js';
export * from './common/QueryHandler.js';
export * from 'devtools-protocol/types/protocol';
//# sourceMappingURL=api-docs-entry.d.ts.map

@@ -33,4 +33,5 @@ "use strict";

*
* We also have src/api.ts. This is used in `index.js` and by the legacy DocLint
* system. src/api-docs-entry.ts is ONLY used by API Extractor.
* The legacy DocLint system and the unit test coverage system use the list of
* modules defined in coverage-utils.js. src/api-docs-entry.ts is ONLY used by
* API Extractor.
*

@@ -43,2 +44,3 @@ * Once we have migrated to API Extractor and removed DocLint we can remove the

__exportStar(require("./node/BrowserFetcher.js"), exports);
__exportStar(require("./node/Puppeteer.js"), exports);
__exportStar(require("./common/Connection.js"), exports);

@@ -57,5 +59,7 @@ __exportStar(require("./common/ConsoleMessage.js"), exports);

__exportStar(require("./common/Page.js"), exports);
__exportStar(require("./common/Product.js"), exports);
__exportStar(require("./common/Puppeteer.js"), exports);
__exportStar(require("./common/BrowserConnector.js"), exports);
__exportStar(require("./node/Launcher.js"), exports);
__exportStar(require("./node/LaunchOptions.js"), exports);
__exportStar(require("./node/Launcher.js"), exports);
__exportStar(require("./common/HTTPRequest.js"), exports);

@@ -74,2 +78,3 @@ __exportStar(require("./common/HTTPResponse.js"), exports);

__exportStar(require("./common/LifecycleWatcher.js"), exports);
__exportStar(require("./common/QueryHandler.js"), exports);
__exportStar(require("devtools-protocol/types/protocol"), exports);

@@ -20,3 +20,2 @@ /**

import { Connection } from './Connection.js';
import { Protocol } from 'devtools-protocol';
import { Page } from './Page.js';

@@ -83,3 +82,3 @@ import { ChildProcess } from 'child_process';

* A Browser is created when Puppeteer connects to a Chromium instance, either through
* {@link Puppeteer.launch} or {@link Puppeteer.connect}.
* {@link PuppeteerNode.launch} or {@link Puppeteer.connect}.
*

@@ -393,3 +392,3 @@ * @remarks

*/
overridePermissions(origin: string, permissions: Protocol.Browser.PermissionType[]): Promise<void>;
overridePermissions(origin: string, permissions: string[]): Promise<void>;
/**

@@ -396,0 +395,0 @@ * Clears all permission overrides for the browser context.

@@ -26,3 +26,3 @@ "use strict";

* A Browser is created when Puppeteer connects to a Chromium instance, either through
* {@link Puppeteer.launch} or {@link Puppeteer.connect}.
* {@link PuppeteerNode.launch} or {@link Puppeteer.connect}.
*

@@ -469,3 +469,3 @@ * @remarks

]);
permissions = permissions.map((permission) => {
const protocolPermissions = permissions.map((permission) => {
const protocolPermission = webPermissionToProtocol.get(permission);

@@ -479,3 +479,3 @@ if (!protocolPermission)

browserContextId: this._id || undefined,
permissions,
permissions: protocolPermissions,
});

@@ -482,0 +482,0 @@ }

@@ -39,3 +39,3 @@ import { Protocol } from 'devtools-protocol';

send<T extends keyof ProtocolMapping.Commands>(method: T, ...paramArgs: ProtocolMapping.Commands[T]['paramsType']): Promise<ProtocolMapping.Commands[T]['returnType']>;
_rawSend(message: {}): number;
_rawSend(message: Record<string, unknown>): number;
_onMessage(message: string): Promise<void>;

@@ -53,3 +53,3 @@ _onClose(): void;

method: string;
params: {};
params: Record<string, unknown>;
error: {

@@ -56,0 +56,0 @@ message: string;

@@ -76,5 +76,5 @@ "use strict";

const id = ++this._lastId;
message = JSON.stringify(Object.assign({}, message, { id }));
debugProtocolSend(message);
this._transport.send(message);
const stringifiedMessage = JSON.stringify(Object.assign({}, message, { id }));
debugProtocolSend(stringifiedMessage);
this._transport.send(stringifiedMessage);
return id;

@@ -81,0 +81,0 @@ }

@@ -46,7 +46,7 @@ /**

private _args;
private _location;
private _stackTraceLocations;
/**
* @public
*/
constructor(type: ConsoleMessageType, text: string, args: JSHandle[], location?: ConsoleMessageLocation);
constructor(type: ConsoleMessageType, text: string, args: JSHandle[], stackTraceLocations: ConsoleMessageLocation[]);
/**

@@ -68,3 +68,7 @@ * @returns The type of the console message.

location(): ConsoleMessageLocation;
/**
* @returns The array of locations on the stack of the console message.
*/
stackTrace(): ConsoleMessageLocation[];
}
//# sourceMappingURL=ConsoleMessage.d.ts.map

@@ -27,7 +27,7 @@ "use strict";

*/
constructor(type, text, args, location = {}) {
constructor(type, text, args, stackTraceLocations) {
this._type = type;
this._text = text;
this._args = args;
this._location = location;
this._stackTraceLocations = stackTraceLocations;
}

@@ -56,5 +56,11 @@ /**

location() {
return this._location;
return this._stackTraceLocations.length ? this._stackTraceLocations[0] : {};
}
/**
* @returns The array of locations on the stack of the console message.
*/
stackTrace() {
return this._stackTraceLocations;
}
}
exports.ConsoleMessage = ConsoleMessage;

@@ -47,5 +47,7 @@ /**

_waitTasks: Set<WaitTask>;
private _boundFunctions;
private _ctxBindings;
constructor(frameManager: FrameManager, frame: Frame, timeoutSettings: TimeoutSettings);
frame(): Frame;
_setContext(context?: ExecutionContext): void;
_setContext(context?: ExecutionContext): Promise<void>;
_hasContext(): boolean;

@@ -110,4 +112,17 @@ _detach(): void;

waitForSelector(selector: string, options: WaitForSelectorOptions): Promise<ElementHandle | null>;
private _settingUpBinding;
/**
* @internal
*/
addBindingToContext(name: string): any;
/**
* @internal
*/
addBinding(name: string, puppeteerFunction: Function): Promise<void>;
private _onBindingCalled;
/**
* @internal
*/
waitForSelectorInPage(queryOne: Function, selector: string, options: WaitForSelectorOptions): Promise<ElementHandle | null>;
waitForXPath(xpath: string, options: WaitForSelectorOptions): Promise<ElementHandle | null>;
private _makePredicateString;
waitForFunction(pageFunction: Function | string, options?: {

@@ -119,3 +134,6 @@ polling?: string | number;

}
declare class WaitTask {
/**
* @internal
*/
export declare class WaitTask {
_domWorld: DOMWorld;

@@ -137,3 +155,2 @@ _polling: string | number;

}
export {};
//# sourceMappingURL=DOMWorld.d.ts.map

@@ -17,4 +17,23 @@ "use strict";

*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DOMWorld = void 0;
exports.WaitTask = exports.DOMWorld = void 0;
const assert_js_1 = require("./assert.js");

@@ -39,2 +58,9 @@ const helper_js_1 = require("./helper.js");

this._waitTasks = new Set();
// Contains mapping from functions that should be bound to Puppeteer functions.
this._boundFunctions = new Map();
// Set of bindings that have been registered in the current context.
this._ctxBindings = new Set();
// If multiple waitFor are set up asynchronously, we need to wait for the
// first one to set up the binding in the page before running the others.
this._settingUpBinding = null;
this._frameManager = frameManager;

@@ -44,2 +70,3 @@ this._frame = frame;

this._setContext(null);
frameManager._client.on('Runtime.bindingCalled', (event) => this._onBindingCalled(event));
}

@@ -49,6 +76,10 @@ frame() {

}
_setContext(context) {
async _setContext(context) {
if (context) {
this._contextResolveCallback.call(null, context);
this._contextResolveCallback = null;
this._ctxBindings.clear();
for (const name of this._boundFunctions.keys()) {
await this.addBindingToContext(name);
}
for (const waitTask of this._waitTasks)

@@ -74,3 +105,3 @@ waitTask.rerun();

if (this._detached)
throw new Error(`Execution Context is not available in detached frame "${this._frame.url()}" (are you trying to evaluate?)`);
throw new Error(`Execution context is not available in detached frame "${this._frame.url()}" (are you trying to evaluate?)`);
return this._contextPromise;

@@ -171,8 +202,4 @@ }

}
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fs = require('fs');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { promisify } = require('util');
const readFileAsync = promisify(fs.readFile);
let contents = await readFileAsync(path, 'utf8');
const fs = await Promise.resolve().then(() => __importStar(require('fs')));
let contents = await fs.promises.readFile(path, 'utf8');
contents += '//# sourceURL=' + path.replace(/\n/g, '');

@@ -237,8 +264,4 @@ const context = await this.executionContext();

}
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fs = require('fs');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { promisify } = require('util');
const readFileAsync = promisify(fs.readFile);
let contents = await readFileAsync(path, 'utf8');
const fs = await Promise.resolve().then(() => __importStar(require('fs')));
let contents = await fs.promises.readFile(path, 'utf8');
contents += '/*# sourceURL=' + path.replace(/\n/g, '') + '*/';

@@ -305,3 +328,2 @@ const context = await this.executionContext();

const handle = await this.$(selector);
assert_js_1.assert(handle, 'No node found for selector: ' + selector);
await handle.tap();

@@ -317,13 +339,106 @@ await handle.dispose();

async waitForSelector(selector, options) {
const { updatedSelector, queryHandler } = QueryHandler_js_1.getQueryHandlerAndSelector(selector);
return queryHandler.waitFor(this, updatedSelector, options);
}
/**
* @internal
*/
async addBindingToContext(name) {
// Previous operation added the binding so we are done.
if (this._ctxBindings.has(name))
return;
// Wait for other operation to finish
if (this._settingUpBinding) {
await this._settingUpBinding;
return this.addBindingToContext(name);
}
const bind = async (name) => {
const expression = helper_js_1.helper.pageBindingInitString('internal', name);
try {
const context = await this.executionContext();
await context._client.send('Runtime.addBinding', {
name,
executionContextId: context._contextId,
});
await context.evaluate(expression);
}
catch (error) {
// We could have tried to evaluate in a context which was already
// destroyed. This happens, for example, if the page is navigated while
// we are trying to add the binding
const ctxDestroyed = error.message.includes('Execution context was destroyed');
const ctxNotFound = error.message.includes('Cannot find context with specified id');
if (ctxDestroyed || ctxNotFound) {
// Retry adding the binding in the next context
await bind(name);
}
else {
helper_js_1.debugError(error);
return;
}
}
this._ctxBindings.add(name);
};
this._settingUpBinding = bind(name);
await this._settingUpBinding;
this._settingUpBinding = null;
}
/**
* @internal
*/
async addBinding(name, puppeteerFunction) {
this._boundFunctions.set(name, puppeteerFunction);
await this.addBindingToContext(name);
}
async _onBindingCalled(event) {
let payload;
try {
payload = JSON.parse(event.payload);
}
catch {
// The binding was either called by something in the page or it was
// called before our wrapper was initialized.
return;
}
const { type, name, seq, args } = payload;
if (type !== 'internal' || !this._ctxBindings.has(name))
return;
if (!this._hasContext())
return;
const context = await this.executionContext();
if (context._contextId !== event.executionContextId)
return;
try {
const result = await this._boundFunctions.get(name)(...args);
await context.evaluate(deliverResult, name, seq, result);
}
catch (error) {
// The WaitTask may already have been resolved by timing out, or the
// exection context may have been destroyed.
// In both caes, the promises above are rejected with a protocol error.
// We can safely ignores these, as the WaitTask is re-installed in
// the next execution context if needed.
if (error.message.includes('Protocol error'))
return;
helper_js_1.debugError(error);
}
function deliverResult(name, seq, result) {
globalThis[name].callbacks.get(seq).resolve(result);
globalThis[name].callbacks.delete(seq);
}
}
/**
* @internal
*/
async waitForSelectorInPage(queryOne, selector, options) {
const { visible: waitForVisible = false, hidden: waitForHidden = false, timeout = this._timeoutSettings.timeout(), } = options;
const polling = waitForVisible || waitForHidden ? 'raf' : 'mutation';
const title = `selector \`${selector}\`${waitForHidden ? ' to be hidden' : ''}`;
const { updatedSelector, queryHandler } = QueryHandler_js_1.getQueryHandlerAndSelector(selector);
function predicate(selector, waitForVisible, waitForHidden) {
async function predicate(selector, waitForVisible, waitForHidden) {
const node = predicateQueryHandler
? predicateQueryHandler(document, selector)
? (await predicateQueryHandler(document, selector))
: document.querySelector(selector);
return checkWaitForOptions(node, waitForVisible, waitForHidden);
}
const waitTask = new WaitTask(this, this._makePredicateString(predicate, queryHandler.queryOne), title, polling, timeout, updatedSelector, waitForVisible, waitForHidden);
const waitTask = new WaitTask(this, helper_js_1.helper.makePredicateString(predicate, queryOne), title, polling, timeout, selector, waitForVisible, waitForHidden);
const jsHandle = await waitTask.promise;

@@ -345,3 +460,3 @@ const elementHandle = jsHandle.asElement();

}
const waitTask = new WaitTask(this, this._makePredicateString(predicate), title, polling, timeout, xpath, waitForVisible, waitForHidden);
const waitTask = new WaitTask(this, helper_js_1.helper.makePredicateString(predicate), title, polling, timeout, xpath, waitForVisible, waitForHidden);
const jsHandle = await waitTask.promise;

@@ -355,30 +470,2 @@ const elementHandle = jsHandle.asElement();

}
_makePredicateString(predicate, predicateQueryHandler) {
const predicateQueryHandlerDef = predicateQueryHandler
? `const predicateQueryHandler = ${predicateQueryHandler};`
: '';
return `
(() => {
${predicateQueryHandlerDef}
const checkWaitForOptions = ${checkWaitForOptions};
return (${predicate})(...args)
})() `;
function checkWaitForOptions(node, waitForVisible, waitForHidden) {
if (!node)
return waitForHidden;
if (!waitForVisible && !waitForHidden)
return node;
const element = node.nodeType === Node.TEXT_NODE
? node.parentElement
: node;
const style = window.getComputedStyle(element);
const isVisible = style && style.visibility !== 'hidden' && hasVisibleBoundingBox();
const success = waitForVisible === isVisible || waitForHidden === !isVisible;
return success ? node : null;
function hasVisibleBoundingBox() {
const rect = element.getBoundingClientRect();
return !!(rect.top || rect.bottom || rect.width || rect.height);
}
}
}
waitForFunction(pageFunction, options = {}, ...args) {

@@ -393,2 +480,5 @@ const { polling = 'raf', timeout = this._timeoutSettings.timeout(), } = options;

exports.DOMWorld = DOMWorld;
/**
* @internal
*/
class WaitTask {

@@ -457,15 +547,23 @@ constructor(domWorld, predicateBody, title, polling, timeout, ...args) {

}
// When the page is navigated, the promise is rejected.
// We will try again in the new execution context.
if (error && error.message.includes('Execution context was destroyed'))
return;
// We could have tried to evaluate in a context which was already
// destroyed.
if (error &&
error.message.includes('Cannot find context with specified id'))
return;
if (error)
// When frame is detached the task should have been terminated by the DOMWorld.
// This can fail if we were adding this task while the frame was detached,
// so we terminate here instead.
if (error) {
if (error.message.includes('Execution context is not available in detached frame')) {
this.terminate(new Error('waitForFunction failed: frame got detached.'));
return;
}
// When the page is navigated, the promise is rejected.
// We will try again in the new execution context.
if (error.message.includes('Execution context was destroyed'))
return;
// We could have tried to evaluate in a context which was already
// destroyed.
if (error.message.includes('Cannot find context with specified id'))
return;
this._reject(error);
else
}
else {
this._resolve(success);
}
this._cleanup();

@@ -478,2 +576,3 @@ }

}
exports.WaitTask = WaitTask;
async function waitForPredicatePageFunction(predicateBody, polling, timeout, ...args) {

@@ -480,0 +579,0 @@ const predicate = new Function('...args', predicateBody);

@@ -25,3 +25,3 @@ /**

* Example operations are {@link Page.waitForSelector | page.waitForSelector}
* or {@link Puppeteer.launch | puppeteer.launch}.
* or {@link PuppeteerNode.launch | puppeteer.launch}.
*

@@ -28,0 +28,0 @@ * @public

@@ -32,3 +32,3 @@ "use strict";

* Example operations are {@link Page.waitForSelector | page.waitForSelector}
* or {@link Puppeteer.launch | puppeteer.launch}.
* or {@link PuppeteerNode.launch | puppeteer.launch}.
*

@@ -35,0 +35,0 @@ * @public

@@ -49,6 +49,9 @@ /**

_world: DOMWorld;
private _contextId;
/**
* @internal
*/
_contextId: number;
/**
* @internal
*/
constructor(client: CDPSession, contextPayload: Protocol.Runtime.ExecutionContextDescription, world: DOMWorld);

@@ -55,0 +58,0 @@ /**

@@ -600,3 +600,3 @@ /**

*/
waitFor(selectorOrFunctionOrTimeout: string | number | Function, options?: {}, ...args: SerializableOrJSHandle[]): Promise<JSHandle | null>;
waitFor(selectorOrFunctionOrTimeout: string | number | Function, options?: Record<string, unknown>, ...args: SerializableOrJSHandle[]): Promise<JSHandle | null>;
/**

@@ -603,0 +603,0 @@ * Causes your script to wait for the given number of milliseconds.

@@ -24,2 +24,7 @@ /// <reference types="node" />

declare function evaluationString(fun: Function | string, ...args: unknown[]): string;
declare function pageBindingInitString(type: string, name: string): string;
declare function pageBindingDeliverResultString(name: string, seq: number, result: unknown): string;
declare function pageBindingDeliverErrorString(name: string, seq: number, message: string, stack: string): string;
declare function pageBindingDeliverErrorValueString(name: string, seq: number, value: unknown): string;
declare function makePredicateString(predicate: Function, predicateQueryHandler?: Function): string;
declare function waitWithTimeout<T extends any>(promise: Promise<T>, taskName: string, timeout: number): Promise<T>;

@@ -29,2 +34,7 @@ declare function readProtocolStream(client: CDPSession, handle: string, path?: string): Promise<Buffer>;

evaluationString: typeof evaluationString;
pageBindingInitString: typeof pageBindingInitString;
pageBindingDeliverResultString: typeof pageBindingDeliverResultString;
pageBindingDeliverErrorString: typeof pageBindingDeliverErrorString;
pageBindingDeliverErrorValueString: typeof pageBindingDeliverErrorValueString;
makePredicateString: typeof makePredicateString;
readProtocolStream: typeof readProtocolStream;

@@ -31,0 +41,0 @@ waitWithTimeout: typeof waitWithTimeout;

@@ -40,8 +40,4 @@ "use strict";

const Debug_js_1 = require("./Debug.js");
const fs = __importStar(require("fs"));
const util_1 = require("util");
const assert_js_1 = require("./assert.js");
const openAsync = util_1.promisify(fs.open);
const writeAsync = util_1.promisify(fs.write);
const closeAsync = util_1.promisify(fs.close);
const environment_js_1 = require("../environment.js");
exports.debugError = Debug_js_1.debug('puppeteer:error');

@@ -155,2 +151,74 @@ function getExceptionMessage(exceptionDetails) {

}
function pageBindingInitString(type, name) {
function addPageBinding(type, bindingName) {
/* Cast window to any here as we're about to add properties to it
* via win[bindingName] which TypeScript doesn't like.
*/
const win = window;
const binding = win[bindingName];
win[bindingName] = (...args) => {
const me = window[bindingName];
let callbacks = me.callbacks;
if (!callbacks) {
callbacks = new Map();
me.callbacks = callbacks;
}
const seq = (me.lastSeq || 0) + 1;
me.lastSeq = seq;
const promise = new Promise((resolve, reject) => callbacks.set(seq, { resolve, reject }));
binding(JSON.stringify({ type, name: bindingName, seq, args }));
return promise;
};
}
return evaluationString(addPageBinding, type, name);
}
function pageBindingDeliverResultString(name, seq, result) {
function deliverResult(name, seq, result) {
window[name].callbacks.get(seq).resolve(result);
window[name].callbacks.delete(seq);
}
return evaluationString(deliverResult, name, seq, result);
}
function pageBindingDeliverErrorString(name, seq, message, stack) {
function deliverError(name, seq, message, stack) {
const error = new Error(message);
error.stack = stack;
window[name].callbacks.get(seq).reject(error);
window[name].callbacks.delete(seq);
}
return evaluationString(deliverError, name, seq, message, stack);
}
function pageBindingDeliverErrorValueString(name, seq, value) {
function deliverErrorValue(name, seq, value) {
window[name].callbacks.get(seq).reject(value);
window[name].callbacks.delete(seq);
}
return evaluationString(deliverErrorValue, name, seq, value);
}
function makePredicateString(predicate, predicateQueryHandler) {
function checkWaitForOptions(node, waitForVisible, waitForHidden) {
if (!node)
return waitForHidden;
if (!waitForVisible && !waitForHidden)
return node;
const element = node.nodeType === Node.TEXT_NODE ? node.parentElement : node;
const style = window.getComputedStyle(element);
const isVisible = style && style.visibility !== 'hidden' && hasVisibleBoundingBox();
const success = waitForVisible === isVisible || waitForHidden === !isVisible;
return success ? node : null;
function hasVisibleBoundingBox() {
const rect = element.getBoundingClientRect();
return !!(rect.top || rect.bottom || rect.width || rect.height);
}
}
const predicateQueryHandlerDef = predicateQueryHandler
? `const predicateQueryHandler = ${predicateQueryHandler};`
: '';
return `
(() => {
${predicateQueryHandlerDef}
const checkWaitForOptions = ${checkWaitForOptions};
return (${predicate})(...args)
})() `;
}
async function waitWithTimeout(promise, taskName, timeout) {

@@ -172,6 +240,11 @@ let reject;

async function readProtocolStream(client, handle, path) {
if (!environment_js_1.isNode && path) {
throw new Error('Cannot write to a path outside of Node.js environment.');
}
const fs = environment_js_1.isNode ? await Promise.resolve().then(() => __importStar(require('fs'))) : null;
let eof = false;
let file;
if (path)
file = await openAsync(path, 'w');
let fileHandle;
if (path && fs) {
fileHandle = await fs.promises.open(path, 'w');
}
const bufs = [];

@@ -183,7 +256,8 @@ while (!eof) {

bufs.push(buf);
if (path)
await writeAsync(file, buf);
if (path && fs) {
await fs.promises.writeFile(fileHandle, buf);
}
}
if (path)
await closeAsync(file);
await fileHandle.close();
await client.send('IO.close', { handle });

@@ -200,2 +274,7 @@ let resultBuffer = null;

evaluationString,
pageBindingInitString,
pageBindingDeliverResultString,
pageBindingDeliverErrorString,
pageBindingDeliverErrorValueString,
makePredicateString,
readProtocolStream,

@@ -202,0 +281,0 @@ waitWithTimeout,

@@ -169,3 +169,3 @@ /**

*/
jsonValue(): Promise<{}>;
jsonValue(): Promise<Record<string, unknown>>;
/**

@@ -172,0 +172,0 @@ * Returns either `null` or the object handle itself, if the object handle is

@@ -17,2 +17,21 @@ "use strict";

*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -23,2 +42,3 @@ exports.ElementHandle = exports.JSHandle = exports.createJSHandle = void 0;

const QueryHandler_js_1 = require("./QueryHandler.js");
const environment_js_1 = require("../environment.js");
/**

@@ -272,6 +292,5 @@ * @internal

inline: 'center',
// Chrome still supports behavior: instant but it's not in the spec
// so TS shouts We don't want to make this breaking change in
// Puppeteer yet so we'll ignore the line.
// @ts-ignore
// @ts-expect-error Chrome still supports behavior: instant but
// it's not in the spec so TS shouts We don't want to make this
// breaking change in Puppeteer yet so we'll ignore the line.
behavior: 'instant',

@@ -292,6 +311,5 @@ });

inline: 'center',
// Chrome still supports behavior: instant but it's not in the spec
// so TS shouts We don't want to make this breaking change in
// Puppeteer yet so we'll ignore the line.
// @ts-ignore
// @ts-expect-error Chrome still supports behavior: instant but
// it's not in the spec so TS shouts We don't want to make this
// breaking change in Puppeteer yet so we'll ignore the line.
behavior: 'instant',

@@ -427,11 +445,10 @@ });

assert_js_1.assert(filePaths.length <= 1 || isMultiple, 'Multiple file uploads only work with <input type=file multiple>');
if (!environment_js_1.isNode) {
throw new Error(`JSHandle#uploadFile can only be used in Node environments.`);
}
// This import is only needed for `uploadFile`, so keep it scoped here to avoid paying
// the cost unnecessarily.
const path = await Promise.resolve().then(() => __importStar(require('path')));
// eslint-disable-next-line @typescript-eslint/no-var-requires
const path = require('path');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fs = require('fs');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { promisify } = require('util');
const access = promisify(fs.access);
const fs = await Promise.resolve().then(() => __importStar(require('fs')));
// Locate all files and confirm that they exist.

@@ -441,3 +458,3 @@ const files = await Promise.all(filePaths.map(async (filePath) => {

try {
await access(resolvedPath, fs.constants.R_OK);
await fs.promises.access(resolvedPath, fs.constants.R_OK);
}

@@ -611,8 +628,3 @@ catch (error) {

const { updatedSelector, queryHandler } = QueryHandler_js_1.getQueryHandlerAndSelector(selector);
const handle = await this.evaluateHandle(queryHandler.queryOne, updatedSelector);
const element = handle.asElement();
if (element)
return element;
await handle.dispose();
return null;
return queryHandler.queryOne(this, updatedSelector);
}

@@ -625,12 +637,3 @@ /**

const { updatedSelector, queryHandler } = QueryHandler_js_1.getQueryHandlerAndSelector(selector);
const handles = await this.evaluateHandle(queryHandler.queryAll, updatedSelector);
const properties = await handles.getProperties();
await handles.dispose();
const result = [];
for (const property of properties.values()) {
const elementHandle = property.asElement();
if (elementHandle)
result.push(elementHandle);
}
return result;
return queryHandler.queryAll(this, updatedSelector);
}

@@ -693,4 +696,3 @@ /**

const { updatedSelector, queryHandler } = QueryHandler_js_1.getQueryHandlerAndSelector(selector);
const queryHandlerToArray = Function('element', 'selector', `return Array.from((${queryHandler.queryAll})(element, selector));`);
const arrayHandle = await this.evaluateHandle(queryHandlerToArray, updatedSelector);
const arrayHandle = await queryHandler.queryAllArray(this, updatedSelector);
const result = await arrayHandle.evaluate(pageFunction, ...args);

@@ -697,0 +699,0 @@ await arrayHandle.dispose();

@@ -38,4 +38,2 @@ "use strict";

exports.Page = void 0;
const fs = __importStar(require("fs"));
const util_1 = require("util");
const EventEmitter_js_1 = require("./EventEmitter.js");

@@ -59,3 +57,3 @@ const Connection_js_1 = require("./Connection.js");

const PDFOptions_js_1 = require("./PDFOptions.js");
const writeFileAsync = util_1.promisify(fs.writeFile);
const environment_js_1 = require("../environment.js");
class ScreenshotTaskQueue {

@@ -298,3 +296,3 @@ constructor() {

if (source !== 'worker')
this.emit("console" /* Console */, new ConsoleMessage_js_1.ConsoleMessage(level, text, [], { url, lineNumber }));
this.emit("console" /* Console */, new ConsoleMessage_js_1.ConsoleMessage(level, text, [], [{ url, lineNumber }]));
}

@@ -665,3 +663,3 @@ /**

this._pageBindings.set(name, puppeteerFunction);
const expression = helper_js_1.helper.evaluationString(addPageBinding, name);
const expression = helper_js_1.helper.pageBindingInitString('exposedFun', name);
await this._client.send('Runtime.addBinding', { name: name });

@@ -672,22 +670,2 @@ await this._client.send('Page.addScriptToEvaluateOnNewDocument', {

await Promise.all(this.frames().map((frame) => frame.evaluate(expression).catch(helper_js_1.debugError)));
function addPageBinding(bindingName) {
/* Cast window to any here as we're about to add properties to it
* via win[bindingName] which TypeScript doesn't like.
*/
const win = window;
const binding = win[bindingName];
win[bindingName] = (...args) => {
const me = window[bindingName];
let callbacks = me['callbacks'];
if (!callbacks) {
callbacks = new Map();
me['callbacks'] = callbacks;
}
const seq = (me['lastSeq'] || 0) + 1;
me['lastSeq'] = seq;
const promise = new Promise((resolve, reject) => callbacks.set(seq, { resolve, reject }));
binding(JSON.stringify({ name: bindingName, seq, args }));
return promise;
};
}
}

@@ -749,13 +727,24 @@ async authenticate(credentials) {

async _onBindingCalled(event) {
const { name, seq, args } = JSON.parse(event.payload);
let payload;
try {
payload = JSON.parse(event.payload);
}
catch {
// The binding was either called by something in the page or it was
// called before our wrapper was initialized.
return;
}
const { type, name, seq, args } = payload;
if (type !== 'exposedFun' || !this._pageBindings.has(name))
return;
let expression = null;
try {
const result = await this._pageBindings.get(name)(...args);
expression = helper_js_1.helper.evaluationString(deliverResult, name, seq, result);
expression = helper_js_1.helper.pageBindingDeliverResultString(name, seq, result);
}
catch (error) {
if (error instanceof Error)
expression = helper_js_1.helper.evaluationString(deliverError, name, seq, error.message, error.stack);
expression = helper_js_1.helper.pageBindingDeliverErrorString(name, seq, error.message, error.stack);
else
expression = helper_js_1.helper.evaluationString(deliverErrorValue, name, seq, error);
expression = helper_js_1.helper.pageBindingDeliverErrorValueString(name, seq, error);
}

@@ -768,16 +757,2 @@ this._client

.catch(helper_js_1.debugError);
function deliverResult(name, seq, result) {
window[name]['callbacks'].get(seq).resolve(result);
window[name]['callbacks'].delete(seq);
}
function deliverError(name, seq, message, stack) {
const error = new Error(message);
error.stack = stack;
window[name]['callbacks'].get(seq).reject(error);
window[name]['callbacks'].delete(seq);
}
function deliverErrorValue(name, seq, value) {
window[name]['callbacks'].get(seq).reject(value);
window[name]['callbacks'].delete(seq);
}
}

@@ -797,10 +772,13 @@ _addConsoleMessage(type, args, stackTrace) {

}
const location = stackTrace && stackTrace.callFrames.length
? {
url: stackTrace.callFrames[0].url,
lineNumber: stackTrace.callFrames[0].lineNumber,
columnNumber: stackTrace.callFrames[0].columnNumber,
const stackTraceLocations = [];
if (stackTrace) {
for (const callFrame of stackTrace.callFrames) {
stackTraceLocations.push({
url: callFrame.url,
lineNumber: callFrame.lineNumber,
columnNumber: callFrame.columnNumber,
});
}
: {};
const message = new ConsoleMessage_js_1.ConsoleMessage(type, textTokens.join(' '), args, location);
}
const message = new ConsoleMessage_js_1.ConsoleMessage(type, textTokens.join(' '), args, stackTraceLocations);
this.emit("console" /* Console */, message);

@@ -1172,4 +1150,8 @@ }

: Buffer.from(result.data, 'base64');
if (!environment_js_1.isNode && options.path) {
throw new Error('Screenshots can only be written to a file path in a Node environment.');
}
const fs = await Promise.resolve().then(() => __importStar(require('fs')));
if (options.path)
await writeFileAsync(options.path, buffer);
await fs.promises.writeFile(options.path, buffer);
return buffer;

@@ -1176,0 +1158,0 @@ function processClip(clip) {

@@ -1,4 +0,16 @@

import { LaunchOptions, ChromeArgOptions, BrowserOptions } from '../node/LaunchOptions.js';
import { ProductLauncher } from '../node/Launcher.js';
import { BrowserFetcher, BrowserFetcherOptions } from '../node/BrowserFetcher.js';
/**
* Copyright 2017 Google Inc. 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.
*/
import { PuppeteerErrors } from './Errors.js';

@@ -8,76 +20,35 @@ import { ConnectionTransport } from './ConnectionTransport.js';

import { Browser } from './Browser.js';
import { QueryHandler } from './QueryHandler.js';
import { CustomQueryHandler } from './QueryHandler.js';
import { Product } from './Product.js';
import { BrowserOptions } from './BrowserConnector.js';
/**
* The main Puppeteer class. Provides the {@link Puppeteer.launch | launch}
* method to launch a browser.
* Settings that are common to the Puppeteer class, regardless of enviroment.
* @internal
*/
export interface CommonPuppeteerSettings {
isPuppeteerCore: boolean;
}
export interface ConnectOptions extends BrowserOptions {
browserWSEndpoint?: string;
browserURL?: string;
transport?: ConnectionTransport;
product?: Product;
}
/**
* The main Puppeteer class.
*
* When you `require` or `import` the Puppeteer npm package you get back an
* instance of this class.
*
* @remarks
*
* @example
* The following is a typical example of using Puppeteer to drive automation:
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* await page.goto('https://www.google.com');
* // other actions...
* await browser.close();
* })();
* ```
*
* Once you have created a `page` you have access to a large API to interact
* with the page, navigate, or find certain elements in that page.
* The {@link Page | `page` documentation} lists all the available methods.
*
* IMPORTANT: if you are using Puppeteer in a Node environment, you will get an
* instance of {@link PuppeteerNode} when you import or require `puppeteer`.
* That class extends `Puppeteer`, so has all the methods documented below as
* well as all that are defined on {@link PuppeteerNode}.
* @public
*/
export declare class Puppeteer {
private _projectRoot;
private _isPuppeteerCore;
private _changedProduct;
private __productName;
private _lazyLauncher;
protected _isPuppeteerCore: boolean;
protected _changedProduct: boolean;
/**
* @internal
*/
_preferredRevision: string;
constructor(settings: CommonPuppeteerSettings);
/**
* @internal
*/
constructor(projectRoot: string, preferredRevision: string, isPuppeteerCore: boolean, productName: string);
/**
* Launches puppeteer and launches a browser instance with given arguments
* and options when specified.
*
* @remarks
*
* @example
* You can use `ignoreDefaultArgs` to filter out `--mute-audio` from default arguments:
* ```js
* const browser = await puppeteer.launch({
* ignoreDefaultArgs: ['--mute-audio']
* });
* ```
*
* **NOTE** Puppeteer can also be used to control the Chrome browser,
* but it works best with the version of Chromium it is bundled with.
* There is no guarantee it will work with any other version.
* Use `executablePath` option with extreme caution.
* If Google Chrome (rather than Chromium) is preferred, a {@link https://www.google.com/chrome/browser/canary.html | Chrome Canary} or {@link https://www.chromium.org/getting-involved/dev-channel | Dev Channel} build is suggested.
* In `puppeteer.launch([options])`, any mention of Chromium also applies to Chrome.
* See {@link https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/ | this article} for a description of the differences between Chromium and Chrome. {@link https://chromium.googlesource.com/chromium/src/+/lkgr/docs/chromium_browser_vs_google_chrome.md | This article} describes some differences for Linux users.
*
* @param options - Set of configurable options to set on the browser.
* @returns Promise which resolves to browser instance.
*/
launch(options?: LaunchOptions & ChromeArgOptions & BrowserOptions & {
product?: string;
extraPrefsFirefox?: {};
}): Promise<Browser>;
/**
* This method attaches Puppeteer to an existing browser instance.

@@ -90,39 +61,5 @@ *

*/
connect(options: BrowserOptions & {
browserWSEndpoint?: string;
browserURL?: string;
transport?: ConnectionTransport;
product?: string;
}): Promise<Browser>;
connect(options: ConnectOptions): Promise<Browser>;
/**
* @internal
*/
get _productName(): string;
set _productName(name: string);
/**
* @remarks
*
* **NOTE** `puppeteer.executablePath()` is affected by the `PUPPETEER_EXECUTABLE_PATH`
* and `PUPPETEER_CHROMIUM_REVISION` environment variables.
*
* @returns A path where Puppeteer expects to find the bundled browser.
* The browser binary might not be there if the download was skipped with
* the `PUPPETEER_SKIP_DOWNLOAD` environment variable.
*/
executablePath(): string;
/**
* @internal
*/
get _launcher(): ProductLauncher;
/**
* The name of the browser that is under automation (`"chrome"` or `"firefox"`)
*
* @remarks
* The product is set by the `PUPPETEER_PRODUCT` environment variable or the `product`
* option in `puppeteer.launch([options])` and defaults to `chrome`.
* Firefox support is experimental.
*/
get product(): string;
/**
* @remarks
* A list of devices to be used with `page.emulate(options)`. Actual list of devices can be found in {@link https://github.com/puppeteer/puppeteer/blob/main/src/common/DeviceDescriptors.ts | src/common/DeviceDescriptors.ts}.

@@ -172,30 +109,29 @@ *

/**
*
* @param options - Set of configurable options to set on the browser.
* @returns The default flags that Chromium will be launched with.
* Registers a {@link CustomQueryHandler | custom query handler}. After
* registration, the handler can be used everywhere where a selector is
* expected by prepending the selection string with `<name>/`. The name is
* only allowed to consist of lower- and upper case latin letters.
* @example
* ```
* puppeteer.registerCustomQueryHandler('text', { … });
* const aHandle = await page.$('text/…');
* ```
* @param name - The name that the custom query handler will be registered under.
* @param queryHandler - The {@link CustomQueryHandler | custom query handler} to
* register.
*/
defaultArgs(options?: ChromeArgOptions): string[];
registerCustomQueryHandler(name: string, queryHandler: CustomQueryHandler): void;
/**
* @param options - Set of configurable options to specify the settings
* of the BrowserFetcher.
* @returns A new BrowserFetcher instance.
* @param name - The name of the query handler to unregistered.
*/
createBrowserFetcher(options: BrowserFetcherOptions): BrowserFetcher;
unregisterCustomQueryHandler(name: string): void;
/**
* @internal
* @returns a list with the names of all registered custom query handlers.
*/
__experimental_registerCustomQueryHandler(name: string, queryHandler: QueryHandler): void;
customQueryHandlerNames(): string[];
/**
* @internal
* Clears all registered handlers.
*/
__experimental_unregisterCustomQueryHandler(name: string): void;
/**
* @internal
*/
__experimental_customQueryHandlers(): Map<string, QueryHandler>;
/**
* @internal
*/
__experimental_clearQueryHandlers(): void;
clearCustomQueryHandlers(): void;
}
//# sourceMappingURL=Puppeteer.d.ts.map
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });

@@ -22,35 +19,13 @@ exports.Puppeteer = void 0;

*/
const Launcher_js_1 = __importDefault(require("../node/Launcher.js"));
const BrowserFetcher_js_1 = require("../node/BrowserFetcher.js");
const Errors_js_1 = require("./Errors.js");
const DeviceDescriptors_js_1 = require("./DeviceDescriptors.js");
const QueryHandler_js_1 = require("./QueryHandler.js");
const revisions_js_1 = require("../revisions.js");
const BrowserConnector_js_1 = require("./BrowserConnector.js");
/**
* The main Puppeteer class. Provides the {@link Puppeteer.launch | launch}
* method to launch a browser.
* The main Puppeteer class.
*
* When you `require` or `import` the Puppeteer npm package you get back an
* instance of this class.
*
* @remarks
*
* @example
* The following is a typical example of using Puppeteer to drive automation:
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* await page.goto('https://www.google.com');
* // other actions...
* await browser.close();
* })();
* ```
*
* Once you have created a `page` you have access to a large API to interact
* with the page, navigate, or find certain elements in that page.
* The {@link Page | `page` documentation} lists all the available methods.
*
* IMPORTANT: if you are using Puppeteer in a Node environment, you will get an
* instance of {@link PuppeteerNode} when you import or require `puppeteer`.
* That class extends `Puppeteer`, so has all the methods documented below as
* well as all that are defined on {@link PuppeteerNode}.
* @public

@@ -62,41 +37,7 @@ */

*/
constructor(projectRoot, preferredRevision, isPuppeteerCore, productName) {
constructor(settings) {
this._changedProduct = false;
this._projectRoot = projectRoot;
this._preferredRevision = preferredRevision;
this._isPuppeteerCore = isPuppeteerCore;
// track changes to Launcher configuration via options or environment variables
this.__productName = productName;
this._isPuppeteerCore = settings.isPuppeteerCore;
}
/**
* Launches puppeteer and launches a browser instance with given arguments
* and options when specified.
*
* @remarks
*
* @example
* You can use `ignoreDefaultArgs` to filter out `--mute-audio` from default arguments:
* ```js
* const browser = await puppeteer.launch({
* ignoreDefaultArgs: ['--mute-audio']
* });
* ```
*
* **NOTE** Puppeteer can also be used to control the Chrome browser,
* but it works best with the version of Chromium it is bundled with.
* There is no guarantee it will work with any other version.
* Use `executablePath` option with extreme caution.
* If Google Chrome (rather than Chromium) is preferred, a {@link https://www.google.com/chrome/browser/canary.html | Chrome Canary} or {@link https://www.chromium.org/getting-involved/dev-channel | Dev Channel} build is suggested.
* In `puppeteer.launch([options])`, any mention of Chromium also applies to Chrome.
* See {@link https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/ | this article} for a description of the differences between Chromium and Chrome. {@link https://chromium.googlesource.com/chromium/src/+/lkgr/docs/chromium_browser_vs_google_chrome.md | This article} describes some differences for Linux users.
*
* @param options - Set of configurable options to set on the browser.
* @returns Promise which resolves to browser instance.
*/
launch(options = {}) {
if (options.product)
this._productName = options.product;
return this._launcher.launch(options);
}
/**
* This method attaches Puppeteer to an existing browser instance.

@@ -110,64 +51,6 @@ *

connect(options) {
if (options.product)
this._productName = options.product;
return this._launcher.connect(options);
return BrowserConnector_js_1.connectToBrowser(options);
}
/**
* @internal
*/
get _productName() {
return this.__productName;
}
// don't need any TSDoc here - because the getter is internal the setter is too.
set _productName(name) {
if (this.__productName !== name)
this._changedProduct = true;
this.__productName = name;
}
/**
* @remarks
*
* **NOTE** `puppeteer.executablePath()` is affected by the `PUPPETEER_EXECUTABLE_PATH`
* and `PUPPETEER_CHROMIUM_REVISION` environment variables.
*
* @returns A path where Puppeteer expects to find the bundled browser.
* The browser binary might not be there if the download was skipped with
* the `PUPPETEER_SKIP_DOWNLOAD` environment variable.
*/
executablePath() {
return this._launcher.executablePath();
}
/**
* @internal
*/
get _launcher() {
if (!this._lazyLauncher ||
this._lazyLauncher.product !== this._productName ||
this._changedProduct) {
switch (this._productName) {
case 'firefox':
this._preferredRevision = revisions_js_1.PUPPETEER_REVISIONS.firefox;
break;
case 'chrome':
default:
this._preferredRevision = revisions_js_1.PUPPETEER_REVISIONS.chromium;
}
this._changedProduct = false;
this._lazyLauncher = Launcher_js_1.default(this._projectRoot, this._preferredRevision, this._isPuppeteerCore, this._productName);
}
return this._lazyLauncher;
}
/**
* The name of the browser that is under automation (`"chrome"` or `"firefox"`)
*
* @remarks
* The product is set by the `PUPPETEER_PRODUCT` environment variable or the `product`
* option in `puppeteer.launch([options])` and defaults to `chrome`.
* Firefox support is experimental.
*/
get product() {
return this._launcher.product;
}
/**
* @remarks
* A list of devices to be used with `page.emulate(options)`. Actual list of devices can be found in {@link https://github.com/puppeteer/puppeteer/blob/main/src/common/DeviceDescriptors.ts | src/common/DeviceDescriptors.ts}.

@@ -221,46 +104,37 @@ *

/**
*
* @param options - Set of configurable options to set on the browser.
* @returns The default flags that Chromium will be launched with.
* Registers a {@link CustomQueryHandler | custom query handler}. After
* registration, the handler can be used everywhere where a selector is
* expected by prepending the selection string with `<name>/`. The name is
* only allowed to consist of lower- and upper case latin letters.
* @example
* ```
* puppeteer.registerCustomQueryHandler('text', { … });
* const aHandle = await page.$('text/…');
* ```
* @param name - The name that the custom query handler will be registered under.
* @param queryHandler - The {@link CustomQueryHandler | custom query handler} to
* register.
*/
defaultArgs(options = {}) {
return this._launcher.defaultArgs(options);
}
/**
* @param options - Set of configurable options to specify the settings
* of the BrowserFetcher.
* @returns A new BrowserFetcher instance.
*/
createBrowserFetcher(options) {
return new BrowserFetcher_js_1.BrowserFetcher(this._projectRoot, options);
}
/**
* @internal
*/
// eslint-disable-next-line @typescript-eslint/camelcase
__experimental_registerCustomQueryHandler(name, queryHandler) {
registerCustomQueryHandler(name, queryHandler) {
QueryHandler_js_1.registerCustomQueryHandler(name, queryHandler);
}
/**
* @internal
* @param name - The name of the query handler to unregistered.
*/
// eslint-disable-next-line @typescript-eslint/camelcase
__experimental_unregisterCustomQueryHandler(name) {
unregisterCustomQueryHandler(name) {
QueryHandler_js_1.unregisterCustomQueryHandler(name);
}
/**
* @internal
* @returns a list with the names of all registered custom query handlers.
*/
// eslint-disable-next-line @typescript-eslint/camelcase
__experimental_customQueryHandlers() {
return QueryHandler_js_1.customQueryHandlers();
customQueryHandlerNames() {
return QueryHandler_js_1.customQueryHandlerNames();
}
/**
* @internal
* Clears all registered handlers.
*/
// eslint-disable-next-line @typescript-eslint/camelcase
__experimental_clearQueryHandlers() {
QueryHandler_js_1.clearQueryHandlers();
clearCustomQueryHandlers() {
QueryHandler_js_1.clearCustomQueryHandlers();
}
}
exports.Puppeteer = Puppeteer;

@@ -16,17 +16,51 @@ /**

*/
export interface QueryHandler {
import { WaitForSelectorOptions, DOMWorld } from './DOMWorld.js';
import { ElementHandle, JSHandle } from './JSHandle.js';
/**
* @internal
*/
export interface InternalQueryHandler {
queryOne?: (element: ElementHandle, selector: string) => Promise<ElementHandle | null>;
waitFor?: (domWorld: DOMWorld, selector: string, options: WaitForSelectorOptions) => Promise<ElementHandle | null>;
queryAll?: (element: ElementHandle, selector: string) => Promise<ElementHandle[]>;
queryAllArray?: (element: ElementHandle, selector: string) => Promise<JSHandle>;
}
/**
* Contains two functions `queryOne` and `queryAll` that can
* be {@link Puppeteer.registerCustomQueryHandler | registered}
* as alternative querying strategies. The functions `queryOne` and `queryAll`
* are executed in the page context. `queryOne` should take an `Element` and a
* selector string as argument and return a single `Element` or `null` if no
* element is found. `queryAll` takes the same arguments but should instead
* return a `NodeListOf<Element>` or `Array<Element>` with all the elements
* that match the given query selector.
* @public
*/
export interface CustomQueryHandler {
queryOne?: (element: Element | Document, selector: string) => Element | null;
queryAll?: (element: Element | Document, selector: string) => Element[] | NodeListOf<Element>;
}
export declare function registerCustomQueryHandler(name: string, handler: QueryHandler): void;
/**
* @param {string} name
* @internal
*/
export declare function registerCustomQueryHandler(name: string, handler: CustomQueryHandler): void;
/**
* @internal
*/
export declare function unregisterCustomQueryHandler(name: string): void;
export declare function customQueryHandlers(): Map<string, QueryHandler>;
export declare function clearQueryHandlers(): void;
/**
* @internal
*/
export declare function customQueryHandlerNames(): string[];
/**
* @internal
*/
export declare function clearCustomQueryHandlers(): void;
/**
* @internal
*/
export declare function getQueryHandlerAndSelector(selector: string): {
updatedSelector: string;
queryHandler: QueryHandler;
queryHandler: InternalQueryHandler;
};
//# sourceMappingURL=QueryHandler.d.ts.map

@@ -18,6 +18,100 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.getQueryHandlerAndSelector = exports.clearQueryHandlers = exports.customQueryHandlers = exports.unregisterCustomQueryHandler = exports.registerCustomQueryHandler = void 0;
const _customQueryHandlers = new Map();
exports.getQueryHandlerAndSelector = exports.clearCustomQueryHandlers = exports.customQueryHandlerNames = exports.unregisterCustomQueryHandler = exports.registerCustomQueryHandler = void 0;
const AriaQueryHandler_js_1 = require("./AriaQueryHandler.js");
function makeQueryHandler(handler) {
const internalHandler = {};
if (handler.queryOne) {
internalHandler.queryOne = async (element, selector) => {
const jsHandle = await element.evaluateHandle(handler.queryOne, selector);
const elementHandle = jsHandle.asElement();
if (elementHandle)
return elementHandle;
await jsHandle.dispose();
return null;
};
internalHandler.waitFor = (domWorld, selector, options) => domWorld.waitForSelectorInPage(handler.queryOne, selector, options);
}
if (handler.queryAll) {
internalHandler.queryAll = async (element, selector) => {
const jsHandle = await element.evaluateHandle(handler.queryAll, selector);
const properties = await jsHandle.getProperties();
await jsHandle.dispose();
const result = [];
for (const property of properties.values()) {
const elementHandle = property.asElement();
if (elementHandle)
result.push(elementHandle);
}
return result;
};
internalHandler.queryAllArray = async (element, selector) => {
const resultHandle = await element.evaluateHandle(handler.queryAll, selector);
const arrayHandle = await resultHandle.evaluateHandle((res) => Array.from(res));
return arrayHandle;
};
}
return internalHandler;
}
const _defaultHandler = makeQueryHandler({
queryOne: (element, selector) => element.querySelector(selector),
queryAll: (element, selector) => element.querySelectorAll(selector),
});
const pierceHandler = makeQueryHandler({
queryOne: (element, selector) => {
let found = null;
const search = (root) => {
const iter = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
do {
const currentNode = iter.currentNode;
if (currentNode.shadowRoot) {
search(currentNode.shadowRoot);
}
if (currentNode instanceof ShadowRoot) {
continue;
}
if (!found && currentNode.matches(selector)) {
found = currentNode;
}
} while (!found && iter.nextNode());
};
if (element instanceof Document) {
element = element.documentElement;
}
search(element);
return found;
},
queryAll: (element, selector) => {
const result = [];
const collect = (root) => {
const iter = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
do {
const currentNode = iter.currentNode;
if (currentNode.shadowRoot) {
collect(currentNode.shadowRoot);
}
if (currentNode instanceof ShadowRoot) {
continue;
}
if (currentNode.matches(selector)) {
result.push(currentNode);
}
} while (iter.nextNode());
};
if (element instanceof Document) {
element = element.documentElement;
}
collect(element);
return result;
},
});
const _builtInHandlers = new Map([
['aria', AriaQueryHandler_js_1.ariaHandler],
['pierce', pierceHandler],
]);
const _queryHandlers = new Map(_builtInHandlers);
/**
* @internal
*/
function registerCustomQueryHandler(name, handler) {
if (_customQueryHandlers.get(name))
if (_queryHandlers.get(name))
throw new Error(`A custom query handler named "${name}" already exists`);

@@ -27,32 +121,40 @@ const isValidName = /^[a-zA-Z]+$/.test(name);

throw new Error(`Custom query handler names may only contain [a-zA-Z]`);
_customQueryHandlers.set(name, handler);
const internalHandler = makeQueryHandler(handler);
_queryHandlers.set(name, internalHandler);
}
exports.registerCustomQueryHandler = registerCustomQueryHandler;
/**
* @param {string} name
* @internal
*/
function unregisterCustomQueryHandler(name) {
_customQueryHandlers.delete(name);
if (_queryHandlers.has(name) && !_builtInHandlers.has(name)) {
_queryHandlers.delete(name);
}
}
exports.unregisterCustomQueryHandler = unregisterCustomQueryHandler;
function customQueryHandlers() {
return _customQueryHandlers;
/**
* @internal
*/
function customQueryHandlerNames() {
return [..._queryHandlers.keys()].filter((name) => !_builtInHandlers.has(name));
}
exports.customQueryHandlers = customQueryHandlers;
function clearQueryHandlers() {
_customQueryHandlers.clear();
exports.customQueryHandlerNames = customQueryHandlerNames;
/**
* @internal
*/
function clearCustomQueryHandlers() {
customQueryHandlerNames().forEach(unregisterCustomQueryHandler);
}
exports.clearQueryHandlers = clearQueryHandlers;
exports.clearCustomQueryHandlers = clearCustomQueryHandlers;
/**
* @internal
*/
function getQueryHandlerAndSelector(selector) {
const defaultHandler = {
queryOne: (element, selector) => element.querySelector(selector),
queryAll: (element, selector) => element.querySelectorAll(selector),
};
const hasCustomQueryHandler = /^[a-zA-Z]+\//.test(selector);
if (!hasCustomQueryHandler)
return { updatedSelector: selector, queryHandler: defaultHandler };
return { updatedSelector: selector, queryHandler: _defaultHandler };
const index = selector.indexOf('/');
const name = selector.slice(0, index);
const updatedSelector = selector.slice(index + 1);
const queryHandler = customQueryHandlers().get(name);
const queryHandler = _queryHandlers.get(name);
if (!queryHandler)

@@ -59,0 +161,0 @@ throw new Error(`Query set to use "${name}", but no query handler of that name was found`);

@@ -16,2 +16,3 @@ /**

*/
import { Product } from '../common/Product.js';
/**

@@ -23,9 +24,4 @@ * Supported platforms.

/**
* Supported products.
* @public
*/
export declare type Product = 'chrome' | 'firefox';
/**
* @public
*/
export interface BrowserFetcherOptions {

@@ -32,0 +28,0 @@ platform?: Platform;

@@ -47,3 +47,3 @@ "use strict";

const Connection_js_1 = require("../common/Connection.js");
const WebSocketTransport_js_1 = require("../common/WebSocketTransport.js");
const NodeWebSocketTransport_js_1 = require("../node/NodeWebSocketTransport.js");
const PipeTransport_js_1 = require("./PipeTransport.js");

@@ -164,3 +164,3 @@ const readline = __importStar(require("readline"));

const browserWSEndpoint = await waitForWSEndpoint(this.proc, timeout, preferredRevision);
const transport = await WebSocketTransport_js_1.WebSocketTransport.create(browserWSEndpoint);
const transport = await NodeWebSocketTransport_js_1.NodeWebSocketTransport.create(browserWSEndpoint);
this.connection = new Connection_js_1.Connection(browserWSEndpoint, transport, slowMo);

@@ -167,0 +167,0 @@ }

@@ -0,1 +1,2 @@

import { Product } from '../common/Product.js';
/**

@@ -7,6 +8,5 @@ * Describes a launcher - a class that is able to create and launch a browser instance.

launch(object: any): any;
connect(object: any): any;
executablePath: () => string;
defaultArgs(object: any): any;
product: string;
product: Product;
}

@@ -13,0 +13,0 @@ /**

@@ -39,12 +39,5 @@ "use strict";

const path = __importStar(require("path"));
const http = __importStar(require("http"));
const https = __importStar(require("https"));
const URL = __importStar(require("url"));
const fs = __importStar(require("fs"));
const BrowserFetcher_js_1 = require("./BrowserFetcher.js");
const Connection_js_1 = require("../common/Connection.js");
const Browser_js_1 = require("../common/Browser.js");
const assert_js_1 = require("../common/assert.js");
const helper_js_1 = require("../common/helper.js");
const WebSocketTransport_js_1 = require("../common/WebSocketTransport.js");
const BrowserRunner_js_1 = require("./BrowserRunner.js");

@@ -151,3 +144,3 @@ const util_1 = require("util");

if (userDataDir)
chromeArguments.push(`--user-data-dir=${userDataDir}`);
chromeArguments.push(`--user-data-dir=${path.resolve(userDataDir)}`);
if (devtools)

@@ -169,24 +162,2 @@ chromeArguments.push('--auto-open-devtools-for-tabs');

}
async connect(options) {
const { browserWSEndpoint, browserURL, ignoreHTTPSErrors = false, defaultViewport = { width: 800, height: 600 }, transport, slowMo = 0, } = options;
assert_js_1.assert(Number(!!browserWSEndpoint) +
Number(!!browserURL) +
Number(!!transport) ===
1, 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect');
let connection = null;
if (transport) {
connection = new Connection_js_1.Connection('', transport, slowMo);
}
else if (browserWSEndpoint) {
const connectionTransport = await WebSocketTransport_js_1.WebSocketTransport.create(browserWSEndpoint);
connection = new Connection_js_1.Connection(browserWSEndpoint, connectionTransport, slowMo);
}
else if (browserURL) {
const connectionURL = await getWSEndpoint(browserURL);
const connectionTransport = await WebSocketTransport_js_1.WebSocketTransport.create(connectionURL);
connection = new Connection_js_1.Connection(connectionURL, connectionTransport, slowMo);
}
const { browserContextIds } = await connection.send('Target.getBrowserContexts');
return Browser_js_1.Browser.create(connection, browserContextIds, ignoreHTTPSErrors, defaultViewport, null, () => connection.send('Browser.close').catch(helper_js_1.debugError));
}
}

@@ -253,24 +224,2 @@ /**

}
async connect(options) {
const { browserWSEndpoint, browserURL, ignoreHTTPSErrors = false, defaultViewport = { width: 800, height: 600 }, transport, slowMo = 0, } = options;
assert_js_1.assert(Number(!!browserWSEndpoint) +
Number(!!browserURL) +
Number(!!transport) ===
1, 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect');
let connection = null;
if (transport) {
connection = new Connection_js_1.Connection('', transport, slowMo);
}
else if (browserWSEndpoint) {
const connectionTransport = await WebSocketTransport_js_1.WebSocketTransport.create(browserWSEndpoint);
connection = new Connection_js_1.Connection(browserWSEndpoint, connectionTransport, slowMo);
}
else if (browserURL) {
const connectionURL = await getWSEndpoint(browserURL);
const connectionTransport = await WebSocketTransport_js_1.WebSocketTransport.create(connectionURL);
connection = new Connection_js_1.Connection(connectionURL, connectionTransport, slowMo);
}
const { browserContextIds } = await connection.send('Target.getBrowserContexts');
return Browser_js_1.Browser.create(connection, browserContextIds, ignoreHTTPSErrors, defaultViewport, null, () => connection.send('Browser.close').catch(helper_js_1.debugError));
}
executablePath() {

@@ -334,3 +283,3 @@ return resolveExecutablePath(this).executablePath;

// Disable topstories
'browser.newtabpage.activity-stream.feeds.section.topstories': false,
'browser.newtabpage.activity-stream.feeds.system.topstories': false,
// Always display a blank page

@@ -376,5 +325,3 @@ 'browser.newtabpage.enabled': false,

'browser.warnOnQuit': false,
// Do not show datareporting policy notifications which can
// interfere with tests
'datareporting.healthreport.about.reportUrl': `http://${server}/dummy/abouthealthreport/`,
// Defensively disable data reporting systems
'datareporting.healthreport.documentServerURI': `http://${server}/dummy/healthreport/`,

@@ -385,4 +332,4 @@ 'datareporting.healthreport.logging.consoleEnabled': false,

'datareporting.healthreport.uploadEnabled': false,
// Do not show datareporting policy notifications which can interfere with tests
'datareporting.policy.dataSubmissionEnabled': false,
'datareporting.policy.dataSubmissionPolicyAccepted': false,
'datareporting.policy.dataSubmissionPolicyBypassNotification': true,

@@ -472,4 +419,2 @@ // DevTools JSONViewer sometimes fails to load dependencies with its require.js.

'toolkit.cosmeticAnimations.enabled': false,
// We want to collect telemetry, but we don't want to send in the results
'toolkit.telemetry.server': `https://${server}/dummy/telemetry/`,
// Prevent starting into safe mode after application crashes

@@ -486,34 +431,2 @@ 'toolkit.startup.max_resumed_crashes': -1,

}
function getWSEndpoint(browserURL) {
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
const endpointURL = URL.resolve(browserURL, '/json/version');
const protocol = endpointURL.startsWith('https') ? https : http;
const requestOptions = Object.assign(URL.parse(endpointURL), {
method: 'GET',
});
const request = protocol.request(requestOptions, (res) => {
let data = '';
if (res.statusCode !== 200) {
// Consume response data to free up memory.
res.resume();
reject(new Error('HTTP ' + res.statusCode));
return;
}
res.setEncoding('utf8');
res.on('data', (chunk) => (data += chunk));
res.on('end', () => resolve(JSON.parse(data).webSocketDebuggerUrl));
});
request.on('error', reject);
request.end();
return promise.catch((error) => {
error.message =
`Failed to fetch browser webSocket url from ${endpointURL}: ` +
error.message;
throw error;
});
}
function resolveExecutablePath(launcher) {

@@ -520,0 +433,0 @@ let downloadPath;

@@ -16,3 +16,2 @@ /**

*/
import { Viewport } from '../common/PuppeteerViewport.js';
/**

@@ -44,11 +43,2 @@ * Launcher options that only apply to Chrome.

}
/**
* Generic browser options that can be passed when launching any browser.
* @public
*/
export interface BrowserOptions {
ignoreHTTPSErrors?: boolean;
defaultViewport?: Viewport;
slowMo?: number;
}
//# sourceMappingURL=LaunchOptions.d.ts.map
"use strict";
/**
* Copyright 2020 Google Inc. 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });

@@ -20,4 +20,4 @@ "use strict";

exports.PUPPETEER_REVISIONS = {
chromium: '800071',
chromium: '809590',
firefox: 'latest',
};

@@ -19,2 +19,3 @@ /**

export * from './node/BrowserFetcher.js';
export * from './node/Puppeteer.js';
export * from './common/Connection.js';

@@ -33,5 +34,7 @@ export * from './common/ConsoleMessage.js';

export * from './common/Page.js';
export * from './common/Product.js';
export * from './common/Puppeteer.js';
export * from './common/BrowserConnector.js';
export * from './node/Launcher.js';
export * from './node/LaunchOptions.js';
export * from './node/Launcher.js';
export * from './common/HTTPRequest.js';

@@ -50,3 +53,4 @@ export * from './common/HTTPResponse.js';

export * from './common/LifecycleWatcher.js';
export * from './common/QueryHandler.js';
export * from 'devtools-protocol/types/protocol';
//# sourceMappingURL=api-docs-entry.d.ts.map

@@ -21,4 +21,5 @@ /**

*
* We also have src/api.ts. This is used in `index.js` and by the legacy DocLint
* system. src/api-docs-entry.ts is ONLY used by API Extractor.
* The legacy DocLint system and the unit test coverage system use the list of
* modules defined in coverage-utils.js. src/api-docs-entry.ts is ONLY used by
* API Extractor.
*

@@ -31,2 +32,3 @@ * Once we have migrated to API Extractor and removed DocLint we can remove the

export * from './node/BrowserFetcher.js';
export * from './node/Puppeteer.js';
export * from './common/Connection.js';

@@ -45,5 +47,7 @@ export * from './common/ConsoleMessage.js';

export * from './common/Page.js';
export * from './common/Product.js';
export * from './common/Puppeteer.js';
export * from './common/BrowserConnector.js';
export * from './node/Launcher.js';
export * from './node/LaunchOptions.js';
export * from './node/Launcher.js';
export * from './common/HTTPRequest.js';

@@ -62,2 +66,3 @@ export * from './common/HTTPResponse.js';

export * from './common/LifecycleWatcher.js';
export * from './common/QueryHandler.js';
export * from 'devtools-protocol/types/protocol';

@@ -20,3 +20,2 @@ /**

import { Connection } from './Connection.js';
import { Protocol } from 'devtools-protocol';
import { Page } from './Page.js';

@@ -83,3 +82,3 @@ import { ChildProcess } from 'child_process';

* A Browser is created when Puppeteer connects to a Chromium instance, either through
* {@link Puppeteer.launch} or {@link Puppeteer.connect}.
* {@link PuppeteerNode.launch} or {@link Puppeteer.connect}.
*

@@ -393,3 +392,3 @@ * @remarks

*/
overridePermissions(origin: string, permissions: Protocol.Browser.PermissionType[]): Promise<void>;
overridePermissions(origin: string, permissions: string[]): Promise<void>;
/**

@@ -396,0 +395,0 @@ * Clears all permission overrides for the browser context.

@@ -23,3 +23,3 @@ /**

* A Browser is created when Puppeteer connects to a Chromium instance, either through
* {@link Puppeteer.launch} or {@link Puppeteer.connect}.
* {@link PuppeteerNode.launch} or {@link Puppeteer.connect}.
*

@@ -465,3 +465,3 @@ * @remarks

]);
permissions = permissions.map((permission) => {
const protocolPermissions = permissions.map((permission) => {
const protocolPermission = webPermissionToProtocol.get(permission);

@@ -475,3 +475,3 @@ if (!protocolPermission)

browserContextId: this._id || undefined,
permissions,
permissions: protocolPermissions,
});

@@ -478,0 +478,0 @@ }

@@ -39,3 +39,3 @@ import { Protocol } from 'devtools-protocol';

send<T extends keyof ProtocolMapping.Commands>(method: T, ...paramArgs: ProtocolMapping.Commands[T]['paramsType']): Promise<ProtocolMapping.Commands[T]['returnType']>;
_rawSend(message: {}): number;
_rawSend(message: Record<string, unknown>): number;
_onMessage(message: string): Promise<void>;

@@ -53,3 +53,3 @@ _onClose(): void;

method: string;
params: {};
params: Record<string, unknown>;
error: {

@@ -56,0 +56,0 @@ message: string;

@@ -73,5 +73,5 @@ /**

const id = ++this._lastId;
message = JSON.stringify(Object.assign({}, message, { id }));
debugProtocolSend(message);
this._transport.send(message);
const stringifiedMessage = JSON.stringify(Object.assign({}, message, { id }));
debugProtocolSend(stringifiedMessage);
this._transport.send(stringifiedMessage);
return id;

@@ -78,0 +78,0 @@ }

@@ -46,7 +46,7 @@ /**

private _args;
private _location;
private _stackTraceLocations;
/**
* @public
*/
constructor(type: ConsoleMessageType, text: string, args: JSHandle[], location?: ConsoleMessageLocation);
constructor(type: ConsoleMessageType, text: string, args: JSHandle[], stackTraceLocations: ConsoleMessageLocation[]);
/**

@@ -68,3 +68,7 @@ * @returns The type of the console message.

location(): ConsoleMessageLocation;
/**
* @returns The array of locations on the stack of the console message.
*/
stackTrace(): ConsoleMessageLocation[];
}
//# sourceMappingURL=ConsoleMessage.d.ts.map

@@ -24,7 +24,7 @@ /**

*/
constructor(type, text, args, location = {}) {
constructor(type, text, args, stackTraceLocations) {
this._type = type;
this._text = text;
this._args = args;
this._location = location;
this._stackTraceLocations = stackTraceLocations;
}

@@ -53,4 +53,10 @@ /**

location() {
return this._location;
return this._stackTraceLocations.length ? this._stackTraceLocations[0] : {};
}
/**
* @returns The array of locations on the stack of the console message.
*/
stackTrace() {
return this._stackTraceLocations;
}
}

@@ -47,5 +47,7 @@ /**

_waitTasks: Set<WaitTask>;
private _boundFunctions;
private _ctxBindings;
constructor(frameManager: FrameManager, frame: Frame, timeoutSettings: TimeoutSettings);
frame(): Frame;
_setContext(context?: ExecutionContext): void;
_setContext(context?: ExecutionContext): Promise<void>;
_hasContext(): boolean;

@@ -110,4 +112,17 @@ _detach(): void;

waitForSelector(selector: string, options: WaitForSelectorOptions): Promise<ElementHandle | null>;
private _settingUpBinding;
/**
* @internal
*/
addBindingToContext(name: string): any;
/**
* @internal
*/
addBinding(name: string, puppeteerFunction: Function): Promise<void>;
private _onBindingCalled;
/**
* @internal
*/
waitForSelectorInPage(queryOne: Function, selector: string, options: WaitForSelectorOptions): Promise<ElementHandle | null>;
waitForXPath(xpath: string, options: WaitForSelectorOptions): Promise<ElementHandle | null>;
private _makePredicateString;
waitForFunction(pageFunction: Function | string, options?: {

@@ -119,3 +134,6 @@ polling?: string | number;

}
declare class WaitTask {
/**
* @internal
*/
export declare class WaitTask {
_domWorld: DOMWorld;

@@ -137,3 +155,2 @@ _polling: string | number;

}
export {};
//# sourceMappingURL=DOMWorld.d.ts.map

@@ -17,3 +17,3 @@ /**

import { assert } from './assert.js';
import { helper } from './helper.js';
import { helper, debugError } from './helper.js';
import { LifecycleWatcher, } from './LifecycleWatcher.js';

@@ -36,2 +36,9 @@ import { TimeoutError } from './Errors.js';

this._waitTasks = new Set();
// Contains mapping from functions that should be bound to Puppeteer functions.
this._boundFunctions = new Map();
// Set of bindings that have been registered in the current context.
this._ctxBindings = new Set();
// If multiple waitFor are set up asynchronously, we need to wait for the
// first one to set up the binding in the page before running the others.
this._settingUpBinding = null;
this._frameManager = frameManager;

@@ -41,2 +48,3 @@ this._frame = frame;

this._setContext(null);
frameManager._client.on('Runtime.bindingCalled', (event) => this._onBindingCalled(event));
}

@@ -46,6 +54,10 @@ frame() {

}
_setContext(context) {
async _setContext(context) {
if (context) {
this._contextResolveCallback.call(null, context);
this._contextResolveCallback = null;
this._ctxBindings.clear();
for (const name of this._boundFunctions.keys()) {
await this.addBindingToContext(name);
}
for (const waitTask of this._waitTasks)

@@ -71,3 +83,3 @@ waitTask.rerun();

if (this._detached)
throw new Error(`Execution Context is not available in detached frame "${this._frame.url()}" (are you trying to evaluate?)`);
throw new Error(`Execution context is not available in detached frame "${this._frame.url()}" (are you trying to evaluate?)`);
return this._contextPromise;

@@ -168,8 +180,4 @@ }

}
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fs = require('fs');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { promisify } = require('util');
const readFileAsync = promisify(fs.readFile);
let contents = await readFileAsync(path, 'utf8');
const fs = await import('fs');
let contents = await fs.promises.readFile(path, 'utf8');
contents += '//# sourceURL=' + path.replace(/\n/g, '');

@@ -234,8 +242,4 @@ const context = await this.executionContext();

}
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fs = require('fs');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { promisify } = require('util');
const readFileAsync = promisify(fs.readFile);
let contents = await readFileAsync(path, 'utf8');
const fs = await import('fs');
let contents = await fs.promises.readFile(path, 'utf8');
contents += '/*# sourceURL=' + path.replace(/\n/g, '') + '*/';

@@ -302,3 +306,2 @@ const context = await this.executionContext();

const handle = await this.$(selector);
assert(handle, 'No node found for selector: ' + selector);
await handle.tap();

@@ -314,13 +317,106 @@ await handle.dispose();

async waitForSelector(selector, options) {
const { updatedSelector, queryHandler } = getQueryHandlerAndSelector(selector);
return queryHandler.waitFor(this, updatedSelector, options);
}
/**
* @internal
*/
async addBindingToContext(name) {
// Previous operation added the binding so we are done.
if (this._ctxBindings.has(name))
return;
// Wait for other operation to finish
if (this._settingUpBinding) {
await this._settingUpBinding;
return this.addBindingToContext(name);
}
const bind = async (name) => {
const expression = helper.pageBindingInitString('internal', name);
try {
const context = await this.executionContext();
await context._client.send('Runtime.addBinding', {
name,
executionContextId: context._contextId,
});
await context.evaluate(expression);
}
catch (error) {
// We could have tried to evaluate in a context which was already
// destroyed. This happens, for example, if the page is navigated while
// we are trying to add the binding
const ctxDestroyed = error.message.includes('Execution context was destroyed');
const ctxNotFound = error.message.includes('Cannot find context with specified id');
if (ctxDestroyed || ctxNotFound) {
// Retry adding the binding in the next context
await bind(name);
}
else {
debugError(error);
return;
}
}
this._ctxBindings.add(name);
};
this._settingUpBinding = bind(name);
await this._settingUpBinding;
this._settingUpBinding = null;
}
/**
* @internal
*/
async addBinding(name, puppeteerFunction) {
this._boundFunctions.set(name, puppeteerFunction);
await this.addBindingToContext(name);
}
async _onBindingCalled(event) {
let payload;
try {
payload = JSON.parse(event.payload);
}
catch {
// The binding was either called by something in the page or it was
// called before our wrapper was initialized.
return;
}
const { type, name, seq, args } = payload;
if (type !== 'internal' || !this._ctxBindings.has(name))
return;
if (!this._hasContext())
return;
const context = await this.executionContext();
if (context._contextId !== event.executionContextId)
return;
try {
const result = await this._boundFunctions.get(name)(...args);
await context.evaluate(deliverResult, name, seq, result);
}
catch (error) {
// The WaitTask may already have been resolved by timing out, or the
// exection context may have been destroyed.
// In both caes, the promises above are rejected with a protocol error.
// We can safely ignores these, as the WaitTask is re-installed in
// the next execution context if needed.
if (error.message.includes('Protocol error'))
return;
debugError(error);
}
function deliverResult(name, seq, result) {
globalThis[name].callbacks.get(seq).resolve(result);
globalThis[name].callbacks.delete(seq);
}
}
/**
* @internal
*/
async waitForSelectorInPage(queryOne, selector, options) {
const { visible: waitForVisible = false, hidden: waitForHidden = false, timeout = this._timeoutSettings.timeout(), } = options;
const polling = waitForVisible || waitForHidden ? 'raf' : 'mutation';
const title = `selector \`${selector}\`${waitForHidden ? ' to be hidden' : ''}`;
const { updatedSelector, queryHandler } = getQueryHandlerAndSelector(selector);
function predicate(selector, waitForVisible, waitForHidden) {
async function predicate(selector, waitForVisible, waitForHidden) {
const node = predicateQueryHandler
? predicateQueryHandler(document, selector)
? (await predicateQueryHandler(document, selector))
: document.querySelector(selector);
return checkWaitForOptions(node, waitForVisible, waitForHidden);
}
const waitTask = new WaitTask(this, this._makePredicateString(predicate, queryHandler.queryOne), title, polling, timeout, updatedSelector, waitForVisible, waitForHidden);
const waitTask = new WaitTask(this, helper.makePredicateString(predicate, queryOne), title, polling, timeout, selector, waitForVisible, waitForHidden);
const jsHandle = await waitTask.promise;

@@ -342,3 +438,3 @@ const elementHandle = jsHandle.asElement();

}
const waitTask = new WaitTask(this, this._makePredicateString(predicate), title, polling, timeout, xpath, waitForVisible, waitForHidden);
const waitTask = new WaitTask(this, helper.makePredicateString(predicate), title, polling, timeout, xpath, waitForVisible, waitForHidden);
const jsHandle = await waitTask.promise;

@@ -352,30 +448,2 @@ const elementHandle = jsHandle.asElement();

}
_makePredicateString(predicate, predicateQueryHandler) {
const predicateQueryHandlerDef = predicateQueryHandler
? `const predicateQueryHandler = ${predicateQueryHandler};`
: '';
return `
(() => {
${predicateQueryHandlerDef}
const checkWaitForOptions = ${checkWaitForOptions};
return (${predicate})(...args)
})() `;
function checkWaitForOptions(node, waitForVisible, waitForHidden) {
if (!node)
return waitForHidden;
if (!waitForVisible && !waitForHidden)
return node;
const element = node.nodeType === Node.TEXT_NODE
? node.parentElement
: node;
const style = window.getComputedStyle(element);
const isVisible = style && style.visibility !== 'hidden' && hasVisibleBoundingBox();
const success = waitForVisible === isVisible || waitForHidden === !isVisible;
return success ? node : null;
function hasVisibleBoundingBox() {
const rect = element.getBoundingClientRect();
return !!(rect.top || rect.bottom || rect.width || rect.height);
}
}
}
waitForFunction(pageFunction, options = {}, ...args) {

@@ -389,3 +457,6 @@ const { polling = 'raf', timeout = this._timeoutSettings.timeout(), } = options;

}
class WaitTask {
/**
* @internal
*/
export class WaitTask {
constructor(domWorld, predicateBody, title, polling, timeout, ...args) {

@@ -453,15 +524,23 @@ this._runCount = 0;

}
// When the page is navigated, the promise is rejected.
// We will try again in the new execution context.
if (error && error.message.includes('Execution context was destroyed'))
return;
// We could have tried to evaluate in a context which was already
// destroyed.
if (error &&
error.message.includes('Cannot find context with specified id'))
return;
if (error)
// When frame is detached the task should have been terminated by the DOMWorld.
// This can fail if we were adding this task while the frame was detached,
// so we terminate here instead.
if (error) {
if (error.message.includes('Execution context is not available in detached frame')) {
this.terminate(new Error('waitForFunction failed: frame got detached.'));
return;
}
// When the page is navigated, the promise is rejected.
// We will try again in the new execution context.
if (error.message.includes('Execution context was destroyed'))
return;
// We could have tried to evaluate in a context which was already
// destroyed.
if (error.message.includes('Cannot find context with specified id'))
return;
this._reject(error);
else
}
else {
this._resolve(success);
}
this._cleanup();

@@ -468,0 +547,0 @@ }

@@ -25,3 +25,3 @@ /**

* Example operations are {@link Page.waitForSelector | page.waitForSelector}
* or {@link Puppeteer.launch | puppeteer.launch}.
* or {@link PuppeteerNode.launch | puppeteer.launch}.
*

@@ -28,0 +28,0 @@ * @public

@@ -29,3 +29,3 @@ /**

* Example operations are {@link Page.waitForSelector | page.waitForSelector}
* or {@link Puppeteer.launch | puppeteer.launch}.
* or {@link PuppeteerNode.launch | puppeteer.launch}.
*

@@ -32,0 +32,0 @@ * @public

@@ -49,6 +49,9 @@ /**

_world: DOMWorld;
private _contextId;
/**
* @internal
*/
_contextId: number;
/**
* @internal
*/
constructor(client: CDPSession, contextPayload: Protocol.Runtime.ExecutionContextDescription, world: DOMWorld);

@@ -55,0 +58,0 @@ /**

@@ -600,3 +600,3 @@ /**

*/
waitFor(selectorOrFunctionOrTimeout: string | number | Function, options?: {}, ...args: SerializableOrJSHandle[]): Promise<JSHandle | null>;
waitFor(selectorOrFunctionOrTimeout: string | number | Function, options?: Record<string, unknown>, ...args: SerializableOrJSHandle[]): Promise<JSHandle | null>;
/**

@@ -603,0 +603,0 @@ * Causes your script to wait for the given number of milliseconds.

@@ -24,2 +24,7 @@ /// <reference types="node" />

declare function evaluationString(fun: Function | string, ...args: unknown[]): string;
declare function pageBindingInitString(type: string, name: string): string;
declare function pageBindingDeliverResultString(name: string, seq: number, result: unknown): string;
declare function pageBindingDeliverErrorString(name: string, seq: number, message: string, stack: string): string;
declare function pageBindingDeliverErrorValueString(name: string, seq: number, value: unknown): string;
declare function makePredicateString(predicate: Function, predicateQueryHandler?: Function): string;
declare function waitWithTimeout<T extends any>(promise: Promise<T>, taskName: string, timeout: number): Promise<T>;

@@ -29,2 +34,7 @@ declare function readProtocolStream(client: CDPSession, handle: string, path?: string): Promise<Buffer>;

evaluationString: typeof evaluationString;
pageBindingInitString: typeof pageBindingInitString;
pageBindingDeliverResultString: typeof pageBindingDeliverResultString;
pageBindingDeliverErrorString: typeof pageBindingDeliverErrorString;
pageBindingDeliverErrorValueString: typeof pageBindingDeliverErrorValueString;
makePredicateString: typeof makePredicateString;
readProtocolStream: typeof readProtocolStream;

@@ -31,0 +41,0 @@ waitWithTimeout: typeof waitWithTimeout;

@@ -18,8 +18,4 @@ /**

import { debug } from './Debug.js';
import * as fs from 'fs';
import { promisify } from 'util';
import { assert } from './assert.js';
const openAsync = promisify(fs.open);
const writeAsync = promisify(fs.write);
const closeAsync = promisify(fs.close);
import { isNode } from '../environment.js';
export const debugError = debug('puppeteer:error');

@@ -133,2 +129,74 @@ function getExceptionMessage(exceptionDetails) {

}
function pageBindingInitString(type, name) {
function addPageBinding(type, bindingName) {
/* Cast window to any here as we're about to add properties to it
* via win[bindingName] which TypeScript doesn't like.
*/
const win = window;
const binding = win[bindingName];
win[bindingName] = (...args) => {
const me = window[bindingName];
let callbacks = me.callbacks;
if (!callbacks) {
callbacks = new Map();
me.callbacks = callbacks;
}
const seq = (me.lastSeq || 0) + 1;
me.lastSeq = seq;
const promise = new Promise((resolve, reject) => callbacks.set(seq, { resolve, reject }));
binding(JSON.stringify({ type, name: bindingName, seq, args }));
return promise;
};
}
return evaluationString(addPageBinding, type, name);
}
function pageBindingDeliverResultString(name, seq, result) {
function deliverResult(name, seq, result) {
window[name].callbacks.get(seq).resolve(result);
window[name].callbacks.delete(seq);
}
return evaluationString(deliverResult, name, seq, result);
}
function pageBindingDeliverErrorString(name, seq, message, stack) {
function deliverError(name, seq, message, stack) {
const error = new Error(message);
error.stack = stack;
window[name].callbacks.get(seq).reject(error);
window[name].callbacks.delete(seq);
}
return evaluationString(deliverError, name, seq, message, stack);
}
function pageBindingDeliverErrorValueString(name, seq, value) {
function deliverErrorValue(name, seq, value) {
window[name].callbacks.get(seq).reject(value);
window[name].callbacks.delete(seq);
}
return evaluationString(deliverErrorValue, name, seq, value);
}
function makePredicateString(predicate, predicateQueryHandler) {
function checkWaitForOptions(node, waitForVisible, waitForHidden) {
if (!node)
return waitForHidden;
if (!waitForVisible && !waitForHidden)
return node;
const element = node.nodeType === Node.TEXT_NODE ? node.parentElement : node;
const style = window.getComputedStyle(element);
const isVisible = style && style.visibility !== 'hidden' && hasVisibleBoundingBox();
const success = waitForVisible === isVisible || waitForHidden === !isVisible;
return success ? node : null;
function hasVisibleBoundingBox() {
const rect = element.getBoundingClientRect();
return !!(rect.top || rect.bottom || rect.width || rect.height);
}
}
const predicateQueryHandlerDef = predicateQueryHandler
? `const predicateQueryHandler = ${predicateQueryHandler};`
: '';
return `
(() => {
${predicateQueryHandlerDef}
const checkWaitForOptions = ${checkWaitForOptions};
return (${predicate})(...args)
})() `;
}
async function waitWithTimeout(promise, taskName, timeout) {

@@ -150,6 +218,11 @@ let reject;

async function readProtocolStream(client, handle, path) {
if (!isNode && path) {
throw new Error('Cannot write to a path outside of Node.js environment.');
}
const fs = isNode ? await import('fs') : null;
let eof = false;
let file;
if (path)
file = await openAsync(path, 'w');
let fileHandle;
if (path && fs) {
fileHandle = await fs.promises.open(path, 'w');
}
const bufs = [];

@@ -161,7 +234,8 @@ while (!eof) {

bufs.push(buf);
if (path)
await writeAsync(file, buf);
if (path && fs) {
await fs.promises.writeFile(fileHandle, buf);
}
}
if (path)
await closeAsync(file);
await fileHandle.close();
await client.send('IO.close', { handle });

@@ -178,2 +252,7 @@ let resultBuffer = null;

evaluationString,
pageBindingInitString,
pageBindingDeliverResultString,
pageBindingDeliverErrorString,
pageBindingDeliverErrorValueString,
makePredicateString,
readProtocolStream,

@@ -180,0 +259,0 @@ waitWithTimeout,

@@ -169,3 +169,3 @@ /**

*/
jsonValue(): Promise<{}>;
jsonValue(): Promise<Record<string, unknown>>;
/**

@@ -172,0 +172,0 @@ * Returns either `null` or the object handle itself, if the object handle is

@@ -19,2 +19,3 @@ /**

import { getQueryHandlerAndSelector } from './QueryHandler.js';
import { isNode } from '../environment.js';
/**

@@ -266,6 +267,5 @@ * @internal

inline: 'center',
// Chrome still supports behavior: instant but it's not in the spec
// so TS shouts We don't want to make this breaking change in
// Puppeteer yet so we'll ignore the line.
// @ts-ignore
// @ts-expect-error Chrome still supports behavior: instant but
// it's not in the spec so TS shouts We don't want to make this
// breaking change in Puppeteer yet so we'll ignore the line.
behavior: 'instant',

@@ -286,6 +286,5 @@ });

inline: 'center',
// Chrome still supports behavior: instant but it's not in the spec
// so TS shouts We don't want to make this breaking change in
// Puppeteer yet so we'll ignore the line.
// @ts-ignore
// @ts-expect-error Chrome still supports behavior: instant but
// it's not in the spec so TS shouts We don't want to make this
// breaking change in Puppeteer yet so we'll ignore the line.
behavior: 'instant',

@@ -421,11 +420,10 @@ });

assert(filePaths.length <= 1 || isMultiple, 'Multiple file uploads only work with <input type=file multiple>');
if (!isNode) {
throw new Error(`JSHandle#uploadFile can only be used in Node environments.`);
}
// This import is only needed for `uploadFile`, so keep it scoped here to avoid paying
// the cost unnecessarily.
const path = await import('path');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const path = require('path');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fs = require('fs');
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { promisify } = require('util');
const access = promisify(fs.access);
const fs = await import('fs');
// Locate all files and confirm that they exist.

@@ -435,3 +433,3 @@ const files = await Promise.all(filePaths.map(async (filePath) => {

try {
await access(resolvedPath, fs.constants.R_OK);
await fs.promises.access(resolvedPath, fs.constants.R_OK);
}

@@ -605,8 +603,3 @@ catch (error) {

const { updatedSelector, queryHandler } = getQueryHandlerAndSelector(selector);
const handle = await this.evaluateHandle(queryHandler.queryOne, updatedSelector);
const element = handle.asElement();
if (element)
return element;
await handle.dispose();
return null;
return queryHandler.queryOne(this, updatedSelector);
}

@@ -619,12 +612,3 @@ /**

const { updatedSelector, queryHandler } = getQueryHandlerAndSelector(selector);
const handles = await this.evaluateHandle(queryHandler.queryAll, updatedSelector);
const properties = await handles.getProperties();
await handles.dispose();
const result = [];
for (const property of properties.values()) {
const elementHandle = property.asElement();
if (elementHandle)
result.push(elementHandle);
}
return result;
return queryHandler.queryAll(this, updatedSelector);
}

@@ -687,4 +671,3 @@ /**

const { updatedSelector, queryHandler } = getQueryHandlerAndSelector(selector);
const queryHandlerToArray = Function('element', 'selector', `return Array.from((${queryHandler.queryAll})(element, selector));`);
const arrayHandle = await this.evaluateHandle(queryHandlerToArray, updatedSelector);
const arrayHandle = await queryHandler.queryAllArray(this, updatedSelector);
const result = await arrayHandle.evaluate(pageFunction, ...args);

@@ -691,0 +674,0 @@ await arrayHandle.dispose();

@@ -16,4 +16,2 @@ /**

*/
import * as fs from 'fs';
import { promisify } from 'util';
import { EventEmitter } from './EventEmitter.js';

@@ -37,3 +35,3 @@ import { Connection, CDPSessionEmittedEvents, } from './Connection.js';

import { paperFormats } from './PDFOptions.js';
const writeFileAsync = promisify(fs.writeFile);
import { isNode } from '../environment.js';
class ScreenshotTaskQueue {

@@ -276,3 +274,3 @@ constructor() {

if (source !== 'worker')
this.emit("console" /* Console */, new ConsoleMessage(level, text, [], { url, lineNumber }));
this.emit("console" /* Console */, new ConsoleMessage(level, text, [], [{ url, lineNumber }]));
}

@@ -643,3 +641,3 @@ /**

this._pageBindings.set(name, puppeteerFunction);
const expression = helper.evaluationString(addPageBinding, name);
const expression = helper.pageBindingInitString('exposedFun', name);
await this._client.send('Runtime.addBinding', { name: name });

@@ -650,22 +648,2 @@ await this._client.send('Page.addScriptToEvaluateOnNewDocument', {

await Promise.all(this.frames().map((frame) => frame.evaluate(expression).catch(debugError)));
function addPageBinding(bindingName) {
/* Cast window to any here as we're about to add properties to it
* via win[bindingName] which TypeScript doesn't like.
*/
const win = window;
const binding = win[bindingName];
win[bindingName] = (...args) => {
const me = window[bindingName];
let callbacks = me['callbacks'];
if (!callbacks) {
callbacks = new Map();
me['callbacks'] = callbacks;
}
const seq = (me['lastSeq'] || 0) + 1;
me['lastSeq'] = seq;
const promise = new Promise((resolve, reject) => callbacks.set(seq, { resolve, reject }));
binding(JSON.stringify({ name: bindingName, seq, args }));
return promise;
};
}
}

@@ -727,13 +705,24 @@ async authenticate(credentials) {

async _onBindingCalled(event) {
const { name, seq, args } = JSON.parse(event.payload);
let payload;
try {
payload = JSON.parse(event.payload);
}
catch {
// The binding was either called by something in the page or it was
// called before our wrapper was initialized.
return;
}
const { type, name, seq, args } = payload;
if (type !== 'exposedFun' || !this._pageBindings.has(name))
return;
let expression = null;
try {
const result = await this._pageBindings.get(name)(...args);
expression = helper.evaluationString(deliverResult, name, seq, result);
expression = helper.pageBindingDeliverResultString(name, seq, result);
}
catch (error) {
if (error instanceof Error)
expression = helper.evaluationString(deliverError, name, seq, error.message, error.stack);
expression = helper.pageBindingDeliverErrorString(name, seq, error.message, error.stack);
else
expression = helper.evaluationString(deliverErrorValue, name, seq, error);
expression = helper.pageBindingDeliverErrorValueString(name, seq, error);
}

@@ -746,16 +735,2 @@ this._client

.catch(debugError);
function deliverResult(name, seq, result) {
window[name]['callbacks'].get(seq).resolve(result);
window[name]['callbacks'].delete(seq);
}
function deliverError(name, seq, message, stack) {
const error = new Error(message);
error.stack = stack;
window[name]['callbacks'].get(seq).reject(error);
window[name]['callbacks'].delete(seq);
}
function deliverErrorValue(name, seq, value) {
window[name]['callbacks'].get(seq).reject(value);
window[name]['callbacks'].delete(seq);
}
}

@@ -775,10 +750,13 @@ _addConsoleMessage(type, args, stackTrace) {

}
const location = stackTrace && stackTrace.callFrames.length
? {
url: stackTrace.callFrames[0].url,
lineNumber: stackTrace.callFrames[0].lineNumber,
columnNumber: stackTrace.callFrames[0].columnNumber,
const stackTraceLocations = [];
if (stackTrace) {
for (const callFrame of stackTrace.callFrames) {
stackTraceLocations.push({
url: callFrame.url,
lineNumber: callFrame.lineNumber,
columnNumber: callFrame.columnNumber,
});
}
: {};
const message = new ConsoleMessage(type, textTokens.join(' '), args, location);
}
const message = new ConsoleMessage(type, textTokens.join(' '), args, stackTraceLocations);
this.emit("console" /* Console */, message);

@@ -1150,4 +1128,8 @@ }

: Buffer.from(result.data, 'base64');
if (!isNode && options.path) {
throw new Error('Screenshots can only be written to a file path in a Node environment.');
}
const fs = await import('fs');
if (options.path)
await writeFileAsync(options.path, buffer);
await fs.promises.writeFile(options.path, buffer);
return buffer;

@@ -1154,0 +1136,0 @@ function processClip(clip) {

@@ -1,4 +0,16 @@

import { LaunchOptions, ChromeArgOptions, BrowserOptions } from '../node/LaunchOptions.js';
import { ProductLauncher } from '../node/Launcher.js';
import { BrowserFetcher, BrowserFetcherOptions } from '../node/BrowserFetcher.js';
/**
* Copyright 2017 Google Inc. 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.
*/
import { PuppeteerErrors } from './Errors.js';

@@ -8,76 +20,35 @@ import { ConnectionTransport } from './ConnectionTransport.js';

import { Browser } from './Browser.js';
import { QueryHandler } from './QueryHandler.js';
import { CustomQueryHandler } from './QueryHandler.js';
import { Product } from './Product.js';
import { BrowserOptions } from './BrowserConnector.js';
/**
* The main Puppeteer class. Provides the {@link Puppeteer.launch | launch}
* method to launch a browser.
* Settings that are common to the Puppeteer class, regardless of enviroment.
* @internal
*/
export interface CommonPuppeteerSettings {
isPuppeteerCore: boolean;
}
export interface ConnectOptions extends BrowserOptions {
browserWSEndpoint?: string;
browserURL?: string;
transport?: ConnectionTransport;
product?: Product;
}
/**
* The main Puppeteer class.
*
* When you `require` or `import` the Puppeteer npm package you get back an
* instance of this class.
*
* @remarks
*
* @example
* The following is a typical example of using Puppeteer to drive automation:
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* await page.goto('https://www.google.com');
* // other actions...
* await browser.close();
* })();
* ```
*
* Once you have created a `page` you have access to a large API to interact
* with the page, navigate, or find certain elements in that page.
* The {@link Page | `page` documentation} lists all the available methods.
*
* IMPORTANT: if you are using Puppeteer in a Node environment, you will get an
* instance of {@link PuppeteerNode} when you import or require `puppeteer`.
* That class extends `Puppeteer`, so has all the methods documented below as
* well as all that are defined on {@link PuppeteerNode}.
* @public
*/
export declare class Puppeteer {
private _projectRoot;
private _isPuppeteerCore;
private _changedProduct;
private __productName;
private _lazyLauncher;
protected _isPuppeteerCore: boolean;
protected _changedProduct: boolean;
/**
* @internal
*/
_preferredRevision: string;
constructor(settings: CommonPuppeteerSettings);
/**
* @internal
*/
constructor(projectRoot: string, preferredRevision: string, isPuppeteerCore: boolean, productName: string);
/**
* Launches puppeteer and launches a browser instance with given arguments
* and options when specified.
*
* @remarks
*
* @example
* You can use `ignoreDefaultArgs` to filter out `--mute-audio` from default arguments:
* ```js
* const browser = await puppeteer.launch({
* ignoreDefaultArgs: ['--mute-audio']
* });
* ```
*
* **NOTE** Puppeteer can also be used to control the Chrome browser,
* but it works best with the version of Chromium it is bundled with.
* There is no guarantee it will work with any other version.
* Use `executablePath` option with extreme caution.
* If Google Chrome (rather than Chromium) is preferred, a {@link https://www.google.com/chrome/browser/canary.html | Chrome Canary} or {@link https://www.chromium.org/getting-involved/dev-channel | Dev Channel} build is suggested.
* In `puppeteer.launch([options])`, any mention of Chromium also applies to Chrome.
* See {@link https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/ | this article} for a description of the differences between Chromium and Chrome. {@link https://chromium.googlesource.com/chromium/src/+/lkgr/docs/chromium_browser_vs_google_chrome.md | This article} describes some differences for Linux users.
*
* @param options - Set of configurable options to set on the browser.
* @returns Promise which resolves to browser instance.
*/
launch(options?: LaunchOptions & ChromeArgOptions & BrowserOptions & {
product?: string;
extraPrefsFirefox?: {};
}): Promise<Browser>;
/**
* This method attaches Puppeteer to an existing browser instance.

@@ -90,39 +61,5 @@ *

*/
connect(options: BrowserOptions & {
browserWSEndpoint?: string;
browserURL?: string;
transport?: ConnectionTransport;
product?: string;
}): Promise<Browser>;
connect(options: ConnectOptions): Promise<Browser>;
/**
* @internal
*/
get _productName(): string;
set _productName(name: string);
/**
* @remarks
*
* **NOTE** `puppeteer.executablePath()` is affected by the `PUPPETEER_EXECUTABLE_PATH`
* and `PUPPETEER_CHROMIUM_REVISION` environment variables.
*
* @returns A path where Puppeteer expects to find the bundled browser.
* The browser binary might not be there if the download was skipped with
* the `PUPPETEER_SKIP_DOWNLOAD` environment variable.
*/
executablePath(): string;
/**
* @internal
*/
get _launcher(): ProductLauncher;
/**
* The name of the browser that is under automation (`"chrome"` or `"firefox"`)
*
* @remarks
* The product is set by the `PUPPETEER_PRODUCT` environment variable or the `product`
* option in `puppeteer.launch([options])` and defaults to `chrome`.
* Firefox support is experimental.
*/
get product(): string;
/**
* @remarks
* A list of devices to be used with `page.emulate(options)`. Actual list of devices can be found in {@link https://github.com/puppeteer/puppeteer/blob/main/src/common/DeviceDescriptors.ts | src/common/DeviceDescriptors.ts}.

@@ -172,30 +109,29 @@ *

/**
*
* @param options - Set of configurable options to set on the browser.
* @returns The default flags that Chromium will be launched with.
* Registers a {@link CustomQueryHandler | custom query handler}. After
* registration, the handler can be used everywhere where a selector is
* expected by prepending the selection string with `<name>/`. The name is
* only allowed to consist of lower- and upper case latin letters.
* @example
* ```
* puppeteer.registerCustomQueryHandler('text', { … });
* const aHandle = await page.$('text/…');
* ```
* @param name - The name that the custom query handler will be registered under.
* @param queryHandler - The {@link CustomQueryHandler | custom query handler} to
* register.
*/
defaultArgs(options?: ChromeArgOptions): string[];
registerCustomQueryHandler(name: string, queryHandler: CustomQueryHandler): void;
/**
* @param options - Set of configurable options to specify the settings
* of the BrowserFetcher.
* @returns A new BrowserFetcher instance.
* @param name - The name of the query handler to unregistered.
*/
createBrowserFetcher(options: BrowserFetcherOptions): BrowserFetcher;
unregisterCustomQueryHandler(name: string): void;
/**
* @internal
* @returns a list with the names of all registered custom query handlers.
*/
__experimental_registerCustomQueryHandler(name: string, queryHandler: QueryHandler): void;
customQueryHandlerNames(): string[];
/**
* @internal
* Clears all registered handlers.
*/
__experimental_unregisterCustomQueryHandler(name: string): void;
/**
* @internal
*/
__experimental_customQueryHandlers(): Map<string, QueryHandler>;
/**
* @internal
*/
__experimental_clearQueryHandlers(): void;
clearCustomQueryHandlers(): void;
}
//# sourceMappingURL=Puppeteer.d.ts.map

@@ -16,35 +16,13 @@ /**

*/
import Launcher from '../node/Launcher.js';
import { BrowserFetcher, } from '../node/BrowserFetcher.js';
import { puppeteerErrors } from './Errors.js';
import { devicesMap } from './DeviceDescriptors.js';
import { registerCustomQueryHandler, unregisterCustomQueryHandler, customQueryHandlers, clearQueryHandlers, } from './QueryHandler.js';
import { PUPPETEER_REVISIONS } from '../revisions.js';
import { registerCustomQueryHandler, unregisterCustomQueryHandler, customQueryHandlerNames, clearCustomQueryHandlers, } from './QueryHandler.js';
import { connectToBrowser } from './BrowserConnector.js';
/**
* The main Puppeteer class. Provides the {@link Puppeteer.launch | launch}
* method to launch a browser.
* The main Puppeteer class.
*
* When you `require` or `import` the Puppeteer npm package you get back an
* instance of this class.
*
* @remarks
*
* @example
* The following is a typical example of using Puppeteer to drive automation:
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* await page.goto('https://www.google.com');
* // other actions...
* await browser.close();
* })();
* ```
*
* Once you have created a `page` you have access to a large API to interact
* with the page, navigate, or find certain elements in that page.
* The {@link Page | `page` documentation} lists all the available methods.
*
* IMPORTANT: if you are using Puppeteer in a Node environment, you will get an
* instance of {@link PuppeteerNode} when you import or require `puppeteer`.
* That class extends `Puppeteer`, so has all the methods documented below as
* well as all that are defined on {@link PuppeteerNode}.
* @public

@@ -56,41 +34,7 @@ */

*/
constructor(projectRoot, preferredRevision, isPuppeteerCore, productName) {
constructor(settings) {
this._changedProduct = false;
this._projectRoot = projectRoot;
this._preferredRevision = preferredRevision;
this._isPuppeteerCore = isPuppeteerCore;
// track changes to Launcher configuration via options or environment variables
this.__productName = productName;
this._isPuppeteerCore = settings.isPuppeteerCore;
}
/**
* Launches puppeteer and launches a browser instance with given arguments
* and options when specified.
*
* @remarks
*
* @example
* You can use `ignoreDefaultArgs` to filter out `--mute-audio` from default arguments:
* ```js
* const browser = await puppeteer.launch({
* ignoreDefaultArgs: ['--mute-audio']
* });
* ```
*
* **NOTE** Puppeteer can also be used to control the Chrome browser,
* but it works best with the version of Chromium it is bundled with.
* There is no guarantee it will work with any other version.
* Use `executablePath` option with extreme caution.
* If Google Chrome (rather than Chromium) is preferred, a {@link https://www.google.com/chrome/browser/canary.html | Chrome Canary} or {@link https://www.chromium.org/getting-involved/dev-channel | Dev Channel} build is suggested.
* In `puppeteer.launch([options])`, any mention of Chromium also applies to Chrome.
* See {@link https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/ | this article} for a description of the differences between Chromium and Chrome. {@link https://chromium.googlesource.com/chromium/src/+/lkgr/docs/chromium_browser_vs_google_chrome.md | This article} describes some differences for Linux users.
*
* @param options - Set of configurable options to set on the browser.
* @returns Promise which resolves to browser instance.
*/
launch(options = {}) {
if (options.product)
this._productName = options.product;
return this._launcher.launch(options);
}
/**
* This method attaches Puppeteer to an existing browser instance.

@@ -104,64 +48,6 @@ *

connect(options) {
if (options.product)
this._productName = options.product;
return this._launcher.connect(options);
return connectToBrowser(options);
}
/**
* @internal
*/
get _productName() {
return this.__productName;
}
// don't need any TSDoc here - because the getter is internal the setter is too.
set _productName(name) {
if (this.__productName !== name)
this._changedProduct = true;
this.__productName = name;
}
/**
* @remarks
*
* **NOTE** `puppeteer.executablePath()` is affected by the `PUPPETEER_EXECUTABLE_PATH`
* and `PUPPETEER_CHROMIUM_REVISION` environment variables.
*
* @returns A path where Puppeteer expects to find the bundled browser.
* The browser binary might not be there if the download was skipped with
* the `PUPPETEER_SKIP_DOWNLOAD` environment variable.
*/
executablePath() {
return this._launcher.executablePath();
}
/**
* @internal
*/
get _launcher() {
if (!this._lazyLauncher ||
this._lazyLauncher.product !== this._productName ||
this._changedProduct) {
switch (this._productName) {
case 'firefox':
this._preferredRevision = PUPPETEER_REVISIONS.firefox;
break;
case 'chrome':
default:
this._preferredRevision = PUPPETEER_REVISIONS.chromium;
}
this._changedProduct = false;
this._lazyLauncher = Launcher(this._projectRoot, this._preferredRevision, this._isPuppeteerCore, this._productName);
}
return this._lazyLauncher;
}
/**
* The name of the browser that is under automation (`"chrome"` or `"firefox"`)
*
* @remarks
* The product is set by the `PUPPETEER_PRODUCT` environment variable or the `product`
* option in `puppeteer.launch([options])` and defaults to `chrome`.
* Firefox support is experimental.
*/
get product() {
return this._launcher.product;
}
/**
* @remarks
* A list of devices to be used with `page.emulate(options)`. Actual list of devices can be found in {@link https://github.com/puppeteer/puppeteer/blob/main/src/common/DeviceDescriptors.ts | src/common/DeviceDescriptors.ts}.

@@ -215,45 +101,36 @@ *

/**
*
* @param options - Set of configurable options to set on the browser.
* @returns The default flags that Chromium will be launched with.
* Registers a {@link CustomQueryHandler | custom query handler}. After
* registration, the handler can be used everywhere where a selector is
* expected by prepending the selection string with `<name>/`. The name is
* only allowed to consist of lower- and upper case latin letters.
* @example
* ```
* puppeteer.registerCustomQueryHandler('text', { … });
* const aHandle = await page.$('text/…');
* ```
* @param name - The name that the custom query handler will be registered under.
* @param queryHandler - The {@link CustomQueryHandler | custom query handler} to
* register.
*/
defaultArgs(options = {}) {
return this._launcher.defaultArgs(options);
}
/**
* @param options - Set of configurable options to specify the settings
* of the BrowserFetcher.
* @returns A new BrowserFetcher instance.
*/
createBrowserFetcher(options) {
return new BrowserFetcher(this._projectRoot, options);
}
/**
* @internal
*/
// eslint-disable-next-line @typescript-eslint/camelcase
__experimental_registerCustomQueryHandler(name, queryHandler) {
registerCustomQueryHandler(name, queryHandler) {
registerCustomQueryHandler(name, queryHandler);
}
/**
* @internal
* @param name - The name of the query handler to unregistered.
*/
// eslint-disable-next-line @typescript-eslint/camelcase
__experimental_unregisterCustomQueryHandler(name) {
unregisterCustomQueryHandler(name) {
unregisterCustomQueryHandler(name);
}
/**
* @internal
* @returns a list with the names of all registered custom query handlers.
*/
// eslint-disable-next-line @typescript-eslint/camelcase
__experimental_customQueryHandlers() {
return customQueryHandlers();
customQueryHandlerNames() {
return customQueryHandlerNames();
}
/**
* @internal
* Clears all registered handlers.
*/
// eslint-disable-next-line @typescript-eslint/camelcase
__experimental_clearQueryHandlers() {
clearQueryHandlers();
clearCustomQueryHandlers() {
clearCustomQueryHandlers();
}
}

@@ -16,17 +16,51 @@ /**

*/
export interface QueryHandler {
import { WaitForSelectorOptions, DOMWorld } from './DOMWorld.js';
import { ElementHandle, JSHandle } from './JSHandle.js';
/**
* @internal
*/
export interface InternalQueryHandler {
queryOne?: (element: ElementHandle, selector: string) => Promise<ElementHandle | null>;
waitFor?: (domWorld: DOMWorld, selector: string, options: WaitForSelectorOptions) => Promise<ElementHandle | null>;
queryAll?: (element: ElementHandle, selector: string) => Promise<ElementHandle[]>;
queryAllArray?: (element: ElementHandle, selector: string) => Promise<JSHandle>;
}
/**
* Contains two functions `queryOne` and `queryAll` that can
* be {@link Puppeteer.registerCustomQueryHandler | registered}
* as alternative querying strategies. The functions `queryOne` and `queryAll`
* are executed in the page context. `queryOne` should take an `Element` and a
* selector string as argument and return a single `Element` or `null` if no
* element is found. `queryAll` takes the same arguments but should instead
* return a `NodeListOf<Element>` or `Array<Element>` with all the elements
* that match the given query selector.
* @public
*/
export interface CustomQueryHandler {
queryOne?: (element: Element | Document, selector: string) => Element | null;
queryAll?: (element: Element | Document, selector: string) => Element[] | NodeListOf<Element>;
}
export declare function registerCustomQueryHandler(name: string, handler: QueryHandler): void;
/**
* @param {string} name
* @internal
*/
export declare function registerCustomQueryHandler(name: string, handler: CustomQueryHandler): void;
/**
* @internal
*/
export declare function unregisterCustomQueryHandler(name: string): void;
export declare function customQueryHandlers(): Map<string, QueryHandler>;
export declare function clearQueryHandlers(): void;
/**
* @internal
*/
export declare function customQueryHandlerNames(): string[];
/**
* @internal
*/
export declare function clearCustomQueryHandlers(): void;
/**
* @internal
*/
export declare function getQueryHandlerAndSelector(selector: string): {
updatedSelector: string;
queryHandler: QueryHandler;
queryHandler: InternalQueryHandler;
};
//# sourceMappingURL=QueryHandler.d.ts.map

@@ -16,5 +16,99 @@ /**

*/
const _customQueryHandlers = new Map();
import { ariaHandler } from './AriaQueryHandler.js';
function makeQueryHandler(handler) {
const internalHandler = {};
if (handler.queryOne) {
internalHandler.queryOne = async (element, selector) => {
const jsHandle = await element.evaluateHandle(handler.queryOne, selector);
const elementHandle = jsHandle.asElement();
if (elementHandle)
return elementHandle;
await jsHandle.dispose();
return null;
};
internalHandler.waitFor = (domWorld, selector, options) => domWorld.waitForSelectorInPage(handler.queryOne, selector, options);
}
if (handler.queryAll) {
internalHandler.queryAll = async (element, selector) => {
const jsHandle = await element.evaluateHandle(handler.queryAll, selector);
const properties = await jsHandle.getProperties();
await jsHandle.dispose();
const result = [];
for (const property of properties.values()) {
const elementHandle = property.asElement();
if (elementHandle)
result.push(elementHandle);
}
return result;
};
internalHandler.queryAllArray = async (element, selector) => {
const resultHandle = await element.evaluateHandle(handler.queryAll, selector);
const arrayHandle = await resultHandle.evaluateHandle((res) => Array.from(res));
return arrayHandle;
};
}
return internalHandler;
}
const _defaultHandler = makeQueryHandler({
queryOne: (element, selector) => element.querySelector(selector),
queryAll: (element, selector) => element.querySelectorAll(selector),
});
const pierceHandler = makeQueryHandler({
queryOne: (element, selector) => {
let found = null;
const search = (root) => {
const iter = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
do {
const currentNode = iter.currentNode;
if (currentNode.shadowRoot) {
search(currentNode.shadowRoot);
}
if (currentNode instanceof ShadowRoot) {
continue;
}
if (!found && currentNode.matches(selector)) {
found = currentNode;
}
} while (!found && iter.nextNode());
};
if (element instanceof Document) {
element = element.documentElement;
}
search(element);
return found;
},
queryAll: (element, selector) => {
const result = [];
const collect = (root) => {
const iter = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
do {
const currentNode = iter.currentNode;
if (currentNode.shadowRoot) {
collect(currentNode.shadowRoot);
}
if (currentNode instanceof ShadowRoot) {
continue;
}
if (currentNode.matches(selector)) {
result.push(currentNode);
}
} while (iter.nextNode());
};
if (element instanceof Document) {
element = element.documentElement;
}
collect(element);
return result;
},
});
const _builtInHandlers = new Map([
['aria', ariaHandler],
['pierce', pierceHandler],
]);
const _queryHandlers = new Map(_builtInHandlers);
/**
* @internal
*/
export function registerCustomQueryHandler(name, handler) {
if (_customQueryHandlers.get(name))
if (_queryHandlers.get(name))
throw new Error(`A custom query handler named "${name}" already exists`);

@@ -24,28 +118,36 @@ const isValidName = /^[a-zA-Z]+$/.test(name);

throw new Error(`Custom query handler names may only contain [a-zA-Z]`);
_customQueryHandlers.set(name, handler);
const internalHandler = makeQueryHandler(handler);
_queryHandlers.set(name, internalHandler);
}
/**
* @param {string} name
* @internal
*/
export function unregisterCustomQueryHandler(name) {
_customQueryHandlers.delete(name);
if (_queryHandlers.has(name) && !_builtInHandlers.has(name)) {
_queryHandlers.delete(name);
}
}
export function customQueryHandlers() {
return _customQueryHandlers;
/**
* @internal
*/
export function customQueryHandlerNames() {
return [..._queryHandlers.keys()].filter((name) => !_builtInHandlers.has(name));
}
export function clearQueryHandlers() {
_customQueryHandlers.clear();
/**
* @internal
*/
export function clearCustomQueryHandlers() {
customQueryHandlerNames().forEach(unregisterCustomQueryHandler);
}
/**
* @internal
*/
export function getQueryHandlerAndSelector(selector) {
const defaultHandler = {
queryOne: (element, selector) => element.querySelector(selector),
queryAll: (element, selector) => element.querySelectorAll(selector),
};
const hasCustomQueryHandler = /^[a-zA-Z]+\//.test(selector);
if (!hasCustomQueryHandler)
return { updatedSelector: selector, queryHandler: defaultHandler };
return { updatedSelector: selector, queryHandler: _defaultHandler };
const index = selector.indexOf('/');
const name = selector.slice(0, index);
const updatedSelector = selector.slice(index + 1);
const queryHandler = customQueryHandlers().get(name);
const queryHandler = _queryHandlers.get(name);
if (!queryHandler)

@@ -52,0 +154,0 @@ throw new Error(`Query set to use "${name}", but no query handler of that name was found`);

@@ -16,2 +16,3 @@ /**

*/
import { Product } from '../common/Product.js';
/**

@@ -23,9 +24,4 @@ * Supported platforms.

/**
* Supported products.
* @public
*/
export declare type Product = 'chrome' | 'firefox';
/**
* @public
*/
export interface BrowserFetcherOptions {

@@ -32,0 +28,0 @@ platform?: Platform;

@@ -22,3 +22,3 @@ /**

import { Connection } from '../common/Connection.js';
import { WebSocketTransport } from '../common/WebSocketTransport.js';
import { NodeWebSocketTransport as WebSocketTransport } from '../node/NodeWebSocketTransport.js';
import { PipeTransport } from './PipeTransport.js';

@@ -25,0 +25,0 @@ import * as readline from 'readline';

@@ -0,1 +1,2 @@

import { Product } from '../common/Product.js';
/**

@@ -7,6 +8,5 @@ * Describes a launcher - a class that is able to create and launch a browser instance.

launch(object: any): any;
connect(object: any): any;
executablePath: () => string;
defaultArgs(object: any): any;
product: string;
product: Product;
}

@@ -13,0 +13,0 @@ /**

@@ -18,12 +18,5 @@ /**

import * as path from 'path';
import * as http from 'http';
import * as https from 'https';
import * as URL from 'url';
import * as fs from 'fs';
import { BrowserFetcher } from './BrowserFetcher.js';
import { Connection } from '../common/Connection.js';
import { Browser } from '../common/Browser.js';
import { assert } from '../common/assert.js';
import { debugError } from '../common/helper.js';
import { WebSocketTransport } from '../common/WebSocketTransport.js';
import { BrowserRunner } from './BrowserRunner.js';

@@ -130,3 +123,3 @@ import { promisify } from 'util';

if (userDataDir)
chromeArguments.push(`--user-data-dir=${userDataDir}`);
chromeArguments.push(`--user-data-dir=${path.resolve(userDataDir)}`);
if (devtools)

@@ -148,24 +141,2 @@ chromeArguments.push('--auto-open-devtools-for-tabs');

}
async connect(options) {
const { browserWSEndpoint, browserURL, ignoreHTTPSErrors = false, defaultViewport = { width: 800, height: 600 }, transport, slowMo = 0, } = options;
assert(Number(!!browserWSEndpoint) +
Number(!!browserURL) +
Number(!!transport) ===
1, 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect');
let connection = null;
if (transport) {
connection = new Connection('', transport, slowMo);
}
else if (browserWSEndpoint) {
const connectionTransport = await WebSocketTransport.create(browserWSEndpoint);
connection = new Connection(browserWSEndpoint, connectionTransport, slowMo);
}
else if (browserURL) {
const connectionURL = await getWSEndpoint(browserURL);
const connectionTransport = await WebSocketTransport.create(connectionURL);
connection = new Connection(connectionURL, connectionTransport, slowMo);
}
const { browserContextIds } = await connection.send('Target.getBrowserContexts');
return Browser.create(connection, browserContextIds, ignoreHTTPSErrors, defaultViewport, null, () => connection.send('Browser.close').catch(debugError));
}
}

@@ -232,24 +203,2 @@ /**

}
async connect(options) {
const { browserWSEndpoint, browserURL, ignoreHTTPSErrors = false, defaultViewport = { width: 800, height: 600 }, transport, slowMo = 0, } = options;
assert(Number(!!browserWSEndpoint) +
Number(!!browserURL) +
Number(!!transport) ===
1, 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect');
let connection = null;
if (transport) {
connection = new Connection('', transport, slowMo);
}
else if (browserWSEndpoint) {
const connectionTransport = await WebSocketTransport.create(browserWSEndpoint);
connection = new Connection(browserWSEndpoint, connectionTransport, slowMo);
}
else if (browserURL) {
const connectionURL = await getWSEndpoint(browserURL);
const connectionTransport = await WebSocketTransport.create(connectionURL);
connection = new Connection(connectionURL, connectionTransport, slowMo);
}
const { browserContextIds } = await connection.send('Target.getBrowserContexts');
return Browser.create(connection, browserContextIds, ignoreHTTPSErrors, defaultViewport, null, () => connection.send('Browser.close').catch(debugError));
}
executablePath() {

@@ -313,3 +262,3 @@ return resolveExecutablePath(this).executablePath;

// Disable topstories
'browser.newtabpage.activity-stream.feeds.section.topstories': false,
'browser.newtabpage.activity-stream.feeds.system.topstories': false,
// Always display a blank page

@@ -355,5 +304,3 @@ 'browser.newtabpage.enabled': false,

'browser.warnOnQuit': false,
// Do not show datareporting policy notifications which can
// interfere with tests
'datareporting.healthreport.about.reportUrl': `http://${server}/dummy/abouthealthreport/`,
// Defensively disable data reporting systems
'datareporting.healthreport.documentServerURI': `http://${server}/dummy/healthreport/`,

@@ -364,4 +311,4 @@ 'datareporting.healthreport.logging.consoleEnabled': false,

'datareporting.healthreport.uploadEnabled': false,
// Do not show datareporting policy notifications which can interfere with tests
'datareporting.policy.dataSubmissionEnabled': false,
'datareporting.policy.dataSubmissionPolicyAccepted': false,
'datareporting.policy.dataSubmissionPolicyBypassNotification': true,

@@ -451,4 +398,2 @@ // DevTools JSONViewer sometimes fails to load dependencies with its require.js.

'toolkit.cosmeticAnimations.enabled': false,
// We want to collect telemetry, but we don't want to send in the results
'toolkit.telemetry.server': `https://${server}/dummy/telemetry/`,
// Prevent starting into safe mode after application crashes

@@ -465,34 +410,2 @@ 'toolkit.startup.max_resumed_crashes': -1,

}
function getWSEndpoint(browserURL) {
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
const endpointURL = URL.resolve(browserURL, '/json/version');
const protocol = endpointURL.startsWith('https') ? https : http;
const requestOptions = Object.assign(URL.parse(endpointURL), {
method: 'GET',
});
const request = protocol.request(requestOptions, (res) => {
let data = '';
if (res.statusCode !== 200) {
// Consume response data to free up memory.
res.resume();
reject(new Error('HTTP ' + res.statusCode));
return;
}
res.setEncoding('utf8');
res.on('data', (chunk) => (data += chunk));
res.on('end', () => resolve(JSON.parse(data).webSocketDebuggerUrl));
});
request.on('error', reject);
request.end();
return promise.catch((error) => {
error.message =
`Failed to fetch browser webSocket url from ${endpointURL}: ` +
error.message;
throw error;
});
}
function resolveExecutablePath(launcher) {

@@ -499,0 +412,0 @@ let downloadPath;

@@ -16,3 +16,2 @@ /**

*/
import { Viewport } from '../common/PuppeteerViewport.js';
/**

@@ -44,11 +43,2 @@ * Launcher options that only apply to Chrome.

}
/**
* Generic browser options that can be passed when launching any browser.
* @public
*/
export interface BrowserOptions {
ignoreHTTPSErrors?: boolean;
defaultViewport?: Viewport;
slowMo?: number;
}
//# sourceMappingURL=LaunchOptions.d.ts.map

@@ -17,4 +17,4 @@ /**

export const PUPPETEER_REVISIONS = {
chromium: '800071',
chromium: '809590',
firefox: 'latest',
};
{
"name": "puppeteer-core",
"version": "5.3.1",
"version": "5.4.0",
"description": "A high-level API to control headless Chrome over the DevTools Protocol",

@@ -18,3 +18,3 @@ "main": "./cjs-entry-core.js",

"funit": "PUPPETEER_PRODUCT=firefox npm run unit",
"test": "npm run tsc && npm run lint --silent && npm run unit-with-coverage && npm run test-browser && npm run test-types",
"test": "npm run tsc && npm run lint --silent && npm run unit-with-coverage && npm run test-browser",
"prepare": "node typescript-if-required.js",

@@ -25,5 +25,7 @@ "prepublishOnly": "npm run tsc",

"eslint-fix": "eslint --ext js --ext ts --fix .",
"lint": "npm run eslint && npm run tsc && npm run doc",
"commitlint": "commitlint --from=HEAD~1",
"lint": "npm run eslint && npm run tsc && npm run doc && npm run commitlint",
"doc": "node utils/doclint/cli.js",
"clean-lib": "rm -rf lib",
"build": "npm run tsc",
"tsc": "npm run clean-lib && tsc --version && npm run tsc-cjs && npm run tsc-esm",

@@ -35,5 +37,4 @@ "tsc-cjs": "tsc -b src/tsconfig.cjs.json",

"generate-docs": "npm run tsc && api-extractor run --local --verbose && api-documenter markdown -i temp -o new-docs",
"ensure-new-docs-up-to-date": "npm run generate-docs && git status && exit `git status --porcelain | head -255 | wc -l`",
"generate-dependency-graph": "echo 'Requires graphviz installed locally!' && depcruise --exclude 'api.ts' --do-not-follow '^node_modules' --output-type dot src/index.ts | dot -T png > dependency-chart.png",
"ensure-correct-devtools-protocol-revision": "ts-node scripts/ensure-correct-devtools-protocol-package"
"ensure-correct-devtools-protocol-revision": "ts-node -s scripts/ensure-correct-devtools-protocol-package"
},

@@ -51,5 +52,6 @@ "files": [

"debug": "^4.1.0",
"devtools-protocol": "0.0.799653",
"devtools-protocol": "0.0.809251",
"extract-zip": "^2.0.0",
"https-proxy-agent": "^4.0.0",
"node-fetch": "^2.6.1",
"pkg-dir": "^4.2.0",

@@ -64,4 +66,6 @@ "progress": "^2.0.1",

"devDependencies": {
"@microsoft/api-documenter": "7.8.14",
"@microsoft/api-extractor": "7.8.12",
"@commitlint/cli": "^11.0.0",
"@commitlint/config-conventional": "^11.0.0",
"@microsoft/api-documenter": "7.9.7",
"@microsoft/api-extractor": "7.10.4",
"@types/debug": "0.0.31",

@@ -76,36 +80,35 @@ "@types/mime": "^2.0.0",

"@types/ws": "^7.2.4",
"@typescript-eslint/eslint-plugin": "^2.28.0",
"@typescript-eslint/parser": "^2.28.0",
"@web/test-runner": "^0.6.40",
"@typescript-eslint/eslint-plugin": "^4.4.0",
"@typescript-eslint/parser": "^4.4.0",
"@web/test-runner": "^0.9.2",
"commonmark": "^0.28.1",
"cross-env": "^5.0.5",
"cross-env": "^7.0.2",
"dependency-cruiser": "^9.7.0",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.11.0",
"eslint": "^7.10.0",
"eslint-config-prettier": "^6.12.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-mocha": "^6.3.0",
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-unicorn": "^19.0.1",
"eslint-plugin-mocha": "^8.0.0",
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-unicorn": "^22.0.0",
"esprima": "^4.0.0",
"expect": "^25.2.7",
"husky": "^4.3.0",
"jpeg-js": "^0.3.7",
"mime": "^2.0.3",
"minimist": "^1.2.0",
"mocha": "^8.0.1",
"mocha": "^8.2.0",
"ncp": "^2.0.0",
"pixelmatch": "^4.0.2",
"pngjs": "^5.0.0",
"prettier": "^2.0.5",
"prettier": "^2.1.2",
"sinon": "^9.0.2",
"text-diff": "^1.0.1",
"ts-node": "^8.10.2",
"ts-node": "^9.0.0",
"typescript": "3.9.5"
},
"browser": {
"./lib/BrowserFetcher.js": false,
"ws": "./utils/browser/WebSocket",
"fs": false,
"child_process": false,
"rimraf": false,
"readline": false
"husky": {
"hooks": {
"commit-msg": "commitlint --env HUSKY_GIT_PARAMS"
}
}
}

@@ -9,3 +9,3 @@ # Puppeteer

###### [API](https://github.com/puppeteer/puppeteer/blob/v5.3.1/docs/api.md) | [FAQ](#faq) | [Contributing](https://github.com/puppeteer/puppeteer/blob/main/CONTRIBUTING.md) | [Troubleshooting](https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md)
###### [API](https://github.com/puppeteer/puppeteer/blob/v5.4.0/docs/api.md) | [FAQ](#faq) | [Contributing](https://github.com/puppeteer/puppeteer/blob/main/CONTRIBUTING.md) | [Troubleshooting](https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md)

@@ -41,3 +41,3 @@ > Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the [DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/). Puppeteer runs [headless](https://developers.google.com/web/updates/2017/04/headless-chrome) by default, but can be configured to run full (non-headless) Chrome or Chromium.

Note: When you install Puppeteer, it downloads a recent version of Chromium (~170MB Mac, ~282MB Linux, ~280MB Win) that is guaranteed to work with the API. To skip the download, or to download a different browser, see [Environment variables](https://github.com/puppeteer/puppeteer/blob/v5.3.1/docs/api.md#environment-variables).
Note: When you install Puppeteer, it downloads a recent version of Chromium (~170MB Mac, ~282MB Linux, ~280MB Win) that is guaranteed to work with the API. To skip the download, or to download a different browser, see [Environment variables](https://github.com/puppeteer/puppeteer/blob/v5.4.0/docs/api.md#environment-variables).

@@ -68,3 +68,3 @@

Puppeteer will be familiar to people using other browser testing frameworks. You create an instance
of `Browser`, open pages, and then manipulate them with [Puppeteer's API](https://github.com/puppeteer/puppeteer/blob/v5.3.1/docs/api.md#).
of `Browser`, open pages, and then manipulate them with [Puppeteer's API](https://github.com/puppeteer/puppeteer/blob/v5.4.0/docs/api.md#).

@@ -94,3 +94,3 @@ **Example** - navigating to https://example.com and saving a screenshot as *example.png*:

Puppeteer sets an initial page size to 800×600px, which defines the screenshot size. The page size can be customized with [`Page.setViewport()`](https://github.com/puppeteer/puppeteer/blob/v5.3.1/docs/api.md#pagesetviewportviewport).
Puppeteer sets an initial page size to 800×600px, which defines the screenshot size. The page size can be customized with [`Page.setViewport()`](https://github.com/puppeteer/puppeteer/blob/v5.4.0/docs/api.md#pagesetviewportviewport).

@@ -120,3 +120,3 @@ **Example** - create a PDF.

See [`Page.pdf()`](https://github.com/puppeteer/puppeteer/blob/v5.3.1/docs/api.md#pagepdfoptions) for more information about creating pdfs.
See [`Page.pdf()`](https://github.com/puppeteer/puppeteer/blob/v5.4.0/docs/api.md#pagepdfoptions) for more information about creating pdfs.

@@ -156,3 +156,3 @@ **Example** - evaluate script in the context of the page

See [`Page.evaluate()`](https://github.com/puppeteer/puppeteer/blob/v5.3.1/docs/api.md#pageevaluatepagefunction-args) for more information on `evaluate` and related methods like `evaluateOnNewDocument` and `exposeFunction`.
See [`Page.evaluate()`](https://github.com/puppeteer/puppeteer/blob/v5.4.0/docs/api.md#pageevaluatepagefunction-args) for more information on `evaluate` and related methods like `evaluateOnNewDocument` and `exposeFunction`.

@@ -166,3 +166,3 @@ <!-- [END getstarted] -->

Puppeteer launches Chromium in [headless mode](https://developers.google.com/web/updates/2017/04/headless-chrome). To launch a full version of Chromium, set the [`headless` option](https://github.com/puppeteer/puppeteer/blob/v5.3.1/docs/api.md#puppeteerlaunchoptions) when launching a browser:
Puppeteer launches Chromium in [headless mode](https://developers.google.com/web/updates/2017/04/headless-chrome). To launch a full version of Chromium, set the [`headless` option](https://github.com/puppeteer/puppeteer/blob/v5.4.0/docs/api.md#puppeteerlaunchoptions) when launching a browser:

@@ -183,3 +183,3 @@ ```js

You can also use Puppeteer with Firefox Nightly (experimental support). See [`Puppeteer.launch()`](https://github.com/puppeteer/puppeteer/blob/v5.3.1/docs/api.md#puppeteerlaunchoptions) for more information.
You can also use Puppeteer with Firefox Nightly (experimental support). See [`Puppeteer.launch()`](https://github.com/puppeteer/puppeteer/blob/v5.4.0/docs/api.md#puppeteerlaunchoptions) for more information.

@@ -196,3 +196,3 @@ See [`this article`](https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/) for a description of the differences between Chromium and Chrome. [`This article`](https://chromium.googlesource.com/chromium/src/+/master/docs/chromium_browser_vs_google_chrome.md) describes some differences for Linux users.

- [API Documentation](https://github.com/puppeteer/puppeteer/blob/v5.3.1/docs/api.md)
- [API Documentation](https://github.com/puppeteer/puppeteer/blob/v5.4.0/docs/api.md)
- [Examples](https://github.com/puppeteer/puppeteer/tree/main/examples/)

@@ -340,3 +340,3 @@ - [Community list of Puppeteer resources](https://github.com/transitive-bullshit/awesome-puppeteer)

From Puppeteer v2.1.0 onwards you can specify [`puppeteer.launch({product: 'firefox'})`](https://github.com/puppeteer/puppeteer/blob/v5.3.1/docs/api.md#puppeteerlaunchoptions) to run your Puppeteer scripts in Firefox Nightly, without any additional custom patches. While [an older experiment](https://www.npmjs.com/package/puppeteer-firefox) required a patched version of Firefox, [the current approach](https://wiki.mozilla.org/Remote) works with “stock” Firefox.
From Puppeteer v2.1.0 onwards you can specify [`puppeteer.launch({product: 'firefox'})`](https://github.com/puppeteer/puppeteer/blob/v5.4.0/docs/api.md#puppeteerlaunchoptions) to run your Puppeteer scripts in Firefox Nightly, without any additional custom patches. While [an older experiment](https://www.npmjs.com/package/puppeteer-firefox) required a patched version of Firefox, [the current approach](https://wiki.mozilla.org/Remote) works with “stock” Firefox.

@@ -437,3 +437,3 @@ We will continue to collaborate with other browser vendors to bring Puppeteer support to browsers such as Safari.

* Puppeteer is bundled with Chromium — not Chrome — and so by default, it inherits all of [Chromium's media-related limitations](https://www.chromium.org/audio-video). This means that Puppeteer does not support licensed formats such as AAC or H.264. (However, it is possible to force Puppeteer to use a separately-installed version Chrome instead of Chromium via the [`executablePath` option to `puppeteer.launch`](https://github.com/puppeteer/puppeteer/blob/v5.3.1/docs/api.md#puppeteerlaunchoptions). You should only use this configuration if you need an official release of Chrome that supports these media formats.)
* Puppeteer is bundled with Chromium — not Chrome — and so by default, it inherits all of [Chromium's media-related limitations](https://www.chromium.org/audio-video). This means that Puppeteer does not support licensed formats such as AAC or H.264. (However, it is possible to force Puppeteer to use a separately-installed version Chrome instead of Chromium via the [`executablePath` option to `puppeteer.launch`](https://github.com/puppeteer/puppeteer/blob/v5.4.0/docs/api.md#puppeteerlaunchoptions). You should only use this configuration if you need an official release of Chrome that supports these media formats.)
* Since Puppeteer (in all configurations) controls a desktop version of Chromium/Chrome, features that are only supported by the mobile version of Chrome are not supported. This means that Puppeteer [does not support HTTP Live Streaming (HLS)](https://caniuse.com/#feat=http-live-streaming).

@@ -440,0 +440,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc