fix: prevent asset conflicts between React and Grid.js versions

Add coexistence checks to all enqueue methods to prevent loading
both React and Grid.js assets simultaneously.

Changes:
- ReactAdmin.php: Only enqueue React assets when ?react=1
- Init.php: Skip Grid.js when React active on admin pages
- Form.php, Coupon.php, Access.php: Restore classic assets when ?react=0
- Customer.php, Product.php, License.php: Add coexistence checks

Now the toggle between Classic and React versions works correctly.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
dwindown
2026-04-18 17:02:14 +07:00
parent bd9cdac02e
commit e8fbfb14c1
74973 changed files with 6658406 additions and 71 deletions

View File

@@ -0,0 +1,111 @@
/**
* 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.
*/
import { LaunchOptions, BrowserLaunchArgumentOptions } from './node/LaunchOptions.js';
import { BrowserConnectOptions } from './common/BrowserConnector.js';
import { Product } from './common/Product.js';
import { Browser } from './common/Browser.js';
import { ConnectOptions } from './common/Puppeteer.js';
import { DevicesMap } from './common/DeviceDescriptors.js';
import { PuppeteerErrors } from './common/Errors.js';
import { PredefinedNetworkConditions } from './common/NetworkConditions.js';
import { CustomQueryHandler } from './common/QueryHandler.js';
export * from './common/Accessibility.js';
export * from './common/Browser.js';
export * from './node/BrowserFetcher.js';
export * from './node/Puppeteer.js';
export * from './common/Coverage.js';
export * from './common/Connection.js';
export * from './common/ConsoleMessage.js';
export * from './common/Coverage.js';
export * from './common/DeviceDescriptors.js';
export * from './common/Dialog.js';
export * from './common/DOMWorld.js';
export * from './common/JSHandle.js';
export * from './common/ExecutionContext.js';
export * from './common/EventEmitter.js';
export * from './common/FileChooser.js';
export * from './common/FrameManager.js';
export * from './common/PuppeteerViewport.js';
export * from './common/Input.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 './common/HTTPRequest.js';
export * from './common/HTTPResponse.js';
export * from './common/SecurityDetails.js';
export * from './common/Target.js';
export * from './common/Errors.js';
export * from './common/Tracing.js';
export * from './common/NetworkManager.js';
export * from './common/WebWorker.js';
export * from './common/USKeyboardLayout.js';
export * from './common/EvalTypes.js';
export * from './common/PDFOptions.js';
export * from './common/TimeoutSettings.js';
export * from './common/LifecycleWatcher.js';
export * from './common/QueryHandler.js';
export * from './common/NetworkConditions.js';
export * from 'devtools-protocol/types/protocol';
/**
* @public
* {@inheritDoc PuppeteerNode.launch}
*/
export declare function launch(options?: LaunchOptions & BrowserLaunchArgumentOptions & BrowserConnectOptions & {
product?: Product;
extraPrefsFirefox?: Record<string, unknown>;
}): Promise<Browser>;
/**
* @public
* {@inheritDoc PuppeteerNode.connect}
*/
export declare function connect(options: ConnectOptions): Promise<Browser>;
/**
* @public
* {@inheritDoc Puppeteer.devices}
*/
export declare let devices: DevicesMap;
/**
* @public
*/
export declare let errors: PuppeteerErrors;
/**
* @public
*/
export declare let networkConditions: PredefinedNetworkConditions;
/**
* @public
* {@inheritDoc Puppeteer.registerCustomQueryHandler}
*/
export declare function registerCustomQueryHandler(name: string, queryHandler: CustomQueryHandler): void;
/**
* @public
* {@inheritDoc Puppeteer.unregisterCustomQueryHandler}
*/
export declare function unregisterCustomQueryHandler(name: string): void;
/**
* @public
* {@inheritDoc Puppeteer.customQueryHandlerNames}
*/
export declare function customQueryHandlerNames(): string[];
/**
* @public
* {@inheritDoc Puppeteer.clearCustomQueryHandlers}
*/
export declare function clearCustomQueryHandlers(): void;
//# sourceMappingURL=api-docs-entry.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"api-docs-entry.d.ts","sourceRoot":"","sources":["../../../src/api-docs-entry.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,85 @@
"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.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.networkConditions = exports.errors = exports.devices = void 0;
/*
* This file re-exports any APIs that we want to have documentation generated
* for. It is used by API Extractor to determine what parts of the system to
* document.
*
* 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.
*
* Once we have migrated to API Extractor and removed DocLint we can remove the
* duplication and use this file.
*/
__exportStar(require("./common/Accessibility.js"), exports);
__exportStar(require("./common/Browser.js"), exports);
__exportStar(require("./node/BrowserFetcher.js"), exports);
__exportStar(require("./node/Puppeteer.js"), exports);
__exportStar(require("./common/Coverage.js"), exports);
__exportStar(require("./common/Connection.js"), exports);
__exportStar(require("./common/ConsoleMessage.js"), exports);
__exportStar(require("./common/Coverage.js"), exports);
__exportStar(require("./common/DeviceDescriptors.js"), exports);
__exportStar(require("./common/Dialog.js"), exports);
__exportStar(require("./common/DOMWorld.js"), exports);
__exportStar(require("./common/JSHandle.js"), exports);
__exportStar(require("./common/ExecutionContext.js"), exports);
__exportStar(require("./common/EventEmitter.js"), exports);
__exportStar(require("./common/FileChooser.js"), exports);
__exportStar(require("./common/FrameManager.js"), exports);
__exportStar(require("./common/PuppeteerViewport.js"), exports);
__exportStar(require("./common/Input.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("./common/HTTPRequest.js"), exports);
__exportStar(require("./common/HTTPResponse.js"), exports);
__exportStar(require("./common/SecurityDetails.js"), exports);
__exportStar(require("./common/Target.js"), exports);
__exportStar(require("./common/Errors.js"), exports);
__exportStar(require("./common/Tracing.js"), exports);
__exportStar(require("./common/NetworkManager.js"), exports);
__exportStar(require("./common/WebWorker.js"), exports);
__exportStar(require("./common/USKeyboardLayout.js"), exports);
__exportStar(require("./common/EvalTypes.js"), exports);
__exportStar(require("./common/PDFOptions.js"), exports);
__exportStar(require("./common/TimeoutSettings.js"), exports);
__exportStar(require("./common/LifecycleWatcher.js"), exports);
__exportStar(require("./common/QueryHandler.js"), exports);
__exportStar(require("./common/NetworkConditions.js"), exports);
__exportStar(require("devtools-protocol/types/protocol"), exports);
//# sourceMappingURL=api-docs-entry.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"api-docs-entry.js","sourceRoot":"","sources":["../../../src/api-docs-entry.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;;;;;;;;;;;;;;;AAeH;;;;;;;;;;;GAWG;AACH,4DAA0C;AAC1C,sDAAoC;AACpC,2DAAyC;AACzC,sDAAoC;AACpC,uDAAqC;AACrC,yDAAuC;AACvC,6DAA2C;AAC3C,uDAAqC;AACrC,gEAA8C;AAC9C,qDAAmC;AACnC,uDAAqC;AACrC,uDAAqC;AACrC,+DAA6C;AAC7C,2DAAyC;AACzC,0DAAwC;AACxC,2DAAyC;AACzC,gEAA8C;AAC9C,oDAAkC;AAClC,mDAAiC;AACjC,sDAAoC;AACpC,wDAAsC;AACtC,+DAA6C;AAC7C,qDAAmC;AACnC,0DAAwC;AACxC,0DAAwC;AACxC,2DAAyC;AACzC,8DAA4C;AAC5C,qDAAmC;AACnC,qDAAmC;AACnC,sDAAoC;AACpC,6DAA2C;AAC3C,wDAAsC;AACtC,+DAA6C;AAC7C,wDAAsC;AACtC,yDAAuC;AACvC,8DAA4C;AAC5C,+DAA6C;AAC7C,2DAAyC;AACzC,gEAA8C;AAC9C,mEAAiD"}

View File

@@ -0,0 +1,176 @@
/**
* Copyright 2018 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 { CDPSession } from './Connection.js';
import { ElementHandle } from './JSHandle.js';
/**
* Represents a Node and the properties of it that are relevant to Accessibility.
* @public
*/
export interface SerializedAXNode {
/**
* The {@link https://www.w3.org/TR/wai-aria/#usage_intro | role} of the node.
*/
role: string;
/**
* A human readable name for the node.
*/
name?: string;
/**
* The current value of the node.
*/
value?: string | number;
/**
* An additional human readable description of the node.
*/
description?: string;
/**
* Any keyboard shortcuts associated with this node.
*/
keyshortcuts?: string;
/**
* A human readable alternative to the role.
*/
roledescription?: string;
/**
* A description of the current value.
*/
valuetext?: string;
disabled?: boolean;
expanded?: boolean;
focused?: boolean;
modal?: boolean;
multiline?: boolean;
/**
* Whether more than one child can be selected.
*/
multiselectable?: boolean;
readonly?: boolean;
required?: boolean;
selected?: boolean;
/**
* Whether the checkbox is checked, or in a
* {@link https://www.w3.org/TR/wai-aria-practices/examples/checkbox/checkbox-2/checkbox-2.html | mixed state}.
*/
checked?: boolean | 'mixed';
/**
* Whether the node is checked or in a mixed state.
*/
pressed?: boolean | 'mixed';
/**
* The level of a heading.
*/
level?: number;
valuemin?: number;
valuemax?: number;
autocomplete?: string;
haspopup?: string;
/**
* Whether and in what way this node's value is invalid.
*/
invalid?: string;
orientation?: string;
/**
* Children of this node, if there are any.
*/
children?: SerializedAXNode[];
}
/**
* @public
*/
export interface SnapshotOptions {
/**
* Prune uninteresting nodes from the tree.
* @defaultValue true
*/
interestingOnly?: boolean;
/**
* Root node to get the accessibility tree for
* @defaultValue The root node of the entire page.
*/
root?: ElementHandle;
}
/**
* The Accessibility class provides methods for inspecting Chromium's
* accessibility tree. The accessibility tree is used by assistive technology
* such as {@link https://en.wikipedia.org/wiki/Screen_reader | screen readers} or
* {@link https://en.wikipedia.org/wiki/Switch_access | switches}.
*
* @remarks
*
* Accessibility is a very platform-specific thing. On different platforms,
* there are different screen readers that might have wildly different output.
*
* Blink - Chrome's rendering engine - has a concept of "accessibility tree",
* which is then translated into different platform-specific APIs. Accessibility
* namespace gives users access to the Blink Accessibility Tree.
*
* Most of the accessibility tree gets filtered out when converting from Blink
* AX Tree to Platform-specific AX-Tree or by assistive technologies themselves.
* By default, Puppeteer tries to approximate this filtering, exposing only
* the "interesting" nodes of the tree.
*
* @public
*/
export declare class Accessibility {
private _client;
/**
* @internal
*/
constructor(client: CDPSession);
/**
* Captures the current state of the accessibility tree.
* The returned object represents the root accessible node of the page.
*
* @remarks
*
* **NOTE** The Chromium accessibility tree contains nodes that go unused on
* most platforms and by most screen readers. Puppeteer will discard them as
* well for an easier to process tree, unless `interestingOnly` is set to
* `false`.
*
* @example
* An example of dumping the entire accessibility tree:
* ```js
* const snapshot = await page.accessibility.snapshot();
* console.log(snapshot);
* ```
*
* @example
* An example of logging the focused node's name:
* ```js
* const snapshot = await page.accessibility.snapshot();
* const node = findFocusedNode(snapshot);
* console.log(node && node.name);
*
* function findFocusedNode(node) {
* if (node.focused)
* return node;
* for (const child of node.children || []) {
* const foundNode = findFocusedNode(child);
* return foundNode;
* }
* return null;
* }
* ```
*
* @returns An AXNode object representing the snapshot.
*
*/
snapshot(options?: SnapshotOptions): Promise<SerializedAXNode>;
private serializeTree;
private collectInterestingNodes;
}
//# sourceMappingURL=Accessibility.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Accessibility.d.ts","sourceRoot":"","sources":["../../../../src/common/Accessibility.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9C;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IAC5B;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IAC5B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAa;IAE5B;;OAEG;gBACS,MAAM,EAAE,UAAU;IAI9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAsCG;IACU,QAAQ,CACnB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,gBAAgB,CAAC;IA0B5B,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,uBAAuB;CAWhC"}

View File

@@ -0,0 +1,361 @@
"use strict";
/**
* Copyright 2018 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 });
exports.Accessibility = void 0;
/**
* The Accessibility class provides methods for inspecting Chromium's
* accessibility tree. The accessibility tree is used by assistive technology
* such as {@link https://en.wikipedia.org/wiki/Screen_reader | screen readers} or
* {@link https://en.wikipedia.org/wiki/Switch_access | switches}.
*
* @remarks
*
* Accessibility is a very platform-specific thing. On different platforms,
* there are different screen readers that might have wildly different output.
*
* Blink - Chrome's rendering engine - has a concept of "accessibility tree",
* which is then translated into different platform-specific APIs. Accessibility
* namespace gives users access to the Blink Accessibility Tree.
*
* Most of the accessibility tree gets filtered out when converting from Blink
* AX Tree to Platform-specific AX-Tree or by assistive technologies themselves.
* By default, Puppeteer tries to approximate this filtering, exposing only
* the "interesting" nodes of the tree.
*
* @public
*/
class Accessibility {
/**
* @internal
*/
constructor(client) {
this._client = client;
}
/**
* Captures the current state of the accessibility tree.
* The returned object represents the root accessible node of the page.
*
* @remarks
*
* **NOTE** The Chromium accessibility tree contains nodes that go unused on
* most platforms and by most screen readers. Puppeteer will discard them as
* well for an easier to process tree, unless `interestingOnly` is set to
* `false`.
*
* @example
* An example of dumping the entire accessibility tree:
* ```js
* const snapshot = await page.accessibility.snapshot();
* console.log(snapshot);
* ```
*
* @example
* An example of logging the focused node's name:
* ```js
* const snapshot = await page.accessibility.snapshot();
* const node = findFocusedNode(snapshot);
* console.log(node && node.name);
*
* function findFocusedNode(node) {
* if (node.focused)
* return node;
* for (const child of node.children || []) {
* const foundNode = findFocusedNode(child);
* return foundNode;
* }
* return null;
* }
* ```
*
* @returns An AXNode object representing the snapshot.
*
*/
async snapshot(options = {}) {
const { interestingOnly = true, root = null } = options;
const { nodes } = await this._client.send('Accessibility.getFullAXTree');
let backendNodeId = null;
if (root) {
const { node } = await this._client.send('DOM.describeNode', {
objectId: root._remoteObject.objectId,
});
backendNodeId = node.backendNodeId;
}
const defaultRoot = AXNode.createTree(nodes);
let needle = defaultRoot;
if (backendNodeId) {
needle = defaultRoot.find((node) => node.payload.backendDOMNodeId === backendNodeId);
if (!needle)
return null;
}
if (!interestingOnly)
return this.serializeTree(needle)[0];
const interestingNodes = new Set();
this.collectInterestingNodes(interestingNodes, defaultRoot, false);
if (!interestingNodes.has(needle))
return null;
return this.serializeTree(needle, interestingNodes)[0];
}
serializeTree(node, interestingNodes) {
const children = [];
for (const child of node.children)
children.push(...this.serializeTree(child, interestingNodes));
if (interestingNodes && !interestingNodes.has(node))
return children;
const serializedNode = node.serialize();
if (children.length)
serializedNode.children = children;
return [serializedNode];
}
collectInterestingNodes(collection, node, insideControl) {
if (node.isInteresting(insideControl))
collection.add(node);
if (node.isLeafNode())
return;
insideControl = insideControl || node.isControl();
for (const child of node.children)
this.collectInterestingNodes(collection, child, insideControl);
}
}
exports.Accessibility = Accessibility;
class AXNode {
constructor(payload) {
this.children = [];
this._richlyEditable = false;
this._editable = false;
this._focusable = false;
this._hidden = false;
this.payload = payload;
this._name = this.payload.name ? this.payload.name.value : '';
this._role = this.payload.role ? this.payload.role.value : 'Unknown';
this._ignored = this.payload.ignored;
for (const property of this.payload.properties || []) {
if (property.name === 'editable') {
this._richlyEditable = property.value.value === 'richtext';
this._editable = true;
}
if (property.name === 'focusable')
this._focusable = property.value.value;
if (property.name === 'hidden')
this._hidden = property.value.value;
}
}
_isPlainTextField() {
if (this._richlyEditable)
return false;
if (this._editable)
return true;
return this._role === 'textbox' || this._role === 'searchbox';
}
_isTextOnlyObject() {
const role = this._role;
return role === 'LineBreak' || role === 'text' || role === 'InlineTextBox';
}
_hasFocusableChild() {
if (this._cachedHasFocusableChild === undefined) {
this._cachedHasFocusableChild = false;
for (const child of this.children) {
if (child._focusable || child._hasFocusableChild()) {
this._cachedHasFocusableChild = true;
break;
}
}
}
return this._cachedHasFocusableChild;
}
find(predicate) {
if (predicate(this))
return this;
for (const child of this.children) {
const result = child.find(predicate);
if (result)
return result;
}
return null;
}
isLeafNode() {
if (!this.children.length)
return true;
// These types of objects may have children that we use as internal
// implementation details, but we want to expose them as leaves to platform
// accessibility APIs because screen readers might be confused if they find
// any children.
if (this._isPlainTextField() || this._isTextOnlyObject())
return true;
// Roles whose children are only presentational according to the ARIA and
// HTML5 Specs should be hidden from screen readers.
// (Note that whilst ARIA buttons can have only presentational children, HTML5
// buttons are allowed to have content.)
switch (this._role) {
case 'doc-cover':
case 'graphics-symbol':
case 'img':
case 'Meter':
case 'scrollbar':
case 'slider':
case 'separator':
case 'progressbar':
return true;
default:
break;
}
// Here and below: Android heuristics
if (this._hasFocusableChild())
return false;
if (this._focusable && this._name)
return true;
if (this._role === 'heading' && this._name)
return true;
return false;
}
isControl() {
switch (this._role) {
case 'button':
case 'checkbox':
case 'ColorWell':
case 'combobox':
case 'DisclosureTriangle':
case 'listbox':
case 'menu':
case 'menubar':
case 'menuitem':
case 'menuitemcheckbox':
case 'menuitemradio':
case 'radio':
case 'scrollbar':
case 'searchbox':
case 'slider':
case 'spinbutton':
case 'switch':
case 'tab':
case 'textbox':
case 'tree':
case 'treeitem':
return true;
default:
return false;
}
}
isInteresting(insideControl) {
const role = this._role;
if (role === 'Ignored' || this._hidden || this._ignored)
return false;
if (this._focusable || this._richlyEditable)
return true;
// If it's not focusable but has a control role, then it's interesting.
if (this.isControl())
return true;
// A non focusable child of a control is not interesting
if (insideControl)
return false;
return this.isLeafNode() && !!this._name;
}
serialize() {
const properties = new Map();
for (const property of this.payload.properties || [])
properties.set(property.name.toLowerCase(), property.value.value);
if (this.payload.name)
properties.set('name', this.payload.name.value);
if (this.payload.value)
properties.set('value', this.payload.value.value);
if (this.payload.description)
properties.set('description', this.payload.description.value);
const node = {
role: this._role,
};
const userStringProperties = [
'name',
'value',
'description',
'keyshortcuts',
'roledescription',
'valuetext',
];
const getUserStringPropertyValue = (key) => properties.get(key);
for (const userStringProperty of userStringProperties) {
if (!properties.has(userStringProperty))
continue;
node[userStringProperty] = getUserStringPropertyValue(userStringProperty);
}
const booleanProperties = [
'disabled',
'expanded',
'focused',
'modal',
'multiline',
'multiselectable',
'readonly',
'required',
'selected',
];
const getBooleanPropertyValue = (key) => properties.get(key);
for (const booleanProperty of booleanProperties) {
// RootWebArea's treat focus differently than other nodes. They report whether
// their frame has focus, not whether focus is specifically on the root
// node.
if (booleanProperty === 'focused' && this._role === 'RootWebArea')
continue;
const value = getBooleanPropertyValue(booleanProperty);
if (!value)
continue;
node[booleanProperty] = getBooleanPropertyValue(booleanProperty);
}
const tristateProperties = ['checked', 'pressed'];
for (const tristateProperty of tristateProperties) {
if (!properties.has(tristateProperty))
continue;
const value = properties.get(tristateProperty);
node[tristateProperty] =
value === 'mixed' ? 'mixed' : value === 'true' ? true : false;
}
const numericalProperties = [
'level',
'valuemax',
'valuemin',
];
const getNumericalPropertyValue = (key) => properties.get(key);
for (const numericalProperty of numericalProperties) {
if (!properties.has(numericalProperty))
continue;
node[numericalProperty] = getNumericalPropertyValue(numericalProperty);
}
const tokenProperties = [
'autocomplete',
'haspopup',
'invalid',
'orientation',
];
const getTokenPropertyValue = (key) => properties.get(key);
for (const tokenProperty of tokenProperties) {
const value = getTokenPropertyValue(tokenProperty);
if (!value || value === 'false')
continue;
node[tokenProperty] = getTokenPropertyValue(tokenProperty);
}
return node;
}
static createTree(payloads) {
const nodeById = new Map();
for (const payload of payloads)
nodeById.set(payload.nodeId, new AXNode(payload));
for (const node of nodeById.values()) {
for (const childId of node.payload.childIds || [])
node.children.push(nodeById.get(childId));
}
return nodeById.values().next().value;
}
}
//# sourceMappingURL=Accessibility.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,21 @@
/**
* 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.
*/
import { InternalQueryHandler } from './QueryHandler.js';
/**
* @internal
*/
export declare const ariaHandler: InternalQueryHandler;
//# sourceMappingURL=AriaQueryHandler.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"AriaQueryHandler.d.ts","sourceRoot":"","sources":["../../../../src/common/AriaQueryHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAoHzD;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,oBAKzB,CAAC"}

View File

@@ -0,0 +1,85 @@
"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 });
exports.ariaHandler = void 0;
async function queryAXTree(client, element, accessibleName, role) {
const { nodes } = await client.send('Accessibility.queryAXTree', {
objectId: element._remoteObject.objectId,
accessibleName,
role,
});
const filteredNodes = nodes.filter((node) => node.role.value !== 'StaticText');
return filteredNodes;
}
const normalizeValue = (value) => value.replace(/ +/g, ' ').trim();
const knownAttributes = new Set(['name', 'role']);
const attributeRegexp = /\[\s*(?<attribute>\w+)\s*=\s*(?<quote>"|')(?<value>\\.|.*?(?=\k<quote>))\k<quote>\s*\]/g;
function parseAriaSelector(selector) {
const queryOptions = {};
const defaultName = selector.replace(attributeRegexp, (_, attribute, quote, value) => {
attribute = attribute.trim();
if (!knownAttributes.has(attribute))
throw new Error(`Unknown aria attribute "${attribute}" in selector`);
queryOptions[attribute] = normalizeValue(value);
return '';
});
if (defaultName && !queryOptions.name)
queryOptions.name = normalizeValue(defaultName);
return queryOptions;
}
const queryOne = async (element, selector) => {
const exeCtx = element.executionContext();
const { name, role } = parseAriaSelector(selector);
const res = await queryAXTree(exeCtx._client, element, name, role);
if (res.length < 1) {
return null;
}
return exeCtx._adoptBackendNodeId(res[0].backendDOMNodeId);
};
const waitFor = async (domWorld, selector, options) => {
const binding = {
name: 'ariaQuerySelector',
pptrFunction: async (selector) => {
const root = options.root || (await domWorld._document());
const element = await queryOne(root, selector);
return element;
},
};
return domWorld.waitForSelectorInPage((_, selector) => globalThis.ariaQuerySelector(selector), selector, options, binding);
};
const queryAll = async (element, selector) => {
const exeCtx = element.executionContext();
const { name, role } = parseAriaSelector(selector);
const res = await queryAXTree(exeCtx._client, element, name, role);
return Promise.all(res.map((axNode) => exeCtx._adoptBackendNodeId(axNode.backendDOMNodeId)));
};
const queryAllArray = async (element, selector) => {
const elementHandles = await queryAll(element, selector);
const exeCtx = element.executionContext();
const jsHandle = exeCtx.evaluateHandle((...elements) => elements, ...elementHandles);
return jsHandle;
};
/**
* @internal
*/
exports.ariaHandler = {
queryOne,
waitFor,
queryAll,
queryAllArray,
};
//# sourceMappingURL=AriaQueryHandler.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"AriaQueryHandler.js","sourceRoot":"","sources":["../../../../src/common/AriaQueryHandler.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,456 @@
/**
* 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.
*/
/// <reference types="node" />
import { Target } from './Target.js';
import { EventEmitter } from './EventEmitter.js';
import { Connection } from './Connection.js';
import { Protocol } from 'devtools-protocol';
import { Page } from './Page.js';
import { ChildProcess } from 'child_process';
import { Viewport } from './PuppeteerViewport.js';
/**
* BrowserContext options.
*
* @public
*/
export interface BrowserContextOptions {
/**
* Proxy server with optional port to use for all requests.
* Username and password can be set in `Page.authenticate`.
*/
proxyServer?: string;
/**
* Bypass the proxy for the given semi-colon-separated list of hosts.
*/
proxyBypassList?: string[];
}
/**
* @internal
*/
export declare type BrowserCloseCallback = () => Promise<void> | void;
/**
* @public
*/
export declare type TargetFilterCallback = (target: Protocol.Target.TargetInfo) => boolean;
/**
* @public
*/
export declare type Permission = 'geolocation' | 'midi' | 'notifications' | 'camera' | 'microphone' | 'background-sync' | 'ambient-light-sensor' | 'accelerometer' | 'gyroscope' | 'magnetometer' | 'accessibility-events' | 'clipboard-read' | 'clipboard-write' | 'payment-handler' | 'persistent-storage' | 'idle-detection' | 'midi-sysex';
/**
* @public
*/
export interface WaitForTargetOptions {
/**
* Maximum wait time in milliseconds. Pass `0` to disable the timeout.
* @defaultValue 30 seconds.
*/
timeout?: number;
}
/**
* All the events a {@link Browser | browser instance} may emit.
*
* @public
*/
export declare const enum BrowserEmittedEvents {
/**
* Emitted when Puppeteer gets disconnected from the Chromium instance. This
* might happen because of one of the following:
*
* - Chromium is closed or crashed
*
* - The {@link Browser.disconnect | browser.disconnect } method was called.
*/
Disconnected = "disconnected",
/**
* Emitted when the url of a target changes. Contains a {@link Target} instance.
*
* @remarks
*
* Note that this includes target changes in incognito browser contexts.
*/
TargetChanged = "targetchanged",
/**
* Emitted when a target is created, for example when a new page is opened by
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Window/open | window.open}
* or by {@link Browser.newPage | browser.newPage}
*
* Contains a {@link Target} instance.
*
* @remarks
*
* Note that this includes target creations in incognito browser contexts.
*/
TargetCreated = "targetcreated",
/**
* Emitted when a target is destroyed, for example when a page is closed.
* Contains a {@link Target} instance.
*
* @remarks
*
* Note that this includes target destructions in incognito browser contexts.
*/
TargetDestroyed = "targetdestroyed"
}
/**
* A Browser is created when Puppeteer connects to a Chromium instance, either through
* {@link PuppeteerNode.launch} or {@link Puppeteer.connect}.
*
* @remarks
*
* The Browser class extends from Puppeteer's {@link EventEmitter} class and will
* emit various events which are documented in the {@link BrowserEmittedEvents} enum.
*
* @example
*
* An example of using a {@link Browser} to create a {@link Page}:
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* await page.goto('https://example.com');
* await browser.close();
* })();
* ```
*
* @example
*
* An example of disconnecting from and reconnecting to a {@link Browser}:
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* // Store the endpoint to be able to reconnect to Chromium
* const browserWSEndpoint = browser.wsEndpoint();
* // Disconnect puppeteer from Chromium
* browser.disconnect();
*
* // Use the endpoint to reestablish a connection
* const browser2 = await puppeteer.connect({browserWSEndpoint});
* // Close Chromium
* await browser2.close();
* })();
* ```
*
* @public
*/
export declare class Browser extends EventEmitter {
/**
* @internal
*/
static create(connection: Connection, contextIds: string[], ignoreHTTPSErrors: boolean, defaultViewport?: Viewport | null, process?: ChildProcess, closeCallback?: BrowserCloseCallback, targetFilterCallback?: TargetFilterCallback): Promise<Browser>;
private _ignoreHTTPSErrors;
private _defaultViewport?;
private _process?;
private _connection;
private _closeCallback;
private _targetFilterCallback;
private _defaultContext;
private _contexts;
private _screenshotTaskQueue;
private _ignoredTargets;
/**
* @internal
* Used in Target.ts directly so cannot be marked private.
*/
_targets: Map<string, Target>;
/**
* @internal
*/
constructor(connection: Connection, contextIds: string[], ignoreHTTPSErrors: boolean, defaultViewport?: Viewport | null, process?: ChildProcess, closeCallback?: BrowserCloseCallback, targetFilterCallback?: TargetFilterCallback);
/**
* The spawned browser process. Returns `null` if the browser instance was created with
* {@link Puppeteer.connect}.
*/
process(): ChildProcess | null;
/**
* Creates a new incognito browser context. This won't share cookies/cache with other
* browser contexts.
*
* @example
* ```js
* (async () => {
* const browser = await puppeteer.launch();
* // Create a new incognito browser context.
* const context = await browser.createIncognitoBrowserContext();
* // Create a new page in a pristine context.
* const page = await context.newPage();
* // Do stuff
* await page.goto('https://example.com');
* })();
* ```
*/
createIncognitoBrowserContext(options?: BrowserContextOptions): Promise<BrowserContext>;
/**
* Returns an array of all open browser contexts. In a newly created browser, this will
* return a single instance of {@link BrowserContext}.
*/
browserContexts(): BrowserContext[];
/**
* Returns the default browser context. The default browser context cannot be closed.
*/
defaultBrowserContext(): BrowserContext;
/**
* @internal
* Used by BrowserContext directly so cannot be marked private.
*/
_disposeContext(contextId?: string): Promise<void>;
private _targetCreated;
private _targetDestroyed;
private _targetInfoChanged;
/**
* The browser websocket endpoint which can be used as an argument to
* {@link Puppeteer.connect}.
*
* @returns The Browser websocket url.
*
* @remarks
*
* The format is `ws://${host}:${port}/devtools/browser/<id>`.
*
* You can find the `webSocketDebuggerUrl` from `http://${host}:${port}/json/version`.
* Learn more about the
* {@link https://chromedevtools.github.io/devtools-protocol | devtools protocol} and
* the {@link
* https://chromedevtools.github.io/devtools-protocol/#how-do-i-access-the-browser-target
* | browser endpoint}.
*/
wsEndpoint(): string;
/**
* Promise which resolves to a new {@link Page} object. The Page is created in
* a default browser context.
*/
newPage(): Promise<Page>;
/**
* @internal
* Used by BrowserContext directly so cannot be marked private.
*/
_createPageInContext(contextId?: string): Promise<Page>;
/**
* All active targets inside the Browser. In case of multiple browser contexts, returns
* an array with all the targets in all browser contexts.
*/
targets(): Target[];
/**
* The target associated with the browser.
*/
target(): Target;
/**
* Searches for a target in all browser contexts.
*
* @param predicate - A function to be run for every target.
* @returns The first target found that matches the `predicate` function.
*
* @example
*
* An example of finding a target for a page opened via `window.open`:
* ```js
* await page.evaluate(() => window.open('https://www.example.com/'));
* const newWindowTarget = await browser.waitForTarget(target => target.url() === 'https://www.example.com/');
* ```
*/
waitForTarget(predicate: (x: Target) => boolean | Promise<boolean>, options?: WaitForTargetOptions): Promise<Target>;
/**
* An array of all open pages inside the Browser.
*
* @remarks
*
* In case of multiple browser contexts, returns an array with all the pages in all
* browser contexts. Non-visible pages, such as `"background_page"`, will not be listed
* here. You can find them using {@link Target.page}.
*/
pages(): Promise<Page[]>;
/**
* A string representing the browser name and version.
*
* @remarks
*
* For headless Chromium, this is similar to `HeadlessChrome/61.0.3153.0`. For
* non-headless, this is similar to `Chrome/61.0.3153.0`.
*
* The format of browser.version() might change with future releases of Chromium.
*/
version(): Promise<string>;
/**
* The browser's original user agent. Pages can override the browser user agent with
* {@link Page.setUserAgent}.
*/
userAgent(): Promise<string>;
/**
* Closes Chromium and all of its pages (if any were opened). The {@link Browser} object
* itself is considered to be disposed and cannot be used anymore.
*/
close(): Promise<void>;
/**
* Disconnects Puppeteer from the browser, but leaves the Chromium process running.
* After calling `disconnect`, the {@link Browser} object is considered disposed and
* cannot be used anymore.
*/
disconnect(): void;
/**
* Indicates that the browser is connected.
*/
isConnected(): boolean;
private _getVersion;
}
/**
* @public
*/
export declare const enum BrowserContextEmittedEvents {
/**
* Emitted when the url of a target inside the browser context changes.
* Contains a {@link Target} instance.
*/
TargetChanged = "targetchanged",
/**
* Emitted when a target is created within the browser context, for example
* when a new page is opened by
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Window/open | window.open}
* or by {@link BrowserContext.newPage | browserContext.newPage}
*
* Contains a {@link Target} instance.
*/
TargetCreated = "targetcreated",
/**
* Emitted when a target is destroyed within the browser context, for example
* when a page is closed. Contains a {@link Target} instance.
*/
TargetDestroyed = "targetdestroyed"
}
/**
* BrowserContexts provide a way to operate multiple independent browser
* sessions. When a browser is launched, it has a single BrowserContext used by
* default. The method {@link Browser.newPage | Browser.newPage} creates a page
* in the default browser context.
*
* @remarks
*
* The Browser class extends from Puppeteer's {@link EventEmitter} class and
* will emit various events which are documented in the
* {@link BrowserContextEmittedEvents} enum.
*
* If a page opens another page, e.g. with a `window.open` call, the popup will
* belong to the parent page's browser context.
*
* Puppeteer allows creation of "incognito" browser contexts with
* {@link Browser.createIncognitoBrowserContext | Browser.createIncognitoBrowserContext}
* method. "Incognito" browser contexts don't write any browsing data to disk.
*
* @example
* ```js
* // Create a new incognito browser context
* const context = await browser.createIncognitoBrowserContext();
* // Create a new page inside context.
* const page = await context.newPage();
* // ... do stuff with page ...
* await page.goto('https://example.com');
* // Dispose context once it's no longer needed.
* await context.close();
* ```
* @public
*/
export declare class BrowserContext extends EventEmitter {
private _connection;
private _browser;
private _id?;
/**
* @internal
*/
constructor(connection: Connection, browser: Browser, contextId?: string);
/**
* An array of all active targets inside the browser context.
*/
targets(): Target[];
/**
* This searches for a target in this specific browser context.
*
* @example
* An example of finding a target for a page opened via `window.open`:
* ```js
* await page.evaluate(() => window.open('https://www.example.com/'));
* const newWindowTarget = await browserContext.waitForTarget(target => target.url() === 'https://www.example.com/');
* ```
*
* @param predicate - A function to be run for every target
* @param options - An object of options. Accepts a timout,
* which is the maximum wait time in milliseconds.
* Pass `0` to disable the timeout. Defaults to 30 seconds.
* @returns Promise which resolves to the first target found
* that matches the `predicate` function.
*/
waitForTarget(predicate: (x: Target) => boolean | Promise<boolean>, options?: {
timeout?: number;
}): Promise<Target>;
/**
* An array of all pages inside the browser context.
*
* @returns Promise which resolves to an array of all open pages.
* Non visible pages, such as `"background_page"`, will not be listed here.
* You can find them using {@link Target.page | the target page}.
*/
pages(): Promise<Page[]>;
/**
* Returns whether BrowserContext is incognito.
* The default browser context is the only non-incognito browser context.
*
* @remarks
* The default browser context cannot be closed.
*/
isIncognito(): boolean;
/**
* @example
* ```js
* const context = browser.defaultBrowserContext();
* await context.overridePermissions('https://html5demos.com', ['geolocation']);
* ```
*
* @param origin - The origin to grant permissions to, e.g. "https://example.com".
* @param permissions - An array of permissions to grant.
* All permissions that are not listed here will be automatically denied.
*/
overridePermissions(origin: string, permissions: Permission[]): Promise<void>;
/**
* Clears all permission overrides for the browser context.
*
* @example
* ```js
* const context = browser.defaultBrowserContext();
* context.overridePermissions('https://example.com', ['clipboard-read']);
* // do stuff ..
* context.clearPermissionOverrides();
* ```
*/
clearPermissionOverrides(): Promise<void>;
/**
* Creates a new page in the browser context.
*/
newPage(): Promise<Page>;
/**
* The browser this browser context belongs to.
*/
browser(): Browser;
/**
* Closes the browser context. All the targets that belong to the browser context
* will be closed.
*
* @remarks
* Only incognito browser contexts can be closed.
*/
close(): Promise<void>;
}
//# sourceMappingURL=Browser.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Browser.d.ts","sourceRoot":"","sources":["../../../../src/common/Browser.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,574 @@
"use strict";
/**
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.BrowserContext = exports.Browser = void 0;
const assert_js_1 = require("./assert.js");
const helper_js_1 = require("./helper.js");
const Target_js_1 = require("./Target.js");
const EventEmitter_js_1 = require("./EventEmitter.js");
const Connection_js_1 = require("./Connection.js");
const TaskQueue_js_1 = require("./TaskQueue.js");
const WEB_PERMISSION_TO_PROTOCOL_PERMISSION = new Map([
['geolocation', 'geolocation'],
['midi', 'midi'],
['notifications', 'notifications'],
// TODO: push isn't a valid type?
// ['push', 'push'],
['camera', 'videoCapture'],
['microphone', 'audioCapture'],
['background-sync', 'backgroundSync'],
['ambient-light-sensor', 'sensors'],
['accelerometer', 'sensors'],
['gyroscope', 'sensors'],
['magnetometer', 'sensors'],
['accessibility-events', 'accessibilityEvents'],
['clipboard-read', 'clipboardReadWrite'],
['clipboard-write', 'clipboardReadWrite'],
['payment-handler', 'paymentHandler'],
['persistent-storage', 'durableStorage'],
['idle-detection', 'idleDetection'],
// chrome-specific permissions we have.
['midi-sysex', 'midiSysex'],
]);
/**
* A Browser is created when Puppeteer connects to a Chromium instance, either through
* {@link PuppeteerNode.launch} or {@link Puppeteer.connect}.
*
* @remarks
*
* The Browser class extends from Puppeteer's {@link EventEmitter} class and will
* emit various events which are documented in the {@link BrowserEmittedEvents} enum.
*
* @example
*
* An example of using a {@link Browser} to create a {@link Page}:
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* await page.goto('https://example.com');
* await browser.close();
* })();
* ```
*
* @example
*
* An example of disconnecting from and reconnecting to a {@link Browser}:
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* // Store the endpoint to be able to reconnect to Chromium
* const browserWSEndpoint = browser.wsEndpoint();
* // Disconnect puppeteer from Chromium
* browser.disconnect();
*
* // Use the endpoint to reestablish a connection
* const browser2 = await puppeteer.connect({browserWSEndpoint});
* // Close Chromium
* await browser2.close();
* })();
* ```
*
* @public
*/
class Browser extends EventEmitter_js_1.EventEmitter {
/**
* @internal
*/
constructor(connection, contextIds, ignoreHTTPSErrors, defaultViewport, process, closeCallback, targetFilterCallback) {
super();
this._ignoredTargets = new Set();
this._ignoreHTTPSErrors = ignoreHTTPSErrors;
this._defaultViewport = defaultViewport;
this._process = process;
this._screenshotTaskQueue = new TaskQueue_js_1.TaskQueue();
this._connection = connection;
this._closeCallback = closeCallback || function () { };
this._targetFilterCallback = targetFilterCallback || (() => true);
this._defaultContext = new BrowserContext(this._connection, this);
this._contexts = new Map();
for (const contextId of contextIds)
this._contexts.set(contextId, new BrowserContext(this._connection, this, contextId));
this._targets = new Map();
this._connection.on(Connection_js_1.ConnectionEmittedEvents.Disconnected, () => this.emit("disconnected" /* Disconnected */));
this._connection.on('Target.targetCreated', this._targetCreated.bind(this));
this._connection.on('Target.targetDestroyed', this._targetDestroyed.bind(this));
this._connection.on('Target.targetInfoChanged', this._targetInfoChanged.bind(this));
}
/**
* @internal
*/
static async create(connection, contextIds, ignoreHTTPSErrors, defaultViewport, process, closeCallback, targetFilterCallback) {
const browser = new Browser(connection, contextIds, ignoreHTTPSErrors, defaultViewport, process, closeCallback, targetFilterCallback);
await connection.send('Target.setDiscoverTargets', { discover: true });
return browser;
}
/**
* The spawned browser process. Returns `null` if the browser instance was created with
* {@link Puppeteer.connect}.
*/
process() {
var _a;
return (_a = this._process) !== null && _a !== void 0 ? _a : null;
}
/**
* Creates a new incognito browser context. This won't share cookies/cache with other
* browser contexts.
*
* @example
* ```js
* (async () => {
* const browser = await puppeteer.launch();
* // Create a new incognito browser context.
* const context = await browser.createIncognitoBrowserContext();
* // Create a new page in a pristine context.
* const page = await context.newPage();
* // Do stuff
* await page.goto('https://example.com');
* })();
* ```
*/
async createIncognitoBrowserContext(options = {}) {
const { proxyServer, proxyBypassList } = options;
const { browserContextId } = await this._connection.send('Target.createBrowserContext', {
proxyServer,
proxyBypassList: proxyBypassList && proxyBypassList.join(','),
});
const context = new BrowserContext(this._connection, this, browserContextId);
this._contexts.set(browserContextId, context);
return context;
}
/**
* Returns an array of all open browser contexts. In a newly created browser, this will
* return a single instance of {@link BrowserContext}.
*/
browserContexts() {
return [this._defaultContext, ...Array.from(this._contexts.values())];
}
/**
* Returns the default browser context. The default browser context cannot be closed.
*/
defaultBrowserContext() {
return this._defaultContext;
}
/**
* @internal
* Used by BrowserContext directly so cannot be marked private.
*/
async _disposeContext(contextId) {
if (!contextId) {
return;
}
await this._connection.send('Target.disposeBrowserContext', {
browserContextId: contextId,
});
this._contexts.delete(contextId);
}
async _targetCreated(event) {
var _a;
const targetInfo = event.targetInfo;
const { browserContextId } = targetInfo;
const context = browserContextId && this._contexts.has(browserContextId)
? this._contexts.get(browserContextId)
: this._defaultContext;
if (!context) {
throw new Error('Missing browser context');
}
const shouldAttachToTarget = this._targetFilterCallback(targetInfo);
if (!shouldAttachToTarget) {
this._ignoredTargets.add(targetInfo.targetId);
return;
}
const target = new Target_js_1.Target(targetInfo, context, () => this._connection.createSession(targetInfo), this._ignoreHTTPSErrors, (_a = this._defaultViewport) !== null && _a !== void 0 ? _a : null, this._screenshotTaskQueue);
(0, assert_js_1.assert)(!this._targets.has(event.targetInfo.targetId), 'Target should not exist before targetCreated');
this._targets.set(event.targetInfo.targetId, target);
if (await target._initializedPromise) {
this.emit("targetcreated" /* TargetCreated */, target);
context.emit("targetcreated" /* TargetCreated */, target);
}
}
async _targetDestroyed(event) {
if (this._ignoredTargets.has(event.targetId))
return;
const target = this._targets.get(event.targetId);
if (!target) {
throw new Error(`Missing target in _targetDestroyed (id = ${event.targetId})`);
}
target._initializedCallback(false);
this._targets.delete(event.targetId);
target._closedCallback();
if (await target._initializedPromise) {
this.emit("targetdestroyed" /* TargetDestroyed */, target);
target
.browserContext()
.emit("targetdestroyed" /* TargetDestroyed */, target);
}
}
_targetInfoChanged(event) {
if (this._ignoredTargets.has(event.targetInfo.targetId))
return;
const target = this._targets.get(event.targetInfo.targetId);
if (!target) {
throw new Error(`Missing target in targetInfoChanged (id = ${event.targetInfo.targetId})`);
}
const previousURL = target.url();
const wasInitialized = target._isInitialized;
target._targetInfoChanged(event.targetInfo);
if (wasInitialized && previousURL !== target.url()) {
this.emit("targetchanged" /* TargetChanged */, target);
target
.browserContext()
.emit("targetchanged" /* TargetChanged */, target);
}
}
/**
* The browser websocket endpoint which can be used as an argument to
* {@link Puppeteer.connect}.
*
* @returns The Browser websocket url.
*
* @remarks
*
* The format is `ws://${host}:${port}/devtools/browser/<id>`.
*
* You can find the `webSocketDebuggerUrl` from `http://${host}:${port}/json/version`.
* Learn more about the
* {@link https://chromedevtools.github.io/devtools-protocol | devtools protocol} and
* the {@link
* https://chromedevtools.github.io/devtools-protocol/#how-do-i-access-the-browser-target
* | browser endpoint}.
*/
wsEndpoint() {
return this._connection.url();
}
/**
* Promise which resolves to a new {@link Page} object. The Page is created in
* a default browser context.
*/
async newPage() {
return this._defaultContext.newPage();
}
/**
* @internal
* Used by BrowserContext directly so cannot be marked private.
*/
async _createPageInContext(contextId) {
const { targetId } = await this._connection.send('Target.createTarget', {
url: 'about:blank',
browserContextId: contextId || undefined,
});
const target = this._targets.get(targetId);
if (!target) {
throw new Error(`Missing target for page (id = ${targetId})`);
}
const initialized = await target._initializedPromise;
if (!initialized) {
throw new Error(`Failed to create target for page (id = ${targetId})`);
}
const page = await target.page();
if (!page) {
throw new Error(`Failed to create a page for context (id = ${contextId})`);
}
return page;
}
/**
* All active targets inside the Browser. In case of multiple browser contexts, returns
* an array with all the targets in all browser contexts.
*/
targets() {
return Array.from(this._targets.values()).filter((target) => target._isInitialized);
}
/**
* The target associated with the browser.
*/
target() {
const browserTarget = this.targets().find((target) => target.type() === 'browser');
if (!browserTarget) {
throw new Error('Browser target is not found');
}
return browserTarget;
}
/**
* Searches for a target in all browser contexts.
*
* @param predicate - A function to be run for every target.
* @returns The first target found that matches the `predicate` function.
*
* @example
*
* An example of finding a target for a page opened via `window.open`:
* ```js
* await page.evaluate(() => window.open('https://www.example.com/'));
* const newWindowTarget = await browser.waitForTarget(target => target.url() === 'https://www.example.com/');
* ```
*/
async waitForTarget(predicate, options = {}) {
const { timeout = 30000 } = options;
let resolve;
const targetPromise = new Promise((x) => (resolve = x));
this.on("targetcreated" /* TargetCreated */, check);
this.on("targetchanged" /* TargetChanged */, check);
try {
if (!timeout)
return await targetPromise;
return await helper_js_1.helper.waitWithTimeout(Promise.race([
targetPromise,
(async () => {
for (const target of this.targets()) {
if (await predicate(target)) {
return target;
}
}
await targetPromise;
})(),
]), 'target', timeout);
}
finally {
this.removeListener("targetcreated" /* TargetCreated */, check);
this.removeListener("targetchanged" /* TargetChanged */, check);
}
async function check(target) {
if (await predicate(target))
resolve(target);
}
}
/**
* An array of all open pages inside the Browser.
*
* @remarks
*
* In case of multiple browser contexts, returns an array with all the pages in all
* browser contexts. Non-visible pages, such as `"background_page"`, will not be listed
* here. You can find them using {@link Target.page}.
*/
async pages() {
const contextPages = await Promise.all(this.browserContexts().map((context) => context.pages()));
// Flatten array.
return contextPages.reduce((acc, x) => acc.concat(x), []);
}
/**
* A string representing the browser name and version.
*
* @remarks
*
* For headless Chromium, this is similar to `HeadlessChrome/61.0.3153.0`. For
* non-headless, this is similar to `Chrome/61.0.3153.0`.
*
* The format of browser.version() might change with future releases of Chromium.
*/
async version() {
const version = await this._getVersion();
return version.product;
}
/**
* The browser's original user agent. Pages can override the browser user agent with
* {@link Page.setUserAgent}.
*/
async userAgent() {
const version = await this._getVersion();
return version.userAgent;
}
/**
* Closes Chromium and all of its pages (if any were opened). The {@link Browser} object
* itself is considered to be disposed and cannot be used anymore.
*/
async close() {
await this._closeCallback.call(null);
this.disconnect();
}
/**
* Disconnects Puppeteer from the browser, but leaves the Chromium process running.
* After calling `disconnect`, the {@link Browser} object is considered disposed and
* cannot be used anymore.
*/
disconnect() {
this._connection.dispose();
}
/**
* Indicates that the browser is connected.
*/
isConnected() {
return !this._connection._closed;
}
_getVersion() {
return this._connection.send('Browser.getVersion');
}
}
exports.Browser = Browser;
/**
* BrowserContexts provide a way to operate multiple independent browser
* sessions. When a browser is launched, it has a single BrowserContext used by
* default. The method {@link Browser.newPage | Browser.newPage} creates a page
* in the default browser context.
*
* @remarks
*
* The Browser class extends from Puppeteer's {@link EventEmitter} class and
* will emit various events which are documented in the
* {@link BrowserContextEmittedEvents} enum.
*
* If a page opens another page, e.g. with a `window.open` call, the popup will
* belong to the parent page's browser context.
*
* Puppeteer allows creation of "incognito" browser contexts with
* {@link Browser.createIncognitoBrowserContext | Browser.createIncognitoBrowserContext}
* method. "Incognito" browser contexts don't write any browsing data to disk.
*
* @example
* ```js
* // Create a new incognito browser context
* const context = await browser.createIncognitoBrowserContext();
* // Create a new page inside context.
* const page = await context.newPage();
* // ... do stuff with page ...
* await page.goto('https://example.com');
* // Dispose context once it's no longer needed.
* await context.close();
* ```
* @public
*/
class BrowserContext extends EventEmitter_js_1.EventEmitter {
/**
* @internal
*/
constructor(connection, browser, contextId) {
super();
this._connection = connection;
this._browser = browser;
this._id = contextId;
}
/**
* An array of all active targets inside the browser context.
*/
targets() {
return this._browser
.targets()
.filter((target) => target.browserContext() === this);
}
/**
* This searches for a target in this specific browser context.
*
* @example
* An example of finding a target for a page opened via `window.open`:
* ```js
* await page.evaluate(() => window.open('https://www.example.com/'));
* const newWindowTarget = await browserContext.waitForTarget(target => target.url() === 'https://www.example.com/');
* ```
*
* @param predicate - A function to be run for every target
* @param options - An object of options. Accepts a timout,
* which is the maximum wait time in milliseconds.
* Pass `0` to disable the timeout. Defaults to 30 seconds.
* @returns Promise which resolves to the first target found
* that matches the `predicate` function.
*/
waitForTarget(predicate, options = {}) {
return this._browser.waitForTarget((target) => target.browserContext() === this && predicate(target), options);
}
/**
* An array of all pages inside the browser context.
*
* @returns Promise which resolves to an array of all open pages.
* Non visible pages, such as `"background_page"`, will not be listed here.
* You can find them using {@link Target.page | the target page}.
*/
async pages() {
const pages = await Promise.all(this.targets()
.filter((target) => target.type() === 'page')
.map((target) => target.page()));
return pages.filter((page) => !!page);
}
/**
* Returns whether BrowserContext is incognito.
* The default browser context is the only non-incognito browser context.
*
* @remarks
* The default browser context cannot be closed.
*/
isIncognito() {
return !!this._id;
}
/**
* @example
* ```js
* const context = browser.defaultBrowserContext();
* await context.overridePermissions('https://html5demos.com', ['geolocation']);
* ```
*
* @param origin - The origin to grant permissions to, e.g. "https://example.com".
* @param permissions - An array of permissions to grant.
* All permissions that are not listed here will be automatically denied.
*/
async overridePermissions(origin, permissions) {
const protocolPermissions = permissions.map((permission) => {
const protocolPermission = WEB_PERMISSION_TO_PROTOCOL_PERMISSION.get(permission);
if (!protocolPermission)
throw new Error('Unknown permission: ' + permission);
return protocolPermission;
});
await this._connection.send('Browser.grantPermissions', {
origin,
browserContextId: this._id || undefined,
permissions: protocolPermissions,
});
}
/**
* Clears all permission overrides for the browser context.
*
* @example
* ```js
* const context = browser.defaultBrowserContext();
* context.overridePermissions('https://example.com', ['clipboard-read']);
* // do stuff ..
* context.clearPermissionOverrides();
* ```
*/
async clearPermissionOverrides() {
await this._connection.send('Browser.resetPermissions', {
browserContextId: this._id || undefined,
});
}
/**
* Creates a new page in the browser context.
*/
newPage() {
return this._browser._createPageInContext(this._id);
}
/**
* The browser this browser context belongs to.
*/
browser() {
return this._browser;
}
/**
* Closes the browser context. All the targets that belong to the browser context
* will be closed.
*
* @remarks
* Only incognito browser contexts can be closed.
*/
async close() {
(0, assert_js_1.assert)(this._id, 'Non-incognito profiles cannot be closed!');
await this._browser._disposeContext(this._id);
}
}
exports.BrowserContext = BrowserContext;
//# sourceMappingURL=Browser.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,54 @@
/**
* 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.
*/
import { ConnectionTransport } from './ConnectionTransport.js';
import { Browser, TargetFilterCallback } from './Browser.js';
import { Viewport } from './PuppeteerViewport.js';
/**
* Generic browser options that can be passed when launching any browser or when
* connecting to an existing browser instance.
* @public
*/
export interface BrowserConnectOptions {
/**
* Whether to ignore HTTPS errors during navigation.
* @defaultValue false
*/
ignoreHTTPSErrors?: boolean;
/**
* Sets the viewport for each page.
*/
defaultViewport?: Viewport | null;
/**
* Slows down Puppeteer operations by the specified amount of milliseconds to
* aid debugging.
*/
slowMo?: number;
/**
* Callback to decide if Puppeteer should connect to a given target or not.
*/
targetFilter?: TargetFilterCallback;
}
/**
* Users should never call this directly; it's called when calling
* `puppeteer.connect`.
* @internal
*/
export declare const connectToBrowser: (options: BrowserConnectOptions & {
browserWSEndpoint?: string;
browserURL?: string;
transport?: ConnectionTransport;
}) => Promise<Browser>;
//# sourceMappingURL=BrowserConnector.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BrowserConnector.d.ts","sourceRoot":"","sources":["../../../../src/common/BrowserConnector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAI7D,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAIlD;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;OAEG;IACH,eAAe,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAClC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,YAAY,CAAC,EAAE,oBAAoB,CAAC;CACrC;AASD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,YAClB,qBAAqB,GAAG;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,mBAAmB,CAAC;CACjC,KACA,QAAQ,OAAO,CA6CjB,CAAC"}

View File

@@ -0,0 +1,102 @@
"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.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (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.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.connectToBrowser = void 0;
const Browser_js_1 = require("./Browser.js");
const assert_js_1 = require("./assert.js");
const helper_js_1 = require("../common/helper.js");
const Connection_js_1 = require("./Connection.js");
const environment_js_1 = require("../environment.js");
const fetch_js_1 = require("./fetch.js");
const getWebSocketTransportClass = async () => {
return environment_js_1.isNode
? (await Promise.resolve().then(() => __importStar(require('../node/NodeWebSocketTransport.js')))).NodeWebSocketTransport
: (await Promise.resolve().then(() => __importStar(require('./BrowserWebSocketTransport.js'))))
.BrowserWebSocketTransport;
};
/**
* Users should never call this directly; it's called when calling
* `puppeteer.connect`.
* @internal
*/
const connectToBrowser = async (options) => {
const { browserWSEndpoint, browserURL, ignoreHTTPSErrors = false, defaultViewport = { width: 800, height: 600 }, transport, slowMo = 0, targetFilter, } = options;
(0, 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 WebSocketClass = await getWebSocketTransportClass();
const connectionTransport = await WebSocketClass.create(browserWSEndpoint);
connection = new Connection_js_1.Connection(browserWSEndpoint, connectionTransport, slowMo);
}
else if (browserURL) {
const connectionURL = await getWSEndpoint(browserURL);
const WebSocketClass = await getWebSocketTransportClass();
const connectionTransport = await WebSocketClass.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), targetFilter);
};
exports.connectToBrowser = connectToBrowser;
async function getWSEndpoint(browserURL) {
const endpointURL = new URL('/json/version', browserURL);
const fetch = await (0, fetch_js_1.getFetch)();
try {
const result = await fetch(endpointURL.toString(), {
method: 'GET',
});
if (!result.ok) {
throw new Error(`HTTP ${result.statusText}`);
}
const data = await result.json();
return data.webSocketDebuggerUrl;
}
catch (error) {
error.message =
`Failed to fetch browser webSocket URL from ${endpointURL}: ` +
error.message;
throw error;
}
}
//# sourceMappingURL=BrowserConnector.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BrowserConnector.js","sourceRoot":"","sources":["../../../../src/common/BrowserConnector.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,26 @@
/**
* 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.
*/
import { ConnectionTransport } from './ConnectionTransport.js';
export declare class BrowserWebSocketTransport implements ConnectionTransport {
static create(url: string): Promise<BrowserWebSocketTransport>;
private _ws;
onmessage?: (message: string) => void;
onclose?: () => void;
constructor(ws: WebSocket);
send(message: string): void;
close(): void;
}
//# sourceMappingURL=BrowserWebSocketTransport.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BrowserWebSocketTransport.d.ts","sourceRoot":"","sources":["../../../../src/common/BrowserWebSocketTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,qBAAa,yBAA0B,YAAW,mBAAmB;IACnE,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAW9D,OAAO,CAAC,GAAG,CAAY;IACvB,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;gBAET,EAAE,EAAE,SAAS;IAczB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI3B,KAAK,IAAI,IAAI;CAGd"}

View File

@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BrowserWebSocketTransport = void 0;
class BrowserWebSocketTransport {
constructor(ws) {
this._ws = ws;
this._ws.addEventListener('message', (event) => {
if (this.onmessage)
this.onmessage.call(null, event.data);
});
this._ws.addEventListener('close', () => {
if (this.onclose)
this.onclose.call(null);
});
// Silently ignore all errors - we don't know what to do with them.
this._ws.addEventListener('error', () => { });
this.onmessage = null;
this.onclose = null;
}
static create(url) {
return new Promise((resolve, reject) => {
const ws = new WebSocket(url);
ws.addEventListener('open', () => resolve(new BrowserWebSocketTransport(ws)));
ws.addEventListener('error', reject);
});
}
send(message) {
this._ws.send(message);
}
close() {
this._ws.close();
}
}
exports.BrowserWebSocketTransport = BrowserWebSocketTransport;
//# sourceMappingURL=BrowserWebSocketTransport.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"BrowserWebSocketTransport.js","sourceRoot":"","sources":["../../../../src/common/BrowserWebSocketTransport.ts"],"names":[],"mappings":";;;AAiBA,MAAa,yBAAyB;IAgBpC,YAAY,EAAa;QACvB,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC;QACd,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;YAC7C,IAAI,IAAI,CAAC,SAAS;gBAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;YACtC,IAAI,IAAI,CAAC,OAAO;gBAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QACH,mEAAmE;QACnE,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC7C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACtB,CAAC;IA3BD,MAAM,CAAC,MAAM,CAAC,GAAW;QACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,EAAE,GAAG,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC;YAE9B,EAAE,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,CAC/B,OAAO,CAAC,IAAI,yBAAyB,CAAC,EAAE,CAAC,CAAC,CAC3C,CAAC;YACF,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC;IAoBD,IAAI,CAAC,OAAe;QAClB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;IACnB,CAAC;CACF;AArCD,8DAqCC"}

View File

@@ -0,0 +1,136 @@
import { Protocol } from 'devtools-protocol';
import { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping.js';
import { ConnectionTransport } from './ConnectionTransport.js';
import { EventEmitter } from './EventEmitter.js';
import { ProtocolError } from './Errors.js';
/**
* @public
*/
export { ConnectionTransport, ProtocolMapping };
/**
* @public
*/
export interface ConnectionCallback {
resolve: Function;
reject: Function;
error: ProtocolError;
method: string;
}
/**
* Internal events that the Connection class emits.
*
* @internal
*/
export declare const ConnectionEmittedEvents: {
readonly Disconnected: symbol;
};
/**
* @public
*/
export declare class Connection extends EventEmitter {
_url: string;
_transport: ConnectionTransport;
_delay: number;
_lastId: number;
_sessions: Map<string, CDPSession>;
_closed: boolean;
_callbacks: Map<number, ConnectionCallback>;
constructor(url: string, transport: ConnectionTransport, delay?: number);
static fromSession(session: CDPSession): Connection | undefined;
/**
* @param sessionId - The session id
* @returns The current CDP session if it exists
*/
session(sessionId: string): CDPSession | null;
url(): string;
send<T extends keyof ProtocolMapping.Commands>(method: T, ...paramArgs: ProtocolMapping.Commands[T]['paramsType']): Promise<ProtocolMapping.Commands[T]['returnType']>;
_rawSend(message: Record<string, unknown>): number;
_onMessage(message: string): Promise<void>;
_onClose(): void;
dispose(): void;
/**
* @param targetInfo - The target info
* @returns The CDP session that is created
*/
createSession(targetInfo: Protocol.Target.TargetInfo): Promise<CDPSession>;
}
/**
* @public
*/
export interface CDPSessionOnMessageObject {
id?: number;
method: string;
params: Record<string, unknown>;
error: {
message: string;
data: any;
code: number;
};
result?: any;
}
/**
* Internal events that the CDPSession class emits.
*
* @internal
*/
export declare const CDPSessionEmittedEvents: {
readonly Disconnected: symbol;
};
/**
* The `CDPSession` instances are used to talk raw Chrome Devtools Protocol.
*
* @remarks
*
* Protocol methods can be called with {@link CDPSession.send} method and protocol
* events can be subscribed to with `CDPSession.on` method.
*
* Useful links: {@link https://chromedevtools.github.io/devtools-protocol/ | DevTools Protocol Viewer}
* and {@link https://github.com/aslushnikov/getting-started-with-cdp/blob/HEAD/README.md | Getting Started with DevTools Protocol}.
*
* @example
* ```js
* const client = await page.target().createCDPSession();
* await client.send('Animation.enable');
* client.on('Animation.animationCreated', () => console.log('Animation created!'));
* const response = await client.send('Animation.getPlaybackRate');
* console.log('playback rate is ' + response.playbackRate);
* await client.send('Animation.setPlaybackRate', {
* playbackRate: response.playbackRate / 2
* });
* ```
*
* @public
*/
export declare class CDPSession extends EventEmitter {
/**
* @internal
*/
_connection?: Connection;
private _sessionId;
private _targetType;
private _callbacks;
/**
* @internal
*/
constructor(connection: Connection, targetType: string, sessionId: string);
connection(): Connection | undefined;
send<T extends keyof ProtocolMapping.Commands>(method: T, ...paramArgs: ProtocolMapping.Commands[T]['paramsType']): Promise<ProtocolMapping.Commands[T]['returnType']>;
/**
* @internal
*/
_onMessage(object: CDPSessionOnMessageObject): void;
/**
* Detaches the cdpSession from the target. Once detached, the cdpSession object
* won't emit any events and can't be used to send messages.
*/
detach(): Promise<void>;
/**
* @internal
*/
_onClosed(): void;
/**
* @internal
*/
id(): string;
}
//# sourceMappingURL=Connection.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Connection.d.ts","sourceRoot":"","sources":["../../../../src/common/Connection.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C;;GAEG;AACH,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,QAAQ,CAAC;IAClB,MAAM,EAAE,QAAQ,CAAC;IACjB,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,eAAO,MAAM,uBAAuB;;CAE1B,CAAC;AAEX;;GAEG;AACH,qBAAa,UAAW,SAAQ,YAAY;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,mBAAmB,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,SAAK;IACZ,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAa;IAC/C,OAAO,UAAS;IAEhB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAa;gBAE5C,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,mBAAmB,EAAE,KAAK,SAAI;IAUlE,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS;IAI/D;;;OAGG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAI7C,GAAG,IAAI,MAAM;IAIb,IAAI,CAAC,CAAC,SAAS,MAAM,eAAe,CAAC,QAAQ,EAC3C,MAAM,EAAE,CAAC,EACT,GAAG,SAAS,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,GACtD,OAAO,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IAmBrD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM;IAU5C,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgDhD,QAAQ,IAAI,IAAI;IAkBhB,OAAO,IAAI,IAAI;IAKf;;;OAGG;IACG,aAAa,CACjB,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,GACrC,OAAO,CAAC,UAAU,CAAC;CAWvB;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,GAAG,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACpD,MAAM,CAAC,EAAE,GAAG,CAAC;CACd;AAED;;;;GAIG;AACH,eAAO,MAAM,uBAAuB;;CAE1B,CAAC;AAEX;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,UAAW,SAAQ,YAAY;IAC1C;;OAEG;IACH,WAAW,CAAC,EAAE,UAAU,CAAC;IACzB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,UAAU,CAA8C;IAEhE;;OAEG;gBACS,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAOzE,UAAU,IAAI,UAAU,GAAG,SAAS;IAIpC,IAAI,CAAC,CAAC,SAAS,MAAM,eAAe,CAAC,QAAQ,EAC3C,MAAM,EAAE,CAAC,EACT,GAAG,SAAS,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,GACtD,OAAO,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IA2BrD;;OAEG;IACH,UAAU,CAAC,MAAM,EAAE,yBAAyB,GAAG,IAAI;IAenD;;;OAGG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAU7B;;OAEG;IACH,SAAS,IAAI,IAAI;IAajB;;OAEG;IACH,EAAE,IAAI,MAAM;CAGb"}

View File

@@ -0,0 +1,303 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CDPSession = exports.CDPSessionEmittedEvents = exports.Connection = exports.ConnectionEmittedEvents = void 0;
/**
* 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.
*/
const assert_js_1 = require("./assert.js");
const Debug_js_1 = require("./Debug.js");
const debugProtocolSend = (0, Debug_js_1.debug)('puppeteer:protocol:SEND ►');
const debugProtocolReceive = (0, Debug_js_1.debug)('puppeteer:protocol:RECV ◀');
const EventEmitter_js_1 = require("./EventEmitter.js");
const Errors_js_1 = require("./Errors.js");
/**
* Internal events that the Connection class emits.
*
* @internal
*/
exports.ConnectionEmittedEvents = {
Disconnected: Symbol('Connection.Disconnected'),
};
/**
* @public
*/
class Connection extends EventEmitter_js_1.EventEmitter {
constructor(url, transport, delay = 0) {
super();
this._lastId = 0;
this._sessions = new Map();
this._closed = false;
this._callbacks = new Map();
this._url = url;
this._delay = delay;
this._transport = transport;
this._transport.onmessage = this._onMessage.bind(this);
this._transport.onclose = this._onClose.bind(this);
}
static fromSession(session) {
return session._connection;
}
/**
* @param sessionId - The session id
* @returns The current CDP session if it exists
*/
session(sessionId) {
return this._sessions.get(sessionId) || null;
}
url() {
return this._url;
}
send(method, ...paramArgs) {
// There is only ever 1 param arg passed, but the Protocol defines it as an
// array of 0 or 1 items See this comment:
// https://github.com/ChromeDevTools/devtools-protocol/pull/113#issuecomment-412603285
// which explains why the protocol defines the params this way for better
// type-inference.
// So now we check if there are any params or not and deal with them accordingly.
const params = paramArgs.length ? paramArgs[0] : undefined;
const id = this._rawSend({ method, params });
return new Promise((resolve, reject) => {
this._callbacks.set(id, {
resolve,
reject,
error: new Errors_js_1.ProtocolError(),
method,
});
});
}
_rawSend(message) {
const id = ++this._lastId;
const stringifiedMessage = JSON.stringify(Object.assign({}, message, { id }));
debugProtocolSend(stringifiedMessage);
this._transport.send(stringifiedMessage);
return id;
}
async _onMessage(message) {
if (this._delay)
await new Promise((f) => setTimeout(f, this._delay));
debugProtocolReceive(message);
const object = JSON.parse(message);
if (object.method === 'Target.attachedToTarget') {
const sessionId = object.params.sessionId;
const session = new CDPSession(this, object.params.targetInfo.type, sessionId);
this._sessions.set(sessionId, session);
this.emit('sessionattached', session);
const parentSession = this._sessions.get(object.sessionId);
if (parentSession) {
parentSession.emit('sessionattached', session);
}
}
else if (object.method === 'Target.detachedFromTarget') {
const session = this._sessions.get(object.params.sessionId);
if (session) {
session._onClosed();
this._sessions.delete(object.params.sessionId);
this.emit('sessiondetached', session);
const parentSession = this._sessions.get(object.sessionId);
if (parentSession) {
parentSession.emit('sessiondetached', session);
}
}
}
if (object.sessionId) {
const session = this._sessions.get(object.sessionId);
if (session)
session._onMessage(object);
}
else if (object.id) {
const callback = this._callbacks.get(object.id);
// Callbacks could be all rejected if someone has called `.dispose()`.
if (callback) {
this._callbacks.delete(object.id);
if (object.error)
callback.reject(createProtocolError(callback.error, callback.method, object));
else
callback.resolve(object.result);
}
}
else {
this.emit(object.method, object.params);
}
}
_onClose() {
if (this._closed)
return;
this._closed = true;
this._transport.onmessage = undefined;
this._transport.onclose = undefined;
for (const callback of this._callbacks.values())
callback.reject(rewriteError(callback.error, `Protocol error (${callback.method}): Target closed.`));
this._callbacks.clear();
for (const session of this._sessions.values())
session._onClosed();
this._sessions.clear();
this.emit(exports.ConnectionEmittedEvents.Disconnected);
}
dispose() {
this._onClose();
this._transport.close();
}
/**
* @param targetInfo - The target info
* @returns The CDP session that is created
*/
async createSession(targetInfo) {
const { sessionId } = await this.send('Target.attachToTarget', {
targetId: targetInfo.targetId,
flatten: true,
});
const session = this._sessions.get(sessionId);
if (!session) {
throw new Error('CDPSession creation failed.');
}
return session;
}
}
exports.Connection = Connection;
/**
* Internal events that the CDPSession class emits.
*
* @internal
*/
exports.CDPSessionEmittedEvents = {
Disconnected: Symbol('CDPSession.Disconnected'),
};
/**
* The `CDPSession` instances are used to talk raw Chrome Devtools Protocol.
*
* @remarks
*
* Protocol methods can be called with {@link CDPSession.send} method and protocol
* events can be subscribed to with `CDPSession.on` method.
*
* Useful links: {@link https://chromedevtools.github.io/devtools-protocol/ | DevTools Protocol Viewer}
* and {@link https://github.com/aslushnikov/getting-started-with-cdp/blob/HEAD/README.md | Getting Started with DevTools Protocol}.
*
* @example
* ```js
* const client = await page.target().createCDPSession();
* await client.send('Animation.enable');
* client.on('Animation.animationCreated', () => console.log('Animation created!'));
* const response = await client.send('Animation.getPlaybackRate');
* console.log('playback rate is ' + response.playbackRate);
* await client.send('Animation.setPlaybackRate', {
* playbackRate: response.playbackRate / 2
* });
* ```
*
* @public
*/
class CDPSession extends EventEmitter_js_1.EventEmitter {
/**
* @internal
*/
constructor(connection, targetType, sessionId) {
super();
this._callbacks = new Map();
this._connection = connection;
this._targetType = targetType;
this._sessionId = sessionId;
}
connection() {
return this._connection;
}
send(method, ...paramArgs) {
if (!this._connection)
return Promise.reject(new Error(`Protocol error (${method}): Session closed. Most likely the ${this._targetType} has been closed.`));
// See the comment in Connection#send explaining why we do this.
const params = paramArgs.length ? paramArgs[0] : undefined;
const id = this._connection._rawSend({
sessionId: this._sessionId,
method,
params,
});
return new Promise((resolve, reject) => {
this._callbacks.set(id, {
resolve,
reject,
error: new Errors_js_1.ProtocolError(),
method,
});
});
}
/**
* @internal
*/
_onMessage(object) {
const callback = object.id ? this._callbacks.get(object.id) : undefined;
if (object.id && callback) {
this._callbacks.delete(object.id);
if (object.error)
callback.reject(createProtocolError(callback.error, callback.method, object));
else
callback.resolve(object.result);
}
else {
(0, assert_js_1.assert)(!object.id);
this.emit(object.method, object.params);
}
}
/**
* Detaches the cdpSession from the target. Once detached, the cdpSession object
* won't emit any events and can't be used to send messages.
*/
async detach() {
if (!this._connection)
throw new Error(`Session already detached. Most likely the ${this._targetType} has been closed.`);
await this._connection.send('Target.detachFromTarget', {
sessionId: this._sessionId,
});
}
/**
* @internal
*/
_onClosed() {
for (const callback of this._callbacks.values())
callback.reject(rewriteError(callback.error, `Protocol error (${callback.method}): Target closed.`));
this._callbacks.clear();
this._connection = undefined;
this.emit(exports.CDPSessionEmittedEvents.Disconnected);
}
/**
* @internal
*/
id() {
return this._sessionId;
}
}
exports.CDPSession = CDPSession;
/**
* @param {!Error} error
* @param {string} method
* @param {{error: {message: string, data: any}}} object
* @returns {!Error}
*/
function createProtocolError(error, method, object) {
let message = `Protocol error (${method}): ${object.error.message}`;
if ('data' in object.error)
message += ` ${object.error.data}`;
return rewriteError(error, message, object.error.message);
}
/**
* @param {!Error} error
* @param {string} message
* @returns {!Error}
*/
function rewriteError(error, message, originalMessage) {
error.message = message;
error.originalMessage = originalMessage !== null && originalMessage !== void 0 ? originalMessage : error.originalMessage;
return error;
}
//# sourceMappingURL=Connection.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,25 @@
/**
* 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.
*/
/**
* @public
*/
export interface ConnectionTransport {
send(message: string): void;
close(): void;
onmessage?: (message: string) => void;
onclose?: () => void;
}
//# sourceMappingURL=ConnectionTransport.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ConnectionTransport.d.ts","sourceRoot":"","sources":["../../../../src/common/ConnectionTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,IAAI,IAAI,CAAC;IACd,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB"}

View File

@@ -0,0 +1,18 @@
"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 });
//# sourceMappingURL=ConnectionTransport.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ConnectionTransport.js","sourceRoot":"","sources":["../../../../src/common/ConnectionTransport.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG"}

View File

@@ -0,0 +1,73 @@
/**
* 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.
*/
import { JSHandle } from './JSHandle.js';
/**
* @public
*/
export interface ConsoleMessageLocation {
/**
* URL of the resource if known or `undefined` otherwise.
*/
url?: string;
/**
* 0-based line number in the resource if known or `undefined` otherwise.
*/
lineNumber?: number;
/**
* 0-based column number in the resource if known or `undefined` otherwise.
*/
columnNumber?: number;
}
/**
* The supported types for console messages.
* @public
*/
export declare type ConsoleMessageType = 'log' | 'debug' | 'info' | 'error' | 'warning' | 'dir' | 'dirxml' | 'table' | 'trace' | 'clear' | 'startGroup' | 'startGroupCollapsed' | 'endGroup' | 'assert' | 'profile' | 'profileEnd' | 'count' | 'timeEnd' | 'verbose';
/**
* ConsoleMessage objects are dispatched by page via the 'console' event.
* @public
*/
export declare class ConsoleMessage {
private _type;
private _text;
private _args;
private _stackTraceLocations;
/**
* @public
*/
constructor(type: ConsoleMessageType, text: string, args: JSHandle[], stackTraceLocations: ConsoleMessageLocation[]);
/**
* @returns The type of the console message.
*/
type(): ConsoleMessageType;
/**
* @returns The text of the console message.
*/
text(): string;
/**
* @returns An array of arguments passed to the console.
*/
args(): JSHandle[];
/**
* @returns The location 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

View File

@@ -0,0 +1 @@
{"version":3,"file":"ConsoleMessage.d.ts","sourceRoot":"","sources":["../../../../src/common/ConsoleMessage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,oBAAY,kBAAkB,GAC1B,KAAK,GACL,OAAO,GACP,MAAM,GACN,OAAO,GACP,SAAS,GACT,KAAK,GACL,QAAQ,GACR,OAAO,GACP,OAAO,GACP,OAAO,GACP,YAAY,GACZ,qBAAqB,GACrB,UAAU,GACV,QAAQ,GACR,SAAS,GACT,YAAY,GACZ,OAAO,GACP,SAAS,GACT,SAAS,CAAC;AAEd;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,oBAAoB,CAA2B;IAEvD;;OAEG;gBAED,IAAI,EAAE,kBAAkB,EACxB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,QAAQ,EAAE,EAChB,mBAAmB,EAAE,sBAAsB,EAAE;IAQ/C;;OAEG;IACH,IAAI,IAAI,kBAAkB;IAI1B;;OAEG;IACH,IAAI,IAAI,MAAM;IAId;;OAEG;IACH,IAAI,IAAI,QAAQ,EAAE;IAIlB;;OAEG;IACH,QAAQ,IAAI,sBAAsB;IAIlC;;OAEG;IACH,UAAU,IAAI,sBAAsB,EAAE;CAGvC"}

View File

@@ -0,0 +1,65 @@
"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 });
exports.ConsoleMessage = void 0;
/**
* ConsoleMessage objects are dispatched by page via the 'console' event.
* @public
*/
class ConsoleMessage {
/**
* @public
*/
constructor(type, text, args, stackTraceLocations) {
this._type = type;
this._text = text;
this._args = args;
this._stackTraceLocations = stackTraceLocations;
}
/**
* @returns The type of the console message.
*/
type() {
return this._type;
}
/**
* @returns The text of the console message.
*/
text() {
return this._text;
}
/**
* @returns An array of arguments passed to the console.
*/
args() {
return this._args;
}
/**
* @returns The location of the console message.
*/
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;
//# sourceMappingURL=ConsoleMessage.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ConsoleMessage.js","sourceRoot":"","sources":["../../../../src/common/ConsoleMessage.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAiDH;;;GAGG;AACH,MAAa,cAAc;IAMzB;;OAEG;IACH,YACE,IAAwB,EACxB,IAAY,EACZ,IAAgB,EAChB,mBAA6C;QAE7C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,oBAAoB,GAAG,mBAAmB,CAAC;IAClD,CAAC;IAED;;OAEG;IACH,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED;;OAEG;IACH,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED;;OAEG;IACH,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,OAAO,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9E,CAAC;IAED;;OAEG;IACH,UAAU;QACR,OAAO,IAAI,CAAC,oBAAoB,CAAC;IACnC,CAAC;CACF;AAvDD,wCAuDC"}

View File

@@ -0,0 +1,205 @@
/**
* 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 { PuppeteerEventListener } from './helper.js';
import { Protocol } from 'devtools-protocol';
import { CDPSession } from './Connection.js';
/**
* @internal
*/
export { PuppeteerEventListener };
/**
* The CoverageEntry class represents one entry of the coverage report.
* @public
*/
export interface CoverageEntry {
/**
* The URL of the style sheet or script.
*/
url: string;
/**
* The content of the style sheet or script.
*/
text: string;
/**
* The covered range as start and end positions.
*/
ranges: Array<{
start: number;
end: number;
}>;
}
/**
* The CoverageEntry class for JavaScript
* @public
*/
export interface JSCoverageEntry extends CoverageEntry {
/**
* Raw V8 script coverage entry.
*/
rawScriptCoverage?: Protocol.Profiler.ScriptCoverage;
}
/**
* Set of configurable options for JS coverage.
* @public
*/
export interface JSCoverageOptions {
/**
* Whether to reset coverage on every navigation.
*/
resetOnNavigation?: boolean;
/**
* Whether anonymous scripts generated by the page should be reported.
*/
reportAnonymousScripts?: boolean;
/**
* Whether the result includes raw V8 script coverage entries.
*/
includeRawScriptCoverage?: boolean;
}
/**
* Set of configurable options for CSS coverage.
* @public
*/
export interface CSSCoverageOptions {
/**
* Whether to reset coverage on every navigation.
*/
resetOnNavigation?: boolean;
}
/**
* The Coverage class provides methods to gathers information about parts of
* JavaScript and CSS that were used by the page.
*
* @remarks
* To output coverage in a form consumable by {@link https://github.com/istanbuljs | Istanbul},
* see {@link https://github.com/istanbuljs/puppeteer-to-istanbul | puppeteer-to-istanbul}.
*
* @example
* An example of using JavaScript and CSS coverage to get percentage of initially
* executed code:
* ```js
* // Enable both JavaScript and CSS coverage
* await Promise.all([
* page.coverage.startJSCoverage(),
* page.coverage.startCSSCoverage()
* ]);
* // Navigate to page
* await page.goto('https://example.com');
* // Disable both JavaScript and CSS coverage
* const [jsCoverage, cssCoverage] = await Promise.all([
* page.coverage.stopJSCoverage(),
* page.coverage.stopCSSCoverage(),
* ]);
* let totalBytes = 0;
* let usedBytes = 0;
* const coverage = [...jsCoverage, ...cssCoverage];
* for (const entry of coverage) {
* totalBytes += entry.text.length;
* for (const range of entry.ranges)
* usedBytes += range.end - range.start - 1;
* }
* console.log(`Bytes used: ${usedBytes / totalBytes * 100}%`);
* ```
* @public
*/
export declare class Coverage {
/**
* @internal
*/
_jsCoverage: JSCoverage;
/**
* @internal
*/
_cssCoverage: CSSCoverage;
constructor(client: CDPSession);
/**
* @param options - Set of configurable options for coverage defaults to
* `resetOnNavigation : true, reportAnonymousScripts : false`
* @returns Promise that resolves when coverage is started.
*
* @remarks
* Anonymous scripts are ones that don't have an associated url. These are
* scripts that are dynamically created on the page using `eval` or
* `new Function`. If `reportAnonymousScripts` is set to `true`, anonymous
* scripts will have `__puppeteer_evaluation_script__` as their URL.
*/
startJSCoverage(options?: JSCoverageOptions): Promise<void>;
/**
* @returns Promise that resolves to the array of coverage reports for
* all scripts.
*
* @remarks
* JavaScript Coverage doesn't include anonymous scripts by default.
* However, scripts with sourceURLs are reported.
*/
stopJSCoverage(): Promise<JSCoverageEntry[]>;
/**
* @param options - Set of configurable options for coverage, defaults to
* `resetOnNavigation : true`
* @returns Promise that resolves when coverage is started.
*/
startCSSCoverage(options?: CSSCoverageOptions): Promise<void>;
/**
* @returns Promise that resolves to the array of coverage reports
* for all stylesheets.
* @remarks
* CSS Coverage doesn't include dynamically injected style tags
* without sourceURLs.
*/
stopCSSCoverage(): Promise<CoverageEntry[]>;
}
/**
* @public
*/
export declare class JSCoverage {
_client: CDPSession;
_enabled: boolean;
_scriptURLs: Map<string, string>;
_scriptSources: Map<string, string>;
_eventListeners: PuppeteerEventListener[];
_resetOnNavigation: boolean;
_reportAnonymousScripts: boolean;
_includeRawScriptCoverage: boolean;
constructor(client: CDPSession);
start(options?: {
resetOnNavigation?: boolean;
reportAnonymousScripts?: boolean;
includeRawScriptCoverage?: boolean;
}): Promise<void>;
_onExecutionContextsCleared(): void;
_onScriptParsed(event: Protocol.Debugger.ScriptParsedEvent): Promise<void>;
stop(): Promise<JSCoverageEntry[]>;
}
/**
* @public
*/
export declare class CSSCoverage {
_client: CDPSession;
_enabled: boolean;
_stylesheetURLs: Map<string, string>;
_stylesheetSources: Map<string, string>;
_eventListeners: PuppeteerEventListener[];
_resetOnNavigation: boolean;
_reportAnonymousScripts: boolean;
constructor(client: CDPSession);
start(options?: {
resetOnNavigation?: boolean;
}): Promise<void>;
_onExecutionContextsCleared(): void;
_onStyleSheet(event: Protocol.CSS.StyleSheetAddedEvent): Promise<void>;
stop(): Promise<CoverageEntry[]>;
}
//# sourceMappingURL=Coverage.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Coverage.d.ts","sourceRoot":"","sources":["../../../../src/common/Coverage.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,336 @@
"use strict";
/**
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.CSSCoverage = exports.JSCoverage = exports.Coverage = void 0;
const assert_js_1 = require("./assert.js");
const helper_js_1 = require("./helper.js");
const ExecutionContext_js_1 = require("./ExecutionContext.js");
/**
* The Coverage class provides methods to gathers information about parts of
* JavaScript and CSS that were used by the page.
*
* @remarks
* To output coverage in a form consumable by {@link https://github.com/istanbuljs | Istanbul},
* see {@link https://github.com/istanbuljs/puppeteer-to-istanbul | puppeteer-to-istanbul}.
*
* @example
* An example of using JavaScript and CSS coverage to get percentage of initially
* executed code:
* ```js
* // Enable both JavaScript and CSS coverage
* await Promise.all([
* page.coverage.startJSCoverage(),
* page.coverage.startCSSCoverage()
* ]);
* // Navigate to page
* await page.goto('https://example.com');
* // Disable both JavaScript and CSS coverage
* const [jsCoverage, cssCoverage] = await Promise.all([
* page.coverage.stopJSCoverage(),
* page.coverage.stopCSSCoverage(),
* ]);
* let totalBytes = 0;
* let usedBytes = 0;
* const coverage = [...jsCoverage, ...cssCoverage];
* for (const entry of coverage) {
* totalBytes += entry.text.length;
* for (const range of entry.ranges)
* usedBytes += range.end - range.start - 1;
* }
* console.log(`Bytes used: ${usedBytes / totalBytes * 100}%`);
* ```
* @public
*/
class Coverage {
constructor(client) {
this._jsCoverage = new JSCoverage(client);
this._cssCoverage = new CSSCoverage(client);
}
/**
* @param options - Set of configurable options for coverage defaults to
* `resetOnNavigation : true, reportAnonymousScripts : false`
* @returns Promise that resolves when coverage is started.
*
* @remarks
* Anonymous scripts are ones that don't have an associated url. These are
* scripts that are dynamically created on the page using `eval` or
* `new Function`. If `reportAnonymousScripts` is set to `true`, anonymous
* scripts will have `__puppeteer_evaluation_script__` as their URL.
*/
async startJSCoverage(options = {}) {
return await this._jsCoverage.start(options);
}
/**
* @returns Promise that resolves to the array of coverage reports for
* all scripts.
*
* @remarks
* JavaScript Coverage doesn't include anonymous scripts by default.
* However, scripts with sourceURLs are reported.
*/
async stopJSCoverage() {
return await this._jsCoverage.stop();
}
/**
* @param options - Set of configurable options for coverage, defaults to
* `resetOnNavigation : true`
* @returns Promise that resolves when coverage is started.
*/
async startCSSCoverage(options = {}) {
return await this._cssCoverage.start(options);
}
/**
* @returns Promise that resolves to the array of coverage reports
* for all stylesheets.
* @remarks
* CSS Coverage doesn't include dynamically injected style tags
* without sourceURLs.
*/
async stopCSSCoverage() {
return await this._cssCoverage.stop();
}
}
exports.Coverage = Coverage;
/**
* @public
*/
class JSCoverage {
constructor(client) {
this._enabled = false;
this._scriptURLs = new Map();
this._scriptSources = new Map();
this._eventListeners = [];
this._resetOnNavigation = false;
this._reportAnonymousScripts = false;
this._includeRawScriptCoverage = false;
this._client = client;
}
async start(options = {}) {
(0, assert_js_1.assert)(!this._enabled, 'JSCoverage is already enabled');
const { resetOnNavigation = true, reportAnonymousScripts = false, includeRawScriptCoverage = false, } = options;
this._resetOnNavigation = resetOnNavigation;
this._reportAnonymousScripts = reportAnonymousScripts;
this._includeRawScriptCoverage = includeRawScriptCoverage;
this._enabled = true;
this._scriptURLs.clear();
this._scriptSources.clear();
this._eventListeners = [
helper_js_1.helper.addEventListener(this._client, 'Debugger.scriptParsed', this._onScriptParsed.bind(this)),
helper_js_1.helper.addEventListener(this._client, 'Runtime.executionContextsCleared', this._onExecutionContextsCleared.bind(this)),
];
await Promise.all([
this._client.send('Profiler.enable'),
this._client.send('Profiler.startPreciseCoverage', {
callCount: this._includeRawScriptCoverage,
detailed: true,
}),
this._client.send('Debugger.enable'),
this._client.send('Debugger.setSkipAllPauses', { skip: true }),
]);
}
_onExecutionContextsCleared() {
if (!this._resetOnNavigation)
return;
this._scriptURLs.clear();
this._scriptSources.clear();
}
async _onScriptParsed(event) {
// Ignore puppeteer-injected scripts
if (event.url === ExecutionContext_js_1.EVALUATION_SCRIPT_URL)
return;
// Ignore other anonymous scripts unless the reportAnonymousScripts option is true.
if (!event.url && !this._reportAnonymousScripts)
return;
try {
const response = await this._client.send('Debugger.getScriptSource', {
scriptId: event.scriptId,
});
this._scriptURLs.set(event.scriptId, event.url);
this._scriptSources.set(event.scriptId, response.scriptSource);
}
catch (error) {
// This might happen if the page has already navigated away.
(0, helper_js_1.debugError)(error);
}
}
async stop() {
(0, assert_js_1.assert)(this._enabled, 'JSCoverage is not enabled');
this._enabled = false;
const result = await Promise.all([
this._client.send('Profiler.takePreciseCoverage'),
this._client.send('Profiler.stopPreciseCoverage'),
this._client.send('Profiler.disable'),
this._client.send('Debugger.disable'),
]);
helper_js_1.helper.removeEventListeners(this._eventListeners);
const coverage = [];
const profileResponse = result[0];
for (const entry of profileResponse.result) {
let url = this._scriptURLs.get(entry.scriptId);
if (!url && this._reportAnonymousScripts)
url = 'debugger://VM' + entry.scriptId;
const text = this._scriptSources.get(entry.scriptId);
if (text === undefined || url === undefined)
continue;
const flattenRanges = [];
for (const func of entry.functions)
flattenRanges.push(...func.ranges);
const ranges = convertToDisjointRanges(flattenRanges);
if (!this._includeRawScriptCoverage) {
coverage.push({ url, ranges, text });
}
else {
coverage.push({ url, ranges, text, rawScriptCoverage: entry });
}
}
return coverage;
}
}
exports.JSCoverage = JSCoverage;
/**
* @public
*/
class CSSCoverage {
constructor(client) {
this._enabled = false;
this._stylesheetURLs = new Map();
this._stylesheetSources = new Map();
this._eventListeners = [];
this._resetOnNavigation = false;
this._reportAnonymousScripts = false;
this._client = client;
}
async start(options = {}) {
(0, assert_js_1.assert)(!this._enabled, 'CSSCoverage is already enabled');
const { resetOnNavigation = true } = options;
this._resetOnNavigation = resetOnNavigation;
this._enabled = true;
this._stylesheetURLs.clear();
this._stylesheetSources.clear();
this._eventListeners = [
helper_js_1.helper.addEventListener(this._client, 'CSS.styleSheetAdded', this._onStyleSheet.bind(this)),
helper_js_1.helper.addEventListener(this._client, 'Runtime.executionContextsCleared', this._onExecutionContextsCleared.bind(this)),
];
await Promise.all([
this._client.send('DOM.enable'),
this._client.send('CSS.enable'),
this._client.send('CSS.startRuleUsageTracking'),
]);
}
_onExecutionContextsCleared() {
if (!this._resetOnNavigation)
return;
this._stylesheetURLs.clear();
this._stylesheetSources.clear();
}
async _onStyleSheet(event) {
const header = event.header;
// Ignore anonymous scripts
if (!header.sourceURL)
return;
try {
const response = await this._client.send('CSS.getStyleSheetText', {
styleSheetId: header.styleSheetId,
});
this._stylesheetURLs.set(header.styleSheetId, header.sourceURL);
this._stylesheetSources.set(header.styleSheetId, response.text);
}
catch (error) {
// This might happen if the page has already navigated away.
(0, helper_js_1.debugError)(error);
}
}
async stop() {
(0, assert_js_1.assert)(this._enabled, 'CSSCoverage is not enabled');
this._enabled = false;
const ruleTrackingResponse = await this._client.send('CSS.stopRuleUsageTracking');
await Promise.all([
this._client.send('CSS.disable'),
this._client.send('DOM.disable'),
]);
helper_js_1.helper.removeEventListeners(this._eventListeners);
// aggregate by styleSheetId
const styleSheetIdToCoverage = new Map();
for (const entry of ruleTrackingResponse.ruleUsage) {
let ranges = styleSheetIdToCoverage.get(entry.styleSheetId);
if (!ranges) {
ranges = [];
styleSheetIdToCoverage.set(entry.styleSheetId, ranges);
}
ranges.push({
startOffset: entry.startOffset,
endOffset: entry.endOffset,
count: entry.used ? 1 : 0,
});
}
const coverage = [];
for (const styleSheetId of this._stylesheetURLs.keys()) {
const url = this._stylesheetURLs.get(styleSheetId);
const text = this._stylesheetSources.get(styleSheetId);
const ranges = convertToDisjointRanges(styleSheetIdToCoverage.get(styleSheetId) || []);
coverage.push({ url, ranges, text });
}
return coverage;
}
}
exports.CSSCoverage = CSSCoverage;
function convertToDisjointRanges(nestedRanges) {
const points = [];
for (const range of nestedRanges) {
points.push({ offset: range.startOffset, type: 0, range });
points.push({ offset: range.endOffset, type: 1, range });
}
// Sort points to form a valid parenthesis sequence.
points.sort((a, b) => {
// Sort with increasing offsets.
if (a.offset !== b.offset)
return a.offset - b.offset;
// All "end" points should go before "start" points.
if (a.type !== b.type)
return b.type - a.type;
const aLength = a.range.endOffset - a.range.startOffset;
const bLength = b.range.endOffset - b.range.startOffset;
// For two "start" points, the one with longer range goes first.
if (a.type === 0)
return bLength - aLength;
// For two "end" points, the one with shorter range goes first.
return aLength - bLength;
});
const hitCountStack = [];
const results = [];
let lastOffset = 0;
// Run scanning line to intersect all ranges.
for (const point of points) {
if (hitCountStack.length &&
lastOffset < point.offset &&
hitCountStack[hitCountStack.length - 1] > 0) {
const lastResult = results.length ? results[results.length - 1] : null;
if (lastResult && lastResult.end === lastOffset)
lastResult.end = point.offset;
else
results.push({ start: lastOffset, end: point.offset });
}
lastOffset = point.offset;
if (point.type === 0)
hitCountStack.push(point.range.count);
else
hitCountStack.pop();
}
// Filter out empty ranges.
return results.filter((range) => range.end - range.start > 1);
}
//# sourceMappingURL=Coverage.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,181 @@
/**
* Copyright 2019 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.
*/
/// <reference types="node" />
import { PuppeteerLifeCycleEvent } from './LifecycleWatcher.js';
import { JSHandle, ElementHandle } from './JSHandle.js';
import { ExecutionContext } from './ExecutionContext.js';
import { TimeoutSettings } from './TimeoutSettings.js';
import { MouseButton } from './Input.js';
import { FrameManager, Frame } from './FrameManager.js';
import { SerializableOrJSHandle, EvaluateHandleFn, WrapElementHandle, EvaluateFn, EvaluateFnReturnType, UnwrapPromiseLike } from './EvalTypes.js';
import { CDPSession } from './Connection.js';
/**
* @public
*/
export interface WaitForSelectorOptions {
visible?: boolean;
hidden?: boolean;
timeout?: number;
root?: ElementHandle;
}
/**
* @internal
*/
export interface PageBinding {
name: string;
pptrFunction: Function;
}
/**
* @internal
*/
export declare class DOMWorld {
private _frameManager;
private _client;
private _frame;
private _timeoutSettings;
private _documentPromise?;
private _contextPromise?;
private _contextResolveCallback?;
private _detached;
/**
* @internal
*/
_waitTasks: Set<WaitTask>;
/**
* @internal
* Contains mapping from functions that should be bound to Puppeteer functions.
*/
_boundFunctions: Map<string, Function>;
private _ctxBindings;
private static bindingIdentifier;
constructor(client: CDPSession, frameManager: FrameManager, frame: Frame, timeoutSettings: TimeoutSettings);
frame(): Frame;
_setContext(context?: ExecutionContext): Promise<void>;
_hasContext(): boolean;
_detach(): void;
executionContext(): Promise<ExecutionContext>;
evaluateHandle<HandlerType extends JSHandle = JSHandle>(pageFunction: EvaluateHandleFn, ...args: SerializableOrJSHandle[]): Promise<HandlerType>;
evaluate<T extends EvaluateFn>(pageFunction: T, ...args: SerializableOrJSHandle[]): Promise<UnwrapPromiseLike<EvaluateFnReturnType<T>>>;
$<T extends Element = Element>(selector: string): Promise<ElementHandle<T> | null>;
_document(): Promise<ElementHandle>;
$x(expression: string): Promise<ElementHandle[]>;
$eval<ReturnType>(selector: string, pageFunction: (element: Element, ...args: unknown[]) => ReturnType | Promise<ReturnType>, ...args: SerializableOrJSHandle[]): Promise<WrapElementHandle<ReturnType>>;
$$eval<ReturnType>(selector: string, pageFunction: (elements: Element[], ...args: unknown[]) => ReturnType | Promise<ReturnType>, ...args: SerializableOrJSHandle[]): Promise<WrapElementHandle<ReturnType>>;
$$<T extends Element = Element>(selector: string): Promise<Array<ElementHandle<T>>>;
content(): Promise<string>;
setContent(html: string, options?: {
timeout?: number;
waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[];
}): Promise<void>;
/**
* Adds a script tag into the current context.
*
* @remarks
*
* You can pass a URL, filepath or string of contents. Note that when running Puppeteer
* in a browser environment you cannot pass a filepath and should use either
* `url` or `content`.
*/
addScriptTag(options: {
url?: string;
path?: string;
content?: string;
id?: string;
type?: string;
}): Promise<ElementHandle>;
/**
* Adds a style tag into the current context.
*
* @remarks
*
* You can pass a URL, filepath or string of contents. Note that when running Puppeteer
* in a browser environment you cannot pass a filepath and should use either
* `url` or `content`.
*
*/
addStyleTag(options: {
url?: string;
path?: string;
content?: string;
}): Promise<ElementHandle>;
click(selector: string, options: {
delay?: number;
button?: MouseButton;
clickCount?: number;
}): Promise<void>;
focus(selector: string): Promise<void>;
hover(selector: string): Promise<void>;
select(selector: string, ...values: string[]): Promise<string[]>;
tap(selector: string): Promise<void>;
type(selector: string, text: string, options?: {
delay: number;
}): Promise<void>;
waitForSelector(selector: string, options: WaitForSelectorOptions): Promise<ElementHandle | null>;
private _settingUpBinding;
/**
* @internal
*/
addBindingToContext(context: ExecutionContext, name: string): Promise<void>;
private _onBindingCalled;
/**
* @internal
*/
waitForSelectorInPage(queryOne: Function, selector: string, options: WaitForSelectorOptions, binding?: PageBinding): Promise<ElementHandle | null>;
waitForXPath(xpath: string, options: WaitForSelectorOptions): Promise<ElementHandle | null>;
waitForFunction(pageFunction: Function | string, options?: {
polling?: string | number;
timeout?: number;
}, ...args: SerializableOrJSHandle[]): Promise<JSHandle>;
title(): Promise<string>;
}
/**
* @internal
*/
export interface WaitTaskOptions {
domWorld: DOMWorld;
predicateBody: Function | string;
predicateAcceptsContextElement: boolean;
title: string;
polling: string | number;
timeout: number;
binding?: PageBinding;
args: SerializableOrJSHandle[];
root?: ElementHandle;
}
/**
* @internal
*/
export declare class WaitTask {
_domWorld: DOMWorld;
_polling: string | number;
_timeout: number;
_predicateBody: string;
_predicateAcceptsContextElement: boolean;
_args: SerializableOrJSHandle[];
_binding: PageBinding;
_runCount: number;
promise: Promise<JSHandle>;
_resolve: (x: JSHandle) => void;
_reject: (x: Error) => void;
_timeoutTimer?: NodeJS.Timeout;
_terminated: boolean;
_root: ElementHandle;
constructor(options: WaitTaskOptions);
terminate(error: Error): void;
rerun(): Promise<void>;
_cleanup(): void;
}
//# sourceMappingURL=DOMWorld.d.ts.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,683 @@
"use strict";
/**
* Copyright 2019 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 });
exports.WaitTask = exports.DOMWorld = void 0;
const assert_js_1 = require("./assert.js");
const helper_js_1 = require("./helper.js");
const LifecycleWatcher_js_1 = require("./LifecycleWatcher.js");
const Errors_js_1 = require("./Errors.js");
const QueryHandler_js_1 = require("./QueryHandler.js");
const environment_js_1 = require("../environment.js");
/**
* @internal
*/
class DOMWorld {
constructor(client, frameManager, frame, timeoutSettings) {
this._documentPromise = null;
this._contextPromise = null;
this._contextResolveCallback = null;
this._detached = false;
/**
* @internal
*/
this._waitTasks = new Set();
/**
* @internal
* 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;
// Keep own reference to client because it might differ from the FrameManager's
// client for OOP iframes.
this._client = client;
this._frameManager = frameManager;
this._frame = frame;
this._timeoutSettings = timeoutSettings;
this._setContext(null);
this._onBindingCalled = this._onBindingCalled.bind(this);
this._client.on('Runtime.bindingCalled', this._onBindingCalled);
}
frame() {
return this._frame;
}
async _setContext(context) {
if (context) {
(0, assert_js_1.assert)(this._contextResolveCallback, 'Execution Context has already been set.');
this._ctxBindings.clear();
this._contextResolveCallback.call(null, context);
this._contextResolveCallback = null;
for (const waitTask of this._waitTasks)
waitTask.rerun();
}
else {
this._documentPromise = null;
this._contextPromise = new Promise((fulfill) => {
this._contextResolveCallback = fulfill;
});
}
}
_hasContext() {
return !this._contextResolveCallback;
}
_detach() {
this._detached = true;
this._client.off('Runtime.bindingCalled', this._onBindingCalled);
for (const waitTask of this._waitTasks)
waitTask.terminate(new Error('waitForFunction failed: frame got detached.'));
}
executionContext() {
if (this._detached)
throw new Error(`Execution context is not available in detached frame "${this._frame.url()}" (are you trying to evaluate?)`);
return this._contextPromise;
}
async evaluateHandle(pageFunction, ...args) {
const context = await this.executionContext();
return context.evaluateHandle(pageFunction, ...args);
}
async evaluate(pageFunction, ...args) {
const context = await this.executionContext();
return context.evaluate(pageFunction, ...args);
}
async $(selector) {
const document = await this._document();
const value = await document.$(selector);
return value;
}
async _document() {
if (this._documentPromise)
return this._documentPromise;
this._documentPromise = this.executionContext().then(async (context) => {
const document = await context.evaluateHandle('document');
return document.asElement();
});
return this._documentPromise;
}
async $x(expression) {
const document = await this._document();
const value = await document.$x(expression);
return value;
}
async $eval(selector, pageFunction, ...args) {
const document = await this._document();
return document.$eval(selector, pageFunction, ...args);
}
async $$eval(selector, pageFunction, ...args) {
const document = await this._document();
const value = await document.$$eval(selector, pageFunction, ...args);
return value;
}
async $$(selector) {
const document = await this._document();
const value = await document.$$(selector);
return value;
}
async content() {
return await this.evaluate(() => {
let retVal = '';
if (document.doctype)
retVal = new XMLSerializer().serializeToString(document.doctype);
if (document.documentElement)
retVal += document.documentElement.outerHTML;
return retVal;
});
}
async setContent(html, options = {}) {
const { waitUntil = ['load'], timeout = this._timeoutSettings.navigationTimeout(), } = options;
// We rely upon the fact that document.open() will reset frame lifecycle with "init"
// lifecycle event. @see https://crrev.com/608658
await this.evaluate((html) => {
document.open();
document.write(html);
document.close();
}, html);
const watcher = new LifecycleWatcher_js_1.LifecycleWatcher(this._frameManager, this._frame, waitUntil, timeout);
const error = await Promise.race([
watcher.timeoutOrTerminationPromise(),
watcher.lifecyclePromise(),
]);
watcher.dispose();
if (error)
throw error;
}
/**
* Adds a script tag into the current context.
*
* @remarks
*
* You can pass a URL, filepath or string of contents. Note that when running Puppeteer
* in a browser environment you cannot pass a filepath and should use either
* `url` or `content`.
*/
async addScriptTag(options) {
const { url = null, path = null, content = null, id = '', type = '', } = options;
if (url !== null) {
try {
const context = await this.executionContext();
return (await context.evaluateHandle(addScriptUrl, url, id, type)).asElement();
}
catch (error) {
throw new Error(`Loading script from ${url} failed`);
}
}
if (path !== null) {
if (!environment_js_1.isNode) {
throw new Error('Cannot pass a filepath to addScriptTag in the browser environment.');
}
const fs = await helper_js_1.helper.importFSModule();
let contents = await fs.promises.readFile(path, 'utf8');
contents += '//# sourceURL=' + path.replace(/\n/g, '');
const context = await this.executionContext();
return (await context.evaluateHandle(addScriptContent, contents, id, type)).asElement();
}
if (content !== null) {
const context = await this.executionContext();
return (await context.evaluateHandle(addScriptContent, content, id, type)).asElement();
}
throw new Error('Provide an object with a `url`, `path` or `content` property');
async function addScriptUrl(url, id, type) {
const script = document.createElement('script');
script.src = url;
if (id)
script.id = id;
if (type)
script.type = type;
const promise = new Promise((res, rej) => {
script.onload = res;
script.onerror = rej;
});
document.head.appendChild(script);
await promise;
return script;
}
function addScriptContent(content, id, type = 'text/javascript') {
const script = document.createElement('script');
script.type = type;
script.text = content;
if (id)
script.id = id;
let error = null;
script.onerror = (e) => (error = e);
document.head.appendChild(script);
if (error)
throw error;
return script;
}
}
/**
* Adds a style tag into the current context.
*
* @remarks
*
* You can pass a URL, filepath or string of contents. Note that when running Puppeteer
* in a browser environment you cannot pass a filepath and should use either
* `url` or `content`.
*
*/
async addStyleTag(options) {
const { url = null, path = null, content = null } = options;
if (url !== null) {
try {
const context = await this.executionContext();
return (await context.evaluateHandle(addStyleUrl, url)).asElement();
}
catch (error) {
throw new Error(`Loading style from ${url} failed`);
}
}
if (path !== null) {
if (!environment_js_1.isNode) {
throw new Error('Cannot pass a filepath to addStyleTag in the browser environment.');
}
const fs = await helper_js_1.helper.importFSModule();
let contents = await fs.promises.readFile(path, 'utf8');
contents += '/*# sourceURL=' + path.replace(/\n/g, '') + '*/';
const context = await this.executionContext();
return (await context.evaluateHandle(addStyleContent, contents)).asElement();
}
if (content !== null) {
const context = await this.executionContext();
return (await context.evaluateHandle(addStyleContent, content)).asElement();
}
throw new Error('Provide an object with a `url`, `path` or `content` property');
async function addStyleUrl(url) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = url;
const promise = new Promise((res, rej) => {
link.onload = res;
link.onerror = rej;
});
document.head.appendChild(link);
await promise;
return link;
}
async function addStyleContent(content) {
const style = document.createElement('style');
style.type = 'text/css';
style.appendChild(document.createTextNode(content));
const promise = new Promise((res, rej) => {
style.onload = res;
style.onerror = rej;
});
document.head.appendChild(style);
await promise;
return style;
}
}
async click(selector, options) {
const handle = await this.$(selector);
(0, assert_js_1.assert)(handle, 'No node found for selector: ' + selector);
await handle.click(options);
await handle.dispose();
}
async focus(selector) {
const handle = await this.$(selector);
(0, assert_js_1.assert)(handle, 'No node found for selector: ' + selector);
await handle.focus();
await handle.dispose();
}
async hover(selector) {
const handle = await this.$(selector);
(0, assert_js_1.assert)(handle, 'No node found for selector: ' + selector);
await handle.hover();
await handle.dispose();
}
async select(selector, ...values) {
const handle = await this.$(selector);
(0, assert_js_1.assert)(handle, 'No node found for selector: ' + selector);
const result = await handle.select(...values);
await handle.dispose();
return result;
}
async tap(selector) {
const handle = await this.$(selector);
await handle.tap();
await handle.dispose();
}
async type(selector, text, options) {
const handle = await this.$(selector);
(0, assert_js_1.assert)(handle, 'No node found for selector: ' + selector);
await handle.type(text, options);
await handle.dispose();
}
async waitForSelector(selector, options) {
const { updatedSelector, queryHandler } = (0, QueryHandler_js_1.getQueryHandlerAndSelector)(selector);
return queryHandler.waitFor(this, updatedSelector, options);
}
/**
* @internal
*/
async addBindingToContext(context, name) {
// Previous operation added the binding so we are done.
if (this._ctxBindings.has(DOMWorld.bindingIdentifier(name, context._contextId))) {
return;
}
// Wait for other operation to finish
if (this._settingUpBinding) {
await this._settingUpBinding;
return this.addBindingToContext(context, name);
}
const bind = async (name) => {
const expression = helper_js_1.helper.pageBindingInitString('internal', name);
try {
// TODO: In theory, it would be enough to call this just once
await context._client.send('Runtime.addBinding', {
name,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore The protocol definition is not up to date.
executionContextName: context._contextName,
});
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) {
return;
}
else {
(0, helper_js_1.debugError)(error);
return;
}
}
this._ctxBindings.add(DOMWorld.bindingIdentifier(name, context._contextId));
};
this._settingUpBinding = bind(name);
await this._settingUpBinding;
this._settingUpBinding = null;
}
async _onBindingCalled(event) {
let payload;
if (!this._hasContext())
return;
const context = await this.executionContext();
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(DOMWorld.bindingIdentifier(name, context._contextId)))
return;
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;
(0, 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, binding) {
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' : ''}`;
async function predicate(root, selector, waitForVisible, waitForHidden) {
const node = predicateQueryHandler
? (await predicateQueryHandler(root, selector))
: root.querySelector(selector);
return checkWaitForOptions(node, waitForVisible, waitForHidden);
}
const waitTaskOptions = {
domWorld: this,
predicateBody: helper_js_1.helper.makePredicateString(predicate, queryOne),
predicateAcceptsContextElement: true,
title,
polling,
timeout,
args: [selector, waitForVisible, waitForHidden],
binding,
root: options.root,
};
const waitTask = new WaitTask(waitTaskOptions);
const jsHandle = await waitTask.promise;
const elementHandle = jsHandle.asElement();
if (!elementHandle) {
await jsHandle.dispose();
return null;
}
return elementHandle;
}
async waitForXPath(xpath, options) {
const { visible: waitForVisible = false, hidden: waitForHidden = false, timeout = this._timeoutSettings.timeout(), } = options;
const polling = waitForVisible || waitForHidden ? 'raf' : 'mutation';
const title = `XPath \`${xpath}\`${waitForHidden ? ' to be hidden' : ''}`;
function predicate(root, xpath, waitForVisible, waitForHidden) {
const node = document.evaluate(xpath, root, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
return checkWaitForOptions(node, waitForVisible, waitForHidden);
}
const waitTaskOptions = {
domWorld: this,
predicateBody: helper_js_1.helper.makePredicateString(predicate),
predicateAcceptsContextElement: true,
title,
polling,
timeout,
args: [xpath, waitForVisible, waitForHidden],
root: options.root,
};
const waitTask = new WaitTask(waitTaskOptions);
const jsHandle = await waitTask.promise;
const elementHandle = jsHandle.asElement();
if (!elementHandle) {
await jsHandle.dispose();
return null;
}
return elementHandle;
}
waitForFunction(pageFunction, options = {}, ...args) {
const { polling = 'raf', timeout = this._timeoutSettings.timeout() } = options;
const waitTaskOptions = {
domWorld: this,
predicateBody: pageFunction,
predicateAcceptsContextElement: false,
title: 'function',
polling,
timeout,
args,
};
const waitTask = new WaitTask(waitTaskOptions);
return waitTask.promise;
}
async title() {
return this.evaluate(() => document.title);
}
}
exports.DOMWorld = DOMWorld;
DOMWorld.bindingIdentifier = (name, contextId) => `${name}_${contextId}`;
/**
* @internal
*/
class WaitTask {
constructor(options) {
this._runCount = 0;
this._terminated = false;
this._root = null;
if (helper_js_1.helper.isString(options.polling))
(0, assert_js_1.assert)(options.polling === 'raf' || options.polling === 'mutation', 'Unknown polling option: ' + options.polling);
else if (helper_js_1.helper.isNumber(options.polling))
(0, assert_js_1.assert)(options.polling > 0, 'Cannot poll with non-positive interval: ' + options.polling);
else
throw new Error('Unknown polling options: ' + options.polling);
function getPredicateBody(predicateBody) {
if (helper_js_1.helper.isString(predicateBody))
return `return (${predicateBody});`;
return `return (${predicateBody})(...args);`;
}
this._domWorld = options.domWorld;
this._polling = options.polling;
this._timeout = options.timeout;
this._root = options.root;
this._predicateBody = getPredicateBody(options.predicateBody);
this._predicateAcceptsContextElement =
options.predicateAcceptsContextElement;
this._args = options.args;
this._binding = options.binding;
this._runCount = 0;
this._domWorld._waitTasks.add(this);
if (this._binding) {
this._domWorld._boundFunctions.set(this._binding.name, this._binding.pptrFunction);
}
this.promise = new Promise((resolve, reject) => {
this._resolve = resolve;
this._reject = reject;
});
// Since page navigation requires us to re-install the pageScript, we should track
// timeout on our end.
if (options.timeout) {
const timeoutError = new Errors_js_1.TimeoutError(`waiting for ${options.title} failed: timeout ${options.timeout}ms exceeded`);
this._timeoutTimer = setTimeout(() => this.terminate(timeoutError), options.timeout);
}
this.rerun();
}
terminate(error) {
this._terminated = true;
this._reject(error);
this._cleanup();
}
async rerun() {
const runCount = ++this._runCount;
let success = null;
let error = null;
const context = await this._domWorld.executionContext();
if (this._terminated || runCount !== this._runCount)
return;
if (this._binding) {
await this._domWorld.addBindingToContext(context, this._binding.name);
}
if (this._terminated || runCount !== this._runCount)
return;
try {
success = await context.evaluateHandle(waitForPredicatePageFunction, this._root || null, this._predicateBody, this._predicateAcceptsContextElement, this._polling, this._timeout, ...this._args);
}
catch (error_) {
error = error_;
}
if (this._terminated || runCount !== this._runCount) {
if (success)
await success.dispose();
return;
}
// Ignore timeouts in pageScript - we track timeouts ourselves.
// If the frame's execution context has already changed, `frame.evaluate` will
// throw an error - ignore this predicate run altogether.
if (!error &&
(await this._domWorld.evaluate((s) => !s, success).catch(() => true))) {
await success.dispose();
return;
}
if (error) {
if (error.message.includes('TypeError: binding is not a function')) {
return this.rerun();
}
// 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.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 {
this._resolve(success);
}
this._cleanup();
}
_cleanup() {
clearTimeout(this._timeoutTimer);
this._domWorld._waitTasks.delete(this);
}
}
exports.WaitTask = WaitTask;
async function waitForPredicatePageFunction(root, predicateBody, predicateAcceptsContextElement, polling, timeout, ...args) {
root = root || document;
const predicate = new Function('...args', predicateBody);
let timedOut = false;
if (timeout)
setTimeout(() => (timedOut = true), timeout);
if (polling === 'raf')
return await pollRaf();
if (polling === 'mutation')
return await pollMutation();
if (typeof polling === 'number')
return await pollInterval(polling);
/**
* @returns {!Promise<*>}
*/
async function pollMutation() {
const success = predicateAcceptsContextElement
? await predicate(root, ...args)
: await predicate(...args);
if (success)
return Promise.resolve(success);
let fulfill;
const result = new Promise((x) => (fulfill = x));
const observer = new MutationObserver(async () => {
if (timedOut) {
observer.disconnect();
fulfill();
}
const success = predicateAcceptsContextElement
? await predicate(root, ...args)
: await predicate(...args);
if (success) {
observer.disconnect();
fulfill(success);
}
});
observer.observe(root, {
childList: true,
subtree: true,
attributes: true,
});
return result;
}
async function pollRaf() {
let fulfill;
const result = new Promise((x) => (fulfill = x));
await onRaf();
return result;
async function onRaf() {
if (timedOut) {
fulfill();
return;
}
const success = predicateAcceptsContextElement
? await predicate(root, ...args)
: await predicate(...args);
if (success)
fulfill(success);
else
requestAnimationFrame(onRaf);
}
}
async function pollInterval(pollInterval) {
let fulfill;
const result = new Promise((x) => (fulfill = x));
await onTimeout();
return result;
async function onTimeout() {
if (timedOut) {
fulfill();
return;
}
const success = predicateAcceptsContextElement
? await predicate(root, ...args)
: await predicate(...args);
if (success)
fulfill(success);
else
setTimeout(onTimeout, pollInterval);
}
}
}
//# sourceMappingURL=DOMWorld.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,53 @@
/**
* 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.
*/
/**
* A debug function that can be used in any environment.
*
* @remarks
*
* If used in Node, it falls back to the
* {@link https://www.npmjs.com/package/debug | debug module}. In the browser it
* uses `console.log`.
*
* @param prefix - this will be prefixed to each log.
* @returns a function that can be called to log to that debug channel.
*
* In Node, use the `DEBUG` environment variable to control logging:
*
* ```
* DEBUG=* // logs all channels
* DEBUG=foo // logs the `foo` channel
* DEBUG=foo* // logs any channels starting with `foo`
* ```
*
* In the browser, set `window.__PUPPETEER_DEBUG` to a string:
*
* ```
* window.__PUPPETEER_DEBUG='*'; // logs all channels
* window.__PUPPETEER_DEBUG='foo'; // logs the `foo` channel
* window.__PUPPETEER_DEBUG='foo*'; // logs any channels starting with `foo`
* ```
*
* @example
* ```
* const log = debug('Page');
*
* log('new page created')
* // logs "Page: new page created"
* ```
*/
export declare const debug: (prefix: string) => (...args: unknown[]) => void;
//# sourceMappingURL=Debug.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Debug.d.ts","sourceRoot":"","sources":["../../../../src/common/Debug.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,KAAK,WAAY,MAAM,eAAc,OAAO,EAAE,KAAK,IA4B/D,CAAC"}

View File

@@ -0,0 +1,82 @@
"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 });
exports.debug = void 0;
const environment_js_1 = require("../environment.js");
/**
* A debug function that can be used in any environment.
*
* @remarks
*
* If used in Node, it falls back to the
* {@link https://www.npmjs.com/package/debug | debug module}. In the browser it
* uses `console.log`.
*
* @param prefix - this will be prefixed to each log.
* @returns a function that can be called to log to that debug channel.
*
* In Node, use the `DEBUG` environment variable to control logging:
*
* ```
* DEBUG=* // logs all channels
* DEBUG=foo // logs the `foo` channel
* DEBUG=foo* // logs any channels starting with `foo`
* ```
*
* In the browser, set `window.__PUPPETEER_DEBUG` to a string:
*
* ```
* window.__PUPPETEER_DEBUG='*'; // logs all channels
* window.__PUPPETEER_DEBUG='foo'; // logs the `foo` channel
* window.__PUPPETEER_DEBUG='foo*'; // logs any channels starting with `foo`
* ```
*
* @example
* ```
* const log = debug('Page');
*
* log('new page created')
* // logs "Page: new page created"
* ```
*/
const debug = (prefix) => {
if (environment_js_1.isNode) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
return require('debug')(prefix);
}
return (...logArgs) => {
const debugLevel = globalThis.__PUPPETEER_DEBUG;
if (!debugLevel)
return;
const everythingShouldBeLogged = debugLevel === '*';
const prefixMatchesDebugLevel = everythingShouldBeLogged ||
/**
* If the debug level is `foo*`, that means we match any prefix that
* starts with `foo`. If the level is `foo`, we match only the prefix
* `foo`.
*/
(debugLevel.endsWith('*')
? prefix.startsWith(debugLevel)
: prefix === debugLevel);
if (!prefixMatchesDebugLevel)
return;
// eslint-disable-next-line no-console
console.log(`${prefix}:`, ...logArgs);
};
};
exports.debug = debug;
//# sourceMappingURL=Debug.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Debug.js","sourceRoot":"","sources":["../../../../src/common/Debug.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAEH,sDAA2C;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACI,MAAM,KAAK,GAAG,CAAC,MAAc,EAAkC,EAAE;IACtE,IAAI,uBAAM,EAAE;QACV,8DAA8D;QAC9D,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;KACjC;IAED,OAAO,CAAC,GAAG,OAAkB,EAAQ,EAAE;QACrC,MAAM,UAAU,GAAG,UAAU,CAAC,iBAA2B,CAAC;QAC1D,IAAI,CAAC,UAAU;YAAE,OAAO;QAExB,MAAM,wBAAwB,GAAG,UAAU,KAAK,GAAG,CAAC;QAEpD,MAAM,uBAAuB,GAC3B,wBAAwB;YACxB;;;;eAIG;YACH,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC;gBACvB,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC;gBAC/B,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC;QAE7B,IAAI,CAAC,uBAAuB;YAAE,OAAO;QAErC,sCAAsC;QACtC,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC;IACxC,CAAC,CAAC;AACJ,CAAC,CAAC;AA5BW,QAAA,KAAK,SA4BhB"}

View File

@@ -0,0 +1,41 @@
/**
* 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.
*/
/**
* @public
*/
export interface Device {
name: string;
userAgent: string;
viewport: {
width: number;
height: number;
deviceScaleFactor: number;
isMobile: boolean;
hasTouch: boolean;
isLandscape: boolean;
};
}
/**
* @public
*/
export declare type DevicesMap = {
[name: string]: Device;
};
/**
* @internal
*/
export declare const devicesMap: DevicesMap;
//# sourceMappingURL=DeviceDescriptors.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"DeviceDescriptors.d.ts","sourceRoot":"","sources":["../../../../src/common/DeviceDescriptors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE;QACR,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,iBAAiB,EAAE,MAAM,CAAC;QAC1B,QAAQ,EAAE,OAAO,CAAC;QAClB,QAAQ,EAAE,OAAO,CAAC;QAClB,WAAW,EAAE,OAAO,CAAC;KACtB,CAAC;CACH;AA29CD;;GAEG;AACH,oBAAY,UAAU,GAAG;IACvB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CACxB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE,UAAe,CAAC"}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,75 @@
/**
* 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 { CDPSession } from './Connection.js';
import { Protocol } from 'devtools-protocol';
/**
* Dialog instances are dispatched by the {@link Page} via the `dialog` event.
*
* @remarks
*
* @example
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* page.on('dialog', async dialog => {
* console.log(dialog.message());
* await dialog.dismiss();
* await browser.close();
* });
* page.evaluate(() => alert('1'));
* })();
* ```
* @public
*/
export declare class Dialog {
private _client;
private _type;
private _message;
private _defaultValue;
private _handled;
/**
* @internal
*/
constructor(client: CDPSession, type: Protocol.Page.DialogType, message: string, defaultValue?: string);
/**
* @returns The type of the dialog.
*/
type(): Protocol.Page.DialogType;
/**
* @returns The message displayed in the dialog.
*/
message(): string;
/**
* @returns The default value of the prompt, or an empty string if the dialog
* is not a `prompt`.
*/
defaultValue(): string;
/**
* @param promptText - optional text that will be entered in the dialog
* prompt. Has no effect if the dialog's type is not `prompt`.
*
* @returns A promise that resolves when the dialog has been accepted.
*/
accept(promptText?: string): Promise<void>;
/**
* @returns A promise which will resolve once the dialog has been dismissed
*/
dismiss(): Promise<void>;
}
//# sourceMappingURL=Dialog.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Dialog.d.ts","sourceRoot":"","sources":["../../../../src/common/Dialog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAS;IAEzB;;OAEG;gBAED,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,UAAU,EAC9B,OAAO,EAAE,MAAM,EACf,YAAY,SAAK;IAQnB;;OAEG;IACH,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,UAAU;IAIhC;;OAEG;IACH,OAAO,IAAI,MAAM;IAIjB;;;OAGG;IACH,YAAY,IAAI,MAAM;IAItB;;;;;OAKG;IACG,MAAM,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAShD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAO/B"}

View File

@@ -0,0 +1,98 @@
"use strict";
/**
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Dialog = void 0;
const assert_js_1 = require("./assert.js");
/**
* Dialog instances are dispatched by the {@link Page} via the `dialog` event.
*
* @remarks
*
* @example
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* page.on('dialog', async dialog => {
* console.log(dialog.message());
* await dialog.dismiss();
* await browser.close();
* });
* page.evaluate(() => alert('1'));
* })();
* ```
* @public
*/
class Dialog {
/**
* @internal
*/
constructor(client, type, message, defaultValue = '') {
this._handled = false;
this._client = client;
this._type = type;
this._message = message;
this._defaultValue = defaultValue;
}
/**
* @returns The type of the dialog.
*/
type() {
return this._type;
}
/**
* @returns The message displayed in the dialog.
*/
message() {
return this._message;
}
/**
* @returns The default value of the prompt, or an empty string if the dialog
* is not a `prompt`.
*/
defaultValue() {
return this._defaultValue;
}
/**
* @param promptText - optional text that will be entered in the dialog
* prompt. Has no effect if the dialog's type is not `prompt`.
*
* @returns A promise that resolves when the dialog has been accepted.
*/
async accept(promptText) {
(0, assert_js_1.assert)(!this._handled, 'Cannot accept dialog which is already handled!');
this._handled = true;
await this._client.send('Page.handleJavaScriptDialog', {
accept: true,
promptText: promptText,
});
}
/**
* @returns A promise which will resolve once the dialog has been dismissed
*/
async dismiss() {
(0, assert_js_1.assert)(!this._handled, 'Cannot dismiss dialog which is already handled!');
this._handled = true;
await this._client.send('Page.handleJavaScriptDialog', {
accept: false,
});
}
}
exports.Dialog = Dialog;
//# sourceMappingURL=Dialog.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Dialog.js","sourceRoot":"","sources":["../../../../src/common/Dialog.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAEH,2CAAqC;AAIrC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAa,MAAM;IAOjB;;OAEG;IACH,YACE,MAAkB,EAClB,IAA8B,EAC9B,OAAe,EACf,YAAY,GAAG,EAAE;QATX,aAAQ,GAAG,KAAK,CAAC;QAWvB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QACxB,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC;IACpC,CAAC;IAED;;OAEG;IACH,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED;;OAEG;IACH,OAAO;QACL,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED;;;OAGG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,MAAM,CAAC,UAAmB;QAC9B,IAAA,kBAAM,EAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,gDAAgD,CAAC,CAAC;QACzE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,6BAA6B,EAAE;YACrD,MAAM,EAAE,IAAI;YACZ,UAAU,EAAE,UAAU;SACvB,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO;QACX,IAAA,kBAAM,EAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,iDAAiD,CAAC,CAAC;QAC1E,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,6BAA6B,EAAE;YACrD,MAAM,EAAE,KAAK;SACd,CAAC,CAAC;IACL,CAAC;CACF;AArED,wBAqEC"}

View File

@@ -0,0 +1,25 @@
/**
* 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 { CDPSession } from './Connection.js';
import { Viewport } from './PuppeteerViewport.js';
export declare class EmulationManager {
_client: CDPSession;
_emulatingMobile: boolean;
_hasTouch: boolean;
constructor(client: CDPSession);
emulateViewport(viewport: Viewport): Promise<boolean>;
}
//# sourceMappingURL=EmulationManager.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"EmulationManager.d.ts","sourceRoot":"","sources":["../../../../src/common/EmulationManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAGlD,qBAAa,gBAAgB;IAC3B,OAAO,EAAE,UAAU,CAAC;IACpB,gBAAgB,UAAS;IACzB,SAAS,UAAS;gBAEN,MAAM,EAAE,UAAU;IAIxB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;CA8B5D"}

View File

@@ -0,0 +1,38 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EmulationManager = void 0;
class EmulationManager {
constructor(client) {
this._emulatingMobile = false;
this._hasTouch = false;
this._client = client;
}
async emulateViewport(viewport) {
const mobile = viewport.isMobile || false;
const width = viewport.width;
const height = viewport.height;
const deviceScaleFactor = viewport.deviceScaleFactor || 1;
const screenOrientation = viewport.isLandscape
? { angle: 90, type: 'landscapePrimary' }
: { angle: 0, type: 'portraitPrimary' };
const hasTouch = viewport.hasTouch || false;
await Promise.all([
this._client.send('Emulation.setDeviceMetricsOverride', {
mobile,
width,
height,
deviceScaleFactor,
screenOrientation,
}),
this._client.send('Emulation.setTouchEmulationEnabled', {
enabled: hasTouch,
}),
]);
const reloadNeeded = this._emulatingMobile !== mobile || this._hasTouch !== hasTouch;
this._emulatingMobile = mobile;
this._hasTouch = hasTouch;
return reloadNeeded;
}
}
exports.EmulationManager = EmulationManager;
//# sourceMappingURL=EmulationManager.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"EmulationManager.js","sourceRoot":"","sources":["../../../../src/common/EmulationManager.ts"],"names":[],"mappings":";;;AAmBA,MAAa,gBAAgB;IAK3B,YAAY,MAAkB;QAH9B,qBAAgB,GAAG,KAAK,CAAC;QACzB,cAAS,GAAG,KAAK,CAAC;QAGhB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,QAAkB;QACtC,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,IAAI,KAAK,CAAC;QAC1C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;QAC7B,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;QAC/B,MAAM,iBAAiB,GAAG,QAAQ,CAAC,iBAAiB,IAAI,CAAC,CAAC;QAC1D,MAAM,iBAAiB,GACrB,QAAQ,CAAC,WAAW;YAClB,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE;YACzC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC;QAC5C,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,IAAI,KAAK,CAAC;QAE5C,MAAM,OAAO,CAAC,GAAG,CAAC;YAChB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,oCAAoC,EAAE;gBACtD,MAAM;gBACN,KAAK;gBACL,MAAM;gBACN,iBAAiB;gBACjB,iBAAiB;aAClB,CAAC;YACF,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,oCAAoC,EAAE;gBACtD,OAAO,EAAE,QAAQ;aAClB,CAAC;SACH,CAAC,CAAC;QAEH,MAAM,YAAY,GAChB,IAAI,CAAC,gBAAgB,KAAK,MAAM,IAAI,IAAI,CAAC,SAAS,KAAK,QAAQ,CAAC;QAClE,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC;QAC/B,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC1B,OAAO,YAAY,CAAC;IACtB,CAAC;CACF;AAvCD,4CAuCC"}

View File

@@ -0,0 +1,51 @@
/**
* Copyright 2018 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.
*/
/**
* @public
*/
export declare class CustomError extends Error {
constructor(message?: string);
}
/**
* TimeoutError is emitted whenever certain operations are terminated due to timeout.
*
* @remarks
*
* Example operations are {@link Page.waitForSelector | page.waitForSelector}
* or {@link PuppeteerNode.launch | puppeteer.launch}.
*
* @public
*/
export declare class TimeoutError extends CustomError {
}
/**
* ProtocolError is emitted whenever there is an error from the protocol.
*
* @public
*/
export declare class ProtocolError extends CustomError {
code?: number;
originalMessage: string;
}
/**
* @public
*/
export declare type PuppeteerErrors = Record<string, typeof CustomError>;
/**
* @public
*/
export declare const puppeteerErrors: PuppeteerErrors;
//# sourceMappingURL=Errors.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Errors.d.ts","sourceRoot":"","sources":["../../../../src/common/Errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;GAEG;AACH,qBAAa,WAAY,SAAQ,KAAK;gBACxB,OAAO,CAAC,EAAE,MAAM;CAK7B;AAED;;;;;;;;;GASG;AACH,qBAAa,YAAa,SAAQ,WAAW;CAAG;AAChD;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,WAAW;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,SAAM;CAC7B;AACD;;GAEG;AACH,oBAAY,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,WAAW,CAAC,CAAC;AACjE;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,eAE7B,CAAC"}

View File

@@ -0,0 +1,61 @@
"use strict";
/**
* Copyright 2018 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 });
exports.puppeteerErrors = exports.ProtocolError = exports.TimeoutError = exports.CustomError = void 0;
/**
* @public
*/
class CustomError extends Error {
constructor(message) {
super(message);
this.name = this.constructor.name;
Error.captureStackTrace(this, this.constructor);
}
}
exports.CustomError = CustomError;
/**
* TimeoutError is emitted whenever certain operations are terminated due to timeout.
*
* @remarks
*
* Example operations are {@link Page.waitForSelector | page.waitForSelector}
* or {@link PuppeteerNode.launch | puppeteer.launch}.
*
* @public
*/
class TimeoutError extends CustomError {
}
exports.TimeoutError = TimeoutError;
/**
* ProtocolError is emitted whenever there is an error from the protocol.
*
* @public
*/
class ProtocolError extends CustomError {
constructor() {
super(...arguments);
this.originalMessage = '';
}
}
exports.ProtocolError = ProtocolError;
/**
* @public
*/
exports.puppeteerErrors = {
TimeoutError,
};
//# sourceMappingURL=Errors.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Errors.js","sourceRoot":"","sources":["../../../../src/common/Errors.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAEH;;GAEG;AACH,MAAa,WAAY,SAAQ,KAAK;IACpC,YAAY,OAAgB;QAC1B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QAClC,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAClD,CAAC;CACF;AAND,kCAMC;AAED;;;;;;;;;GASG;AACH,MAAa,YAAa,SAAQ,WAAW;CAAG;AAAhD,oCAAgD;AAChD;;;;GAIG;AACH,MAAa,aAAc,SAAQ,WAAW;IAA9C;;QAES,oBAAe,GAAG,EAAE,CAAC;IAC9B,CAAC;CAAA;AAHD,sCAGC;AAKD;;GAEG;AACU,QAAA,eAAe,GAAoB;IAC9C,YAAY;CACb,CAAC"}

View File

@@ -0,0 +1,61 @@
/**
* 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.
*/
import { JSHandle, ElementHandle } from './JSHandle.js';
/**
* @public
*/
export declare type EvaluateFn<T = any> = string | ((arg1: T, ...args: any[]) => any);
/**
* @public
*/
export declare type UnwrapPromiseLike<T> = T extends PromiseLike<infer U> ? U : T;
/**
* @public
*/
export declare type EvaluateFnReturnType<T extends EvaluateFn> = T extends (...args: any[]) => infer R ? R : any;
/**
* @public
*/
export declare type EvaluateHandleFn = string | ((...args: any[]) => any);
/**
* @public
*/
export declare type Serializable = number | string | boolean | null | BigInt | JSONArray | JSONObject;
/**
* @public
*/
export declare type JSONArray = readonly Serializable[];
/**
* @public
*/
export interface JSONObject {
[key: string]: Serializable;
}
/**
* @public
*/
export declare type SerializableOrJSHandle = Serializable | JSHandle;
/**
* Wraps a DOM element into an ElementHandle instance
* @public
**/
export declare type WrapElementHandle<X> = X extends Element ? ElementHandle<X> : X;
/**
* Unwraps a DOM element out of an ElementHandle instance
* @public
**/
export declare type UnwrapElementHandle<X> = X extends ElementHandle<infer E> ? E : X;
//# sourceMappingURL=EvalTypes.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"EvalTypes.d.ts","sourceRoot":"","sources":["../../../../src/common/EvalTypes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAExD;;GAEG;AACH,oBAAY,UAAU,CAAC,CAAC,GAAG,GAAG,IAAI,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,CAAC;AAC9E;;GAEG;AACH,oBAAY,iBAAiB,CAAC,CAAC,IAAI,CAAC,SAAS,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAE1E;;GAEG;AACH,oBAAY,oBAAoB,CAAC,CAAC,SAAS,UAAU,IAAI,CAAC,SAAS,CACjE,GAAG,IAAI,EAAE,GAAG,EAAE,KACX,MAAM,CAAC,GACR,CAAC,GACD,GAAG,CAAC;AAER;;GAEG;AACH,oBAAY,gBAAgB,GAAG,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,CAAC;AAElE;;GAEG;AACH,oBAAY,YAAY,GACpB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,MAAM,GACN,SAAS,GACT,UAAU,CAAC;AAEf;;GAEG;AACH,oBAAY,SAAS,GAAG,SAAS,YAAY,EAAE,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAAC;CAC7B;AAED;;GAEG;AACH,oBAAY,sBAAsB,GAAG,YAAY,GAAG,QAAQ,CAAC;AAE7D;;;IAGI;AACJ,oBAAY,iBAAiB,CAAC,CAAC,IAAI,CAAC,SAAS,OAAO,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAE5E;;;IAGI;AACJ,oBAAY,mBAAmB,CAAC,CAAC,IAAI,CAAC,SAAS,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC"}

View File

@@ -0,0 +1,18 @@
"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 });
//# sourceMappingURL=EvalTypes.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"EvalTypes.js","sourceRoot":"","sources":["../../../../src/common/EvalTypes.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG"}

View File

@@ -0,0 +1,93 @@
import { EventType, Handler } from '../../vendor/mitt/src/index.js';
/**
* @public
*/
export { EventType, Handler };
/**
* @public
*/
export interface CommonEventEmitter {
on(event: EventType, handler: Handler): CommonEventEmitter;
off(event: EventType, handler: Handler): CommonEventEmitter;
addListener(event: EventType, handler: Handler): CommonEventEmitter;
removeListener(event: EventType, handler: Handler): CommonEventEmitter;
emit(event: EventType, eventData?: unknown): boolean;
once(event: EventType, handler: Handler): CommonEventEmitter;
listenerCount(event: string): number;
removeAllListeners(event?: EventType): CommonEventEmitter;
}
/**
* The EventEmitter class that many Puppeteer classes extend.
*
* @remarks
*
* This allows you to listen to events that Puppeteer classes fire and act
* accordingly. Therefore you'll mostly use {@link EventEmitter.on | on} and
* {@link EventEmitter.off | off} to bind
* and unbind to event listeners.
*
* @public
*/
export declare class EventEmitter implements CommonEventEmitter {
private emitter;
private eventsMap;
/**
* @internal
*/
constructor();
/**
* Bind an event listener to fire when an event occurs.
* @param event - the event type you'd like to listen to. Can be a string or symbol.
* @param handler - the function to be called when the event occurs.
* @returns `this` to enable you to chain method calls.
*/
on(event: EventType, handler: Handler): EventEmitter;
/**
* Remove an event listener from firing.
* @param event - the event type you'd like to stop listening to.
* @param handler - the function that should be removed.
* @returns `this` to enable you to chain method calls.
*/
off(event: EventType, handler: Handler): EventEmitter;
/**
* Remove an event listener.
* @deprecated please use {@link EventEmitter.off} instead.
*/
removeListener(event: EventType, handler: Handler): EventEmitter;
/**
* Add an event listener.
* @deprecated please use {@link EventEmitter.on} instead.
*/
addListener(event: EventType, handler: Handler): EventEmitter;
/**
* Emit an event and call any associated listeners.
*
* @param event - the event you'd like to emit
* @param eventData - any data you'd like to emit with the event
* @returns `true` if there are any listeners, `false` if there are not.
*/
emit(event: EventType, eventData?: unknown): boolean;
/**
* Like `on` but the listener will only be fired once and then it will be removed.
* @param event - the event you'd like to listen to
* @param handler - the handler function to run when the event occurs
* @returns `this` to enable you to chain method calls.
*/
once(event: EventType, handler: Handler): EventEmitter;
/**
* Gets the number of listeners for a given event.
*
* @param event - the event to get the listener count for
* @returns the number of listeners bound to the given event
*/
listenerCount(event: EventType): number;
/**
* Removes all listeners. If given an event argument, it will remove only
* listeners for that event.
* @param event - the event to remove listeners for.
* @returns `this` to enable you to chain method calls.
*/
removeAllListeners(event?: EventType): EventEmitter;
private eventListenersCount;
}
//# sourceMappingURL=EventEmitter.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"EventEmitter.d.ts","sourceRoot":"","sources":["../../../../src/common/EventEmitter.ts"],"names":[],"mappings":"AAAA,OAAa,EAEX,SAAS,EACT,OAAO,EACR,MAAM,gCAAgC,CAAC;AAExC;;GAEG;AACH,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;AAE9B;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,kBAAkB,CAAC;IAC3D,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,kBAAkB,CAAC;IAK5D,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,kBAAkB,CAAC;IACpE,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,kBAAkB,CAAC;IACvE,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IACrD,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,kBAAkB,CAAC;IAC7D,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAErC,kBAAkB,CAAC,KAAK,CAAC,EAAE,SAAS,GAAG,kBAAkB,CAAC;CAC3D;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,YAAa,YAAW,kBAAkB;IACrD,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,SAAS,CAAmC;IAEpD;;OAEG;;IAKH;;;;;OAKG;IACH,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,YAAY;IAKpD;;;;;OAKG;IACH,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,YAAY;IAKrD;;;OAGG;IACH,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,YAAY;IAKhE;;;OAGG;IACH,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,YAAY;IAK7D;;;;;;OAMG;IACH,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO;IAKpD;;;;;OAKG;IACH,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,YAAY;IAStD;;;;;OAKG;IACH,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM;IAIvC;;;;;OAKG;IACH,kBAAkB,CAAC,KAAK,CAAC,EAAE,SAAS,GAAG,YAAY;IASnD,OAAO,CAAC,mBAAmB;CAG5B"}

View File

@@ -0,0 +1,118 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EventEmitter = void 0;
const index_js_1 = __importDefault(require("../../vendor/mitt/src/index.js"));
/**
* The EventEmitter class that many Puppeteer classes extend.
*
* @remarks
*
* This allows you to listen to events that Puppeteer classes fire and act
* accordingly. Therefore you'll mostly use {@link EventEmitter.on | on} and
* {@link EventEmitter.off | off} to bind
* and unbind to event listeners.
*
* @public
*/
class EventEmitter {
/**
* @internal
*/
constructor() {
this.eventsMap = new Map();
this.emitter = (0, index_js_1.default)(this.eventsMap);
}
/**
* Bind an event listener to fire when an event occurs.
* @param event - the event type you'd like to listen to. Can be a string or symbol.
* @param handler - the function to be called when the event occurs.
* @returns `this` to enable you to chain method calls.
*/
on(event, handler) {
this.emitter.on(event, handler);
return this;
}
/**
* Remove an event listener from firing.
* @param event - the event type you'd like to stop listening to.
* @param handler - the function that should be removed.
* @returns `this` to enable you to chain method calls.
*/
off(event, handler) {
this.emitter.off(event, handler);
return this;
}
/**
* Remove an event listener.
* @deprecated please use {@link EventEmitter.off} instead.
*/
removeListener(event, handler) {
this.off(event, handler);
return this;
}
/**
* Add an event listener.
* @deprecated please use {@link EventEmitter.on} instead.
*/
addListener(event, handler) {
this.on(event, handler);
return this;
}
/**
* Emit an event and call any associated listeners.
*
* @param event - the event you'd like to emit
* @param eventData - any data you'd like to emit with the event
* @returns `true` if there are any listeners, `false` if there are not.
*/
emit(event, eventData) {
this.emitter.emit(event, eventData);
return this.eventListenersCount(event) > 0;
}
/**
* Like `on` but the listener will only be fired once and then it will be removed.
* @param event - the event you'd like to listen to
* @param handler - the handler function to run when the event occurs
* @returns `this` to enable you to chain method calls.
*/
once(event, handler) {
const onceHandler = (eventData) => {
handler(eventData);
this.off(event, onceHandler);
};
return this.on(event, onceHandler);
}
/**
* Gets the number of listeners for a given event.
*
* @param event - the event to get the listener count for
* @returns the number of listeners bound to the given event
*/
listenerCount(event) {
return this.eventListenersCount(event);
}
/**
* Removes all listeners. If given an event argument, it will remove only
* listeners for that event.
* @param event - the event to remove listeners for.
* @returns `this` to enable you to chain method calls.
*/
removeAllListeners(event) {
if (event) {
this.eventsMap.delete(event);
}
else {
this.eventsMap.clear();
}
return this;
}
eventListenersCount(event) {
var _a;
return ((_a = this.eventsMap.get(event)) === null || _a === void 0 ? void 0 : _a.length) || 0;
}
}
exports.EventEmitter = EventEmitter;
//# sourceMappingURL=EventEmitter.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"EventEmitter.js","sourceRoot":"","sources":["../../../../src/common/EventEmitter.ts"],"names":[],"mappings":";;;;;;AAAA,8EAIwC;AA0BxC;;;;;;;;;;;GAWG;AACH,MAAa,YAAY;IAIvB;;OAEG;IACH;QALQ,cAAS,GAAG,IAAI,GAAG,EAAwB,CAAC;QAMlD,IAAI,CAAC,OAAO,GAAG,IAAA,kBAAI,EAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;IAED;;;;;OAKG;IACH,EAAE,CAAC,KAAgB,EAAE,OAAgB;QACnC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAC,KAAgB,EAAE,OAAgB;QACpC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,cAAc,CAAC,KAAgB,EAAE,OAAgB;QAC/C,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,WAAW,CAAC,KAAgB,EAAE,OAAgB;QAC5C,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;OAMG;IACH,IAAI,CAAC,KAAgB,EAAE,SAAmB;QACxC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7C,CAAC;IAED;;;;;OAKG;IACH,IAAI,CAAC,KAAgB,EAAE,OAAgB;QACrC,MAAM,WAAW,GAAY,CAAC,SAAS,EAAE,EAAE;YACzC,OAAO,CAAC,SAAS,CAAC,CAAC;YACnB,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QAC/B,CAAC,CAAC;QAEF,OAAO,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IACrC,CAAC;IAED;;;;;OAKG;IACH,aAAa,CAAC,KAAgB;QAC5B,OAAO,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC;IAED;;;;;OAKG;IACH,kBAAkB,CAAC,KAAiB;QAClC,IAAI,KAAK,EAAE;YACT,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;SAC9B;aAAM;YACL,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;SACxB;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,mBAAmB,CAAC,KAAgB;;QAC1C,OAAO,CAAA,MAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,0CAAE,MAAM,KAAI,CAAC,CAAC;IAChD,CAAC;CACF;AA1GD,oCA0GC"}

View File

@@ -0,0 +1,82 @@
/**
* Copyright 2019 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.
*/
/**
* IMPORTANT: we are mid-way through migrating away from this Events.ts file
* in favour of defining events next to the class that emits them.
*
* However we need to maintain this file for now because the legacy DocLint
* system relies on them. Be aware in the mean time if you make a change here
* you probably need to replicate it in the relevant class. For example if you
* add a new Page event, you should update the PageEmittedEvents enum in
* src/common/Page.ts.
*
* Chat to @jackfranklin if you're unsure.
*/
export declare const Events: {
readonly Page: {
readonly Close: "close";
readonly Console: "console";
readonly Dialog: "dialog";
readonly DOMContentLoaded: "domcontentloaded";
readonly Error: "error";
readonly PageError: "pageerror";
readonly Request: "request";
readonly Response: "response";
readonly RequestFailed: "requestfailed";
readonly RequestFinished: "requestfinished";
readonly FrameAttached: "frameattached";
readonly FrameDetached: "framedetached";
readonly FrameNavigated: "framenavigated";
readonly Load: "load";
readonly Metrics: "metrics";
readonly Popup: "popup";
readonly WorkerCreated: "workercreated";
readonly WorkerDestroyed: "workerdestroyed";
};
readonly Browser: {
readonly TargetCreated: "targetcreated";
readonly TargetDestroyed: "targetdestroyed";
readonly TargetChanged: "targetchanged";
readonly Disconnected: "disconnected";
};
readonly BrowserContext: {
readonly TargetCreated: "targetcreated";
readonly TargetDestroyed: "targetdestroyed";
readonly TargetChanged: "targetchanged";
};
readonly NetworkManager: {
readonly Request: symbol;
readonly Response: symbol;
readonly RequestFailed: symbol;
readonly RequestFinished: symbol;
};
readonly FrameManager: {
readonly FrameAttached: symbol;
readonly FrameNavigated: symbol;
readonly FrameDetached: symbol;
readonly LifecycleEvent: symbol;
readonly FrameNavigatedWithinDocument: symbol;
readonly ExecutionContextCreated: symbol;
readonly ExecutionContextDestroyed: symbol;
};
readonly Connection: {
readonly Disconnected: symbol;
};
readonly CDPSession: {
readonly Disconnected: symbol;
};
};
//# sourceMappingURL=Events.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Events.d.ts","sourceRoot":"","sources":["../../../../src/common/Events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmET,CAAC"}

View File

@@ -0,0 +1,87 @@
"use strict";
/**
* Copyright 2019 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 });
exports.Events = void 0;
/**
* IMPORTANT: we are mid-way through migrating away from this Events.ts file
* in favour of defining events next to the class that emits them.
*
* However we need to maintain this file for now because the legacy DocLint
* system relies on them. Be aware in the mean time if you make a change here
* you probably need to replicate it in the relevant class. For example if you
* add a new Page event, you should update the PageEmittedEvents enum in
* src/common/Page.ts.
*
* Chat to @jackfranklin if you're unsure.
*/
exports.Events = {
Page: {
Close: 'close',
Console: 'console',
Dialog: 'dialog',
DOMContentLoaded: 'domcontentloaded',
Error: 'error',
// Can't use just 'error' due to node.js special treatment of error events.
// @see https://nodejs.org/api/events.html#events_error_events
PageError: 'pageerror',
Request: 'request',
Response: 'response',
RequestFailed: 'requestfailed',
RequestFinished: 'requestfinished',
FrameAttached: 'frameattached',
FrameDetached: 'framedetached',
FrameNavigated: 'framenavigated',
Load: 'load',
Metrics: 'metrics',
Popup: 'popup',
WorkerCreated: 'workercreated',
WorkerDestroyed: 'workerdestroyed',
},
Browser: {
TargetCreated: 'targetcreated',
TargetDestroyed: 'targetdestroyed',
TargetChanged: 'targetchanged',
Disconnected: 'disconnected',
},
BrowserContext: {
TargetCreated: 'targetcreated',
TargetDestroyed: 'targetdestroyed',
TargetChanged: 'targetchanged',
},
NetworkManager: {
Request: Symbol('Events.NetworkManager.Request'),
Response: Symbol('Events.NetworkManager.Response'),
RequestFailed: Symbol('Events.NetworkManager.RequestFailed'),
RequestFinished: Symbol('Events.NetworkManager.RequestFinished'),
},
FrameManager: {
FrameAttached: Symbol('Events.FrameManager.FrameAttached'),
FrameNavigated: Symbol('Events.FrameManager.FrameNavigated'),
FrameDetached: Symbol('Events.FrameManager.FrameDetached'),
LifecycleEvent: Symbol('Events.FrameManager.LifecycleEvent'),
FrameNavigatedWithinDocument: Symbol('Events.FrameManager.FrameNavigatedWithinDocument'),
ExecutionContextCreated: Symbol('Events.FrameManager.ExecutionContextCreated'),
ExecutionContextDestroyed: Symbol('Events.FrameManager.ExecutionContextDestroyed'),
},
Connection: {
Disconnected: Symbol('Events.Connection.Disconnected'),
},
CDPSession: {
Disconnected: Symbol('Events.CDPSession.Disconnected'),
},
};
//# sourceMappingURL=Events.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Events.js","sourceRoot":"","sources":["../../../../src/common/Events.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAEH;;;;;;;;;;;GAWG;AAEU,QAAA,MAAM,GAAG;IACpB,IAAI,EAAE;QACJ,KAAK,EAAE,OAAO;QACd,OAAO,EAAE,SAAS;QAClB,MAAM,EAAE,QAAQ;QAChB,gBAAgB,EAAE,kBAAkB;QACpC,KAAK,EAAE,OAAO;QACd,2EAA2E;QAC3E,8DAA8D;QAC9D,SAAS,EAAE,WAAW;QACtB,OAAO,EAAE,SAAS;QAClB,QAAQ,EAAE,UAAU;QACpB,aAAa,EAAE,eAAe;QAC9B,eAAe,EAAE,iBAAiB;QAClC,aAAa,EAAE,eAAe;QAC9B,aAAa,EAAE,eAAe;QAC9B,cAAc,EAAE,gBAAgB;QAChC,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,OAAO;QACd,aAAa,EAAE,eAAe;QAC9B,eAAe,EAAE,iBAAiB;KACnC;IAED,OAAO,EAAE;QACP,aAAa,EAAE,eAAe;QAC9B,eAAe,EAAE,iBAAiB;QAClC,aAAa,EAAE,eAAe;QAC9B,YAAY,EAAE,cAAc;KAC7B;IAED,cAAc,EAAE;QACd,aAAa,EAAE,eAAe;QAC9B,eAAe,EAAE,iBAAiB;QAClC,aAAa,EAAE,eAAe;KAC/B;IAED,cAAc,EAAE;QACd,OAAO,EAAE,MAAM,CAAC,+BAA+B,CAAC;QAChD,QAAQ,EAAE,MAAM,CAAC,gCAAgC,CAAC;QAClD,aAAa,EAAE,MAAM,CAAC,qCAAqC,CAAC;QAC5D,eAAe,EAAE,MAAM,CAAC,uCAAuC,CAAC;KACjE;IAED,YAAY,EAAE;QACZ,aAAa,EAAE,MAAM,CAAC,mCAAmC,CAAC;QAC1D,cAAc,EAAE,MAAM,CAAC,oCAAoC,CAAC;QAC5D,aAAa,EAAE,MAAM,CAAC,mCAAmC,CAAC;QAC1D,cAAc,EAAE,MAAM,CAAC,oCAAoC,CAAC;QAC5D,4BAA4B,EAAE,MAAM,CAClC,kDAAkD,CACnD;QACD,uBAAuB,EAAE,MAAM,CAC7B,6CAA6C,CAC9C;QACD,yBAAyB,EAAE,MAAM,CAC/B,+CAA+C,CAChD;KACF;IAED,UAAU,EAAE;QACV,YAAY,EAAE,MAAM,CAAC,gCAAgC,CAAC;KACvD;IAED,UAAU,EAAE;QACV,YAAY,EAAE,MAAM,CAAC,gCAAgC,CAAC;KACvD;CACO,CAAC"}

View File

@@ -0,0 +1,194 @@
/**
* 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 { JSHandle, ElementHandle } from './JSHandle.js';
import { CDPSession } from './Connection.js';
import { DOMWorld } from './DOMWorld.js';
import { Frame } from './FrameManager.js';
import { Protocol } from 'devtools-protocol';
import { EvaluateHandleFn, SerializableOrJSHandle } from './EvalTypes.js';
/**
* @public
*/
export declare const EVALUATION_SCRIPT_URL = "__puppeteer_evaluation_script__";
/**
* This class represents a context for JavaScript execution. A [Page] might have
* many execution contexts:
* - each
* {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe |
* frame } has "default" execution context that is always created after frame is
* attached to DOM. This context is returned by the
* {@link Frame.executionContext} method.
* - {@link https://developer.chrome.com/extensions | Extension}'s content scripts
* create additional execution contexts.
*
* Besides pages, execution contexts can be found in
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API |
* workers }.
*
* @public
*/
export declare class ExecutionContext {
/**
* @internal
*/
_client: CDPSession;
/**
* @internal
*/
_world: DOMWorld;
/**
* @internal
*/
_contextId: number;
/**
* @internal
*/
_contextName: string;
/**
* @internal
*/
constructor(client: CDPSession, contextPayload: Protocol.Runtime.ExecutionContextDescription, world: DOMWorld);
/**
* @remarks
*
* Not every execution context is associated with a frame. For
* example, workers and extensions have execution contexts that are not
* associated with frames.
*
* @returns The frame associated with this execution context.
*/
frame(): Frame | null;
/**
* @remarks
* If the function passed to the `executionContext.evaluate` returns a
* Promise, then `executionContext.evaluate` would wait for the promise to
* resolve and return its value. If the function passed to the
* `executionContext.evaluate` returns a non-serializable value, then
* `executionContext.evaluate` resolves to `undefined`. DevTools Protocol also
* supports transferring some additional values that are not serializable by
* `JSON`: `-0`, `NaN`, `Infinity`, `-Infinity`, and bigint literals.
*
*
* @example
* ```js
* const executionContext = await page.mainFrame().executionContext();
* const result = await executionContext.evaluate(() => Promise.resolve(8 * 7))* ;
* console.log(result); // prints "56"
* ```
*
* @example
* A string can also be passed in instead of a function.
*
* ```js
* console.log(await executionContext.evaluate('1 + 2')); // prints "3"
* ```
*
* @example
* {@link JSHandle} instances can be passed as arguments to the
* `executionContext.* evaluate`:
* ```js
* const oneHandle = await executionContext.evaluateHandle(() => 1);
* const twoHandle = await executionContext.evaluateHandle(() => 2);
* const result = await executionContext.evaluate(
* (a, b) => a + b, oneHandle, * twoHandle
* );
* await oneHandle.dispose();
* await twoHandle.dispose();
* console.log(result); // prints '3'.
* ```
* @param pageFunction - a function to be evaluated in the `executionContext`
* @param args - argument to pass to the page function
*
* @returns A promise that resolves to the return value of the given function.
*/
evaluate<ReturnType>(pageFunction: Function | string, ...args: unknown[]): Promise<ReturnType>;
/**
* @remarks
* The only difference between `executionContext.evaluate` and
* `executionContext.evaluateHandle` is that `executionContext.evaluateHandle`
* returns an in-page object (a {@link JSHandle}).
* If the function passed to the `executionContext.evaluateHandle` returns a
* Promise, then `executionContext.evaluateHandle` would wait for the
* promise to resolve and return its value.
*
* @example
* ```js
* const context = await page.mainFrame().executionContext();
* const aHandle = await context.evaluateHandle(() => Promise.resolve(self));
* aHandle; // Handle for the global object.
* ```
*
* @example
* A string can also be passed in instead of a function.
*
* ```js
* // Handle for the '3' * object.
* const aHandle = await context.evaluateHandle('1 + 2');
* ```
*
* @example
* JSHandle instances can be passed as arguments
* to the `executionContext.* evaluateHandle`:
*
* ```js
* const aHandle = await context.evaluateHandle(() => document.body);
* const resultHandle = await context.evaluateHandle(body => body.innerHTML, * aHandle);
* console.log(await resultHandle.jsonValue()); // prints body's innerHTML
* await aHandle.dispose();
* await resultHandle.dispose();
* ```
*
* @param pageFunction - a function to be evaluated in the `executionContext`
* @param args - argument to pass to the page function
*
* @returns A promise that resolves to the return value of the given function
* as an in-page object (a {@link JSHandle}).
*/
evaluateHandle<HandleType extends JSHandle | ElementHandle = JSHandle>(pageFunction: EvaluateHandleFn, ...args: SerializableOrJSHandle[]): Promise<HandleType>;
private _evaluateInternal;
/**
* This method iterates the JavaScript heap and finds all the objects with the
* given prototype.
* @remarks
* @example
* ```js
* // Create a Map object
* await page.evaluate(() => window.map = new Map());
* // Get a handle to the Map object prototype
* const mapPrototype = await page.evaluateHandle(() => Map.prototype);
* // Query all map instances into an array
* const mapInstances = await page.queryObjects(mapPrototype);
* // Count amount of map objects in heap
* const count = await page.evaluate(maps => maps.length, mapInstances);
* await mapInstances.dispose();
* await mapPrototype.dispose();
* ```
*
* @param prototypeHandle - a handle to the object prototype
*
* @returns A handle to an array of objects with the given prototype.
*/
queryObjects(prototypeHandle: JSHandle): Promise<JSHandle>;
/**
* @internal
*/
_adoptBackendNodeId(backendNodeId: Protocol.DOM.BackendNodeId): Promise<ElementHandle>;
/**
* @internal
*/
_adoptElementHandle(elementHandle: ElementHandle): Promise<ElementHandle>;
}
//# sourceMappingURL=ExecutionContext.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ExecutionContext.d.ts","sourceRoot":"","sources":["../../../../src/common/ExecutionContext.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,EAAkB,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC1E;;GAEG;AACH,eAAO,MAAM,qBAAqB,oCAAoC,CAAC;AAGvE;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,gBAAgB;IAC3B;;OAEG;IACH,OAAO,EAAE,UAAU,CAAC;IACpB;;OAEG;IACH,MAAM,EAAE,QAAQ,CAAC;IACjB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;OAEG;gBAED,MAAM,EAAE,UAAU,EAClB,cAAc,EAAE,QAAQ,CAAC,OAAO,CAAC,2BAA2B,EAC5D,KAAK,EAAE,QAAQ;IAQjB;;;;;;;;OAQG;IACH,KAAK,IAAI,KAAK,GAAG,IAAI;IAIrB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA0CG;IACG,QAAQ,CAAC,UAAU,EACvB,YAAY,EAAE,QAAQ,GAAG,MAAM,EAC/B,GAAG,IAAI,EAAE,OAAO,EAAE,GACjB,OAAO,CAAC,UAAU,CAAC;IAQtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAyCG;IACG,cAAc,CAAC,UAAU,SAAS,QAAQ,GAAG,aAAa,GAAG,QAAQ,EACzE,YAAY,EAAE,gBAAgB,EAC9B,GAAG,IAAI,EAAE,sBAAsB,EAAE,GAChC,OAAO,CAAC,UAAU,CAAC;YAIR,iBAAiB;IAqI/B;;;;;;;;;;;;;;;;;;;;;OAqBG;IACG,YAAY,CAAC,eAAe,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAYhE;;OAEG;IACG,mBAAmB,CACvB,aAAa,EAAE,QAAQ,CAAC,GAAG,CAAC,aAAa,GACxC,OAAO,CAAC,aAAa,CAAC;IAQzB;;OAEG;IACG,mBAAmB,CACvB,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,aAAa,CAAC;CAW1B"}

View File

@@ -0,0 +1,322 @@
"use strict";
/**
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExecutionContext = exports.EVALUATION_SCRIPT_URL = void 0;
const assert_js_1 = require("./assert.js");
const helper_js_1 = require("./helper.js");
const JSHandle_js_1 = require("./JSHandle.js");
/**
* @public
*/
exports.EVALUATION_SCRIPT_URL = '__puppeteer_evaluation_script__';
const SOURCE_URL_REGEX = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/m;
/**
* This class represents a context for JavaScript execution. A [Page] might have
* many execution contexts:
* - each
* {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe |
* frame } has "default" execution context that is always created after frame is
* attached to DOM. This context is returned by the
* {@link Frame.executionContext} method.
* - {@link https://developer.chrome.com/extensions | Extension}'s content scripts
* create additional execution contexts.
*
* Besides pages, execution contexts can be found in
* {@link https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API |
* workers }.
*
* @public
*/
class ExecutionContext {
/**
* @internal
*/
constructor(client, contextPayload, world) {
this._client = client;
this._world = world;
this._contextId = contextPayload.id;
this._contextName = contextPayload.name;
}
/**
* @remarks
*
* Not every execution context is associated with a frame. For
* example, workers and extensions have execution contexts that are not
* associated with frames.
*
* @returns The frame associated with this execution context.
*/
frame() {
return this._world ? this._world.frame() : null;
}
/**
* @remarks
* If the function passed to the `executionContext.evaluate` returns a
* Promise, then `executionContext.evaluate` would wait for the promise to
* resolve and return its value. If the function passed to the
* `executionContext.evaluate` returns a non-serializable value, then
* `executionContext.evaluate` resolves to `undefined`. DevTools Protocol also
* supports transferring some additional values that are not serializable by
* `JSON`: `-0`, `NaN`, `Infinity`, `-Infinity`, and bigint literals.
*
*
* @example
* ```js
* const executionContext = await page.mainFrame().executionContext();
* const result = await executionContext.evaluate(() => Promise.resolve(8 * 7))* ;
* console.log(result); // prints "56"
* ```
*
* @example
* A string can also be passed in instead of a function.
*
* ```js
* console.log(await executionContext.evaluate('1 + 2')); // prints "3"
* ```
*
* @example
* {@link JSHandle} instances can be passed as arguments to the
* `executionContext.* evaluate`:
* ```js
* const oneHandle = await executionContext.evaluateHandle(() => 1);
* const twoHandle = await executionContext.evaluateHandle(() => 2);
* const result = await executionContext.evaluate(
* (a, b) => a + b, oneHandle, * twoHandle
* );
* await oneHandle.dispose();
* await twoHandle.dispose();
* console.log(result); // prints '3'.
* ```
* @param pageFunction - a function to be evaluated in the `executionContext`
* @param args - argument to pass to the page function
*
* @returns A promise that resolves to the return value of the given function.
*/
async evaluate(pageFunction, ...args) {
return await this._evaluateInternal(true, pageFunction, ...args);
}
/**
* @remarks
* The only difference between `executionContext.evaluate` and
* `executionContext.evaluateHandle` is that `executionContext.evaluateHandle`
* returns an in-page object (a {@link JSHandle}).
* If the function passed to the `executionContext.evaluateHandle` returns a
* Promise, then `executionContext.evaluateHandle` would wait for the
* promise to resolve and return its value.
*
* @example
* ```js
* const context = await page.mainFrame().executionContext();
* const aHandle = await context.evaluateHandle(() => Promise.resolve(self));
* aHandle; // Handle for the global object.
* ```
*
* @example
* A string can also be passed in instead of a function.
*
* ```js
* // Handle for the '3' * object.
* const aHandle = await context.evaluateHandle('1 + 2');
* ```
*
* @example
* JSHandle instances can be passed as arguments
* to the `executionContext.* evaluateHandle`:
*
* ```js
* const aHandle = await context.evaluateHandle(() => document.body);
* const resultHandle = await context.evaluateHandle(body => body.innerHTML, * aHandle);
* console.log(await resultHandle.jsonValue()); // prints body's innerHTML
* await aHandle.dispose();
* await resultHandle.dispose();
* ```
*
* @param pageFunction - a function to be evaluated in the `executionContext`
* @param args - argument to pass to the page function
*
* @returns A promise that resolves to the return value of the given function
* as an in-page object (a {@link JSHandle}).
*/
async evaluateHandle(pageFunction, ...args) {
return this._evaluateInternal(false, pageFunction, ...args);
}
async _evaluateInternal(returnByValue, pageFunction, ...args) {
const suffix = `//# sourceURL=${exports.EVALUATION_SCRIPT_URL}`;
if (helper_js_1.helper.isString(pageFunction)) {
const contextId = this._contextId;
const expression = pageFunction;
const expressionWithSourceUrl = SOURCE_URL_REGEX.test(expression)
? expression
: expression + '\n' + suffix;
const { exceptionDetails, result: remoteObject } = await this._client
.send('Runtime.evaluate', {
expression: expressionWithSourceUrl,
contextId,
returnByValue,
awaitPromise: true,
userGesture: true,
})
.catch(rewriteError);
if (exceptionDetails)
throw new Error('Evaluation failed: ' + helper_js_1.helper.getExceptionMessage(exceptionDetails));
return returnByValue
? helper_js_1.helper.valueFromRemoteObject(remoteObject)
: (0, JSHandle_js_1.createJSHandle)(this, remoteObject);
}
if (typeof pageFunction !== 'function')
throw new Error(`Expected to get |string| or |function| as the first argument, but got "${pageFunction}" instead.`);
let functionText = pageFunction.toString();
try {
new Function('(' + functionText + ')');
}
catch (error) {
// This means we might have a function shorthand. Try another
// time prefixing 'function '.
if (functionText.startsWith('async '))
functionText =
'async function ' + functionText.substring('async '.length);
else
functionText = 'function ' + functionText;
try {
new Function('(' + functionText + ')');
}
catch (error) {
// We tried hard to serialize, but there's a weird beast here.
throw new Error('Passed function is not well-serializable!');
}
}
let callFunctionOnPromise;
try {
callFunctionOnPromise = this._client.send('Runtime.callFunctionOn', {
functionDeclaration: functionText + '\n' + suffix + '\n',
executionContextId: this._contextId,
arguments: args.map(convertArgument.bind(this)),
returnByValue,
awaitPromise: true,
userGesture: true,
});
}
catch (error) {
if (error instanceof TypeError &&
error.message.startsWith('Converting circular structure to JSON'))
error.message += ' Are you passing a nested JSHandle?';
throw error;
}
const { exceptionDetails, result: remoteObject } = await callFunctionOnPromise.catch(rewriteError);
if (exceptionDetails)
throw new Error('Evaluation failed: ' + helper_js_1.helper.getExceptionMessage(exceptionDetails));
return returnByValue
? helper_js_1.helper.valueFromRemoteObject(remoteObject)
: (0, JSHandle_js_1.createJSHandle)(this, remoteObject);
/**
* @param {*} arg
* @returns {*}
* @this {ExecutionContext}
*/
function convertArgument(arg) {
if (typeof arg === 'bigint')
// eslint-disable-line valid-typeof
return { unserializableValue: `${arg.toString()}n` };
if (Object.is(arg, -0))
return { unserializableValue: '-0' };
if (Object.is(arg, Infinity))
return { unserializableValue: 'Infinity' };
if (Object.is(arg, -Infinity))
return { unserializableValue: '-Infinity' };
if (Object.is(arg, NaN))
return { unserializableValue: 'NaN' };
const objectHandle = arg && arg instanceof JSHandle_js_1.JSHandle ? arg : null;
if (objectHandle) {
if (objectHandle._context !== this)
throw new Error('JSHandles can be evaluated only in the context they were created!');
if (objectHandle._disposed)
throw new Error('JSHandle is disposed!');
if (objectHandle._remoteObject.unserializableValue)
return {
unserializableValue: objectHandle._remoteObject.unserializableValue,
};
if (!objectHandle._remoteObject.objectId)
return { value: objectHandle._remoteObject.value };
return { objectId: objectHandle._remoteObject.objectId };
}
return { value: arg };
}
function rewriteError(error) {
if (error.message.includes('Object reference chain is too long'))
return { result: { type: 'undefined' } };
if (error.message.includes("Object couldn't be returned by value"))
return { result: { type: 'undefined' } };
if (error.message.endsWith('Cannot find context with specified id') ||
error.message.endsWith('Inspected target navigated or closed'))
throw new Error('Execution context was destroyed, most likely because of a navigation.');
throw error;
}
}
/**
* This method iterates the JavaScript heap and finds all the objects with the
* given prototype.
* @remarks
* @example
* ```js
* // Create a Map object
* await page.evaluate(() => window.map = new Map());
* // Get a handle to the Map object prototype
* const mapPrototype = await page.evaluateHandle(() => Map.prototype);
* // Query all map instances into an array
* const mapInstances = await page.queryObjects(mapPrototype);
* // Count amount of map objects in heap
* const count = await page.evaluate(maps => maps.length, mapInstances);
* await mapInstances.dispose();
* await mapPrototype.dispose();
* ```
*
* @param prototypeHandle - a handle to the object prototype
*
* @returns A handle to an array of objects with the given prototype.
*/
async queryObjects(prototypeHandle) {
(0, assert_js_1.assert)(!prototypeHandle._disposed, 'Prototype JSHandle is disposed!');
(0, assert_js_1.assert)(prototypeHandle._remoteObject.objectId, 'Prototype JSHandle must not be referencing primitive value');
const response = await this._client.send('Runtime.queryObjects', {
prototypeObjectId: prototypeHandle._remoteObject.objectId,
});
return (0, JSHandle_js_1.createJSHandle)(this, response.objects);
}
/**
* @internal
*/
async _adoptBackendNodeId(backendNodeId) {
const { object } = await this._client.send('DOM.resolveNode', {
backendNodeId: backendNodeId,
executionContextId: this._contextId,
});
return (0, JSHandle_js_1.createJSHandle)(this, object);
}
/**
* @internal
*/
async _adoptElementHandle(elementHandle) {
(0, assert_js_1.assert)(elementHandle.executionContext() !== this, 'Cannot adopt handle that already belongs to this execution context');
(0, assert_js_1.assert)(this._world, 'Cannot adopt handle without DOMWorld');
const nodeInfo = await this._client.send('DOM.describeNode', {
objectId: elementHandle._remoteObject.objectId,
});
return this._adoptBackendNodeId(nodeInfo.node.backendNodeId);
}
}
exports.ExecutionContext = ExecutionContext;
//# sourceMappingURL=ExecutionContext.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,59 @@
/**
* 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.
*/
import { ElementHandle } from './JSHandle.js';
import { Protocol } from 'devtools-protocol';
/**
* File choosers let you react to the page requesting for a file.
* @remarks
* `FileChooser` objects are returned via the `page.waitForFileChooser` method.
* @example
* An example of using `FileChooser`:
* ```js
* const [fileChooser] = await Promise.all([
* page.waitForFileChooser(),
* page.click('#upload-file-button'), // some button that triggers file selection
* ]);
* await fileChooser.accept(['/tmp/myfile.pdf']);
* ```
* **NOTE** In browsers, only one file chooser can be opened at a time.
* All file choosers must be accepted or canceled. Not doing so will prevent
* subsequent file choosers from appearing.
* @public
*/
export declare class FileChooser {
private _element;
private _multiple;
private _handled;
/**
* @internal
*/
constructor(element: ElementHandle, event: Protocol.Page.FileChooserOpenedEvent);
/**
* Whether file chooser allow for {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#attr-multiple | multiple} file selection.
*/
isMultiple(): boolean;
/**
* Accept the file chooser request with given paths.
* @param filePaths - If some of the `filePaths` are relative paths,
* then they are resolved relative to the {@link https://nodejs.org/api/process.html#process_process_cwd | current working directory}.
*/
accept(filePaths: string[]): Promise<void>;
/**
* Closes the file chooser without selecting any files.
*/
cancel(): void;
}
//# sourceMappingURL=FileChooser.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"FileChooser.d.ts","sourceRoot":"","sources":["../../../../src/common/FileChooser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAG7C;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,SAAS,CAAU;IAC3B,OAAO,CAAC,QAAQ,CAAS;IAEzB;;OAEG;gBAED,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,sBAAsB;IAM7C;;OAEG;IACH,UAAU,IAAI,OAAO;IAIrB;;;;OAIG;IACG,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAShD;;OAEG;IACH,MAAM,IAAI,IAAI;CAOf"}

View File

@@ -0,0 +1,72 @@
"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 });
exports.FileChooser = void 0;
const assert_js_1 = require("./assert.js");
/**
* File choosers let you react to the page requesting for a file.
* @remarks
* `FileChooser` objects are returned via the `page.waitForFileChooser` method.
* @example
* An example of using `FileChooser`:
* ```js
* const [fileChooser] = await Promise.all([
* page.waitForFileChooser(),
* page.click('#upload-file-button'), // some button that triggers file selection
* ]);
* await fileChooser.accept(['/tmp/myfile.pdf']);
* ```
* **NOTE** In browsers, only one file chooser can be opened at a time.
* All file choosers must be accepted or canceled. Not doing so will prevent
* subsequent file choosers from appearing.
* @public
*/
class FileChooser {
/**
* @internal
*/
constructor(element, event) {
this._handled = false;
this._element = element;
this._multiple = event.mode !== 'selectSingle';
}
/**
* Whether file chooser allow for {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#attr-multiple | multiple} file selection.
*/
isMultiple() {
return this._multiple;
}
/**
* Accept the file chooser request with given paths.
* @param filePaths - If some of the `filePaths` are relative paths,
* then they are resolved relative to the {@link https://nodejs.org/api/process.html#process_process_cwd | current working directory}.
*/
async accept(filePaths) {
(0, assert_js_1.assert)(!this._handled, 'Cannot accept FileChooser which is already handled!');
this._handled = true;
await this._element.uploadFile(...filePaths);
}
/**
* Closes the file chooser without selecting any files.
*/
cancel() {
(0, assert_js_1.assert)(!this._handled, 'Cannot cancel FileChooser which is already handled!');
this._handled = true;
}
}
exports.FileChooser = FileChooser;
//# sourceMappingURL=FileChooser.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"FileChooser.js","sourceRoot":"","sources":["../../../../src/common/FileChooser.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAIH,2CAAqC;AAErC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAa,WAAW;IAKtB;;OAEG;IACH,YACE,OAAsB,EACtB,KAA2C;QAPrC,aAAQ,GAAG,KAAK,CAAC;QASvB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;QACxB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,IAAI,KAAK,cAAc,CAAC;IACjD,CAAC;IAED;;OAEG;IACH,UAAU;QACR,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,SAAmB;QAC9B,IAAA,kBAAM,EACJ,CAAC,IAAI,CAAC,QAAQ,EACd,qDAAqD,CACtD,CAAC;QACF,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,SAAS,CAAC,CAAC;IAC/C,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,IAAA,kBAAM,EACJ,CAAC,IAAI,CAAC,QAAQ,EACd,qDAAqD,CACtD,CAAC;QACF,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACvB,CAAC;CACF;AA/CD,kCA+CC"}

View File

@@ -0,0 +1,754 @@
/**
* 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 { EventEmitter } from './EventEmitter.js';
import { ExecutionContext } from './ExecutionContext.js';
import { PuppeteerLifeCycleEvent } from './LifecycleWatcher.js';
import { DOMWorld, WaitForSelectorOptions } from './DOMWorld.js';
import { NetworkManager } from './NetworkManager.js';
import { TimeoutSettings } from './TimeoutSettings.js';
import { CDPSession } from './Connection.js';
import { JSHandle, ElementHandle } from './JSHandle.js';
import { MouseButton } from './Input.js';
import { Page } from './Page.js';
import { HTTPResponse } from './HTTPResponse.js';
import { Protocol } from 'devtools-protocol';
import { SerializableOrJSHandle, EvaluateHandleFn, WrapElementHandle, EvaluateFn, EvaluateFnReturnType, UnwrapPromiseLike } from './EvalTypes.js';
/**
* We use symbols to prevent external parties listening to these events.
* They are internal to Puppeteer.
*
* @internal
*/
export declare const FrameManagerEmittedEvents: {
FrameAttached: symbol;
FrameNavigated: symbol;
FrameDetached: symbol;
FrameSwapped: symbol;
LifecycleEvent: symbol;
FrameNavigatedWithinDocument: symbol;
ExecutionContextCreated: symbol;
ExecutionContextDestroyed: symbol;
};
/**
* @internal
*/
export declare class FrameManager extends EventEmitter {
_client: CDPSession;
private _page;
private _networkManager;
_timeoutSettings: TimeoutSettings;
private _frames;
private _contextIdToContext;
private _isolatedWorlds;
private _mainFrame;
constructor(client: CDPSession, page: Page, ignoreHTTPSErrors: boolean, timeoutSettings: TimeoutSettings);
private setupEventListeners;
initialize(client?: CDPSession): Promise<void>;
networkManager(): NetworkManager;
navigateFrame(frame: Frame, url: string, options?: {
referer?: string;
timeout?: number;
waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[];
}): Promise<HTTPResponse | null>;
waitForFrameNavigation(frame: Frame, options?: {
timeout?: number;
waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[];
}): Promise<HTTPResponse | null>;
private _onAttachedToTarget;
private _onDetachedFromTarget;
_onLifecycleEvent(event: Protocol.Page.LifecycleEventEvent): void;
_onFrameStoppedLoading(frameId: string): void;
_handleFrameTree(session: CDPSession, frameTree: Protocol.Page.FrameTree): void;
page(): Page;
mainFrame(): Frame;
frames(): Frame[];
frame(frameId: string): Frame | null;
_onFrameAttached(session: CDPSession, frameId: string, parentFrameId?: string): void;
_onFrameNavigated(framePayload: Protocol.Page.Frame): void;
_ensureIsolatedWorld(session: CDPSession, name: string): Promise<void>;
_onFrameNavigatedWithinDocument(frameId: string, url: string): void;
_onFrameDetached(frameId: string, reason: Protocol.Page.FrameDetachedEventReason): void;
_onExecutionContextCreated(contextPayload: Protocol.Runtime.ExecutionContextDescription, session: CDPSession): void;
private _onExecutionContextDestroyed;
private _onExecutionContextsCleared;
executionContextById(contextId: number, session?: CDPSession): ExecutionContext;
private _removeFramesRecursively;
}
/**
* @public
*/
export interface FrameWaitForFunctionOptions {
/**
* An interval at which the `pageFunction` is executed, defaults to `raf`. If
* `polling` is a number, then it is treated as an interval in milliseconds at
* which the function would be executed. If `polling` is a string, then it can
* be one of the following values:
*
* - `raf` - to constantly execute `pageFunction` in `requestAnimationFrame`
* callback. This is the tightest polling mode which is suitable to observe
* styling changes.
*
* - `mutation` - to execute `pageFunction` on every DOM mutation.
*/
polling?: string | number;
/**
* Maximum time to wait in milliseconds. Defaults to `30000` (30 seconds).
* Pass `0` to disable the timeout. Puppeteer's default timeout can be changed
* using {@link Page.setDefaultTimeout}.
*/
timeout?: number;
}
/**
* @public
*/
export interface FrameAddScriptTagOptions {
/**
* the URL of the script to be added.
*/
url?: string;
/**
* The path to a JavaScript file to be injected into the frame.
* @remarks
* If `path` is a relative path, it is resolved relative to the current
* working directory (`process.cwd()` in Node.js).
*/
path?: string;
/**
* Raw JavaScript content to be injected into the frame.
*/
content?: string;
/**
* Set the script's `type`. Use `module` in order to load an ES2015 module.
*/
type?: string;
}
/**
* @public
*/
export interface FrameAddStyleTagOptions {
/**
* the URL of the CSS file to be added.
*/
url?: string;
/**
* The path to a CSS file to be injected into the frame.
* @remarks
* If `path` is a relative path, it is resolved relative to the current
* working directory (`process.cwd()` in Node.js).
*/
path?: string;
/**
* Raw CSS content to be injected into the frame.
*/
content?: string;
}
/**
* At every point of time, page exposes its current frame tree via the
* {@link Page.mainFrame | page.mainFrame} and
* {@link Frame.childFrames | frame.childFrames} methods.
*
* @remarks
*
* `Frame` object lifecycles are controlled by three events that are all
* dispatched on the page object:
*
* - {@link PageEmittedEvents.FrameAttached}
*
* - {@link PageEmittedEvents.FrameNavigated}
*
* - {@link PageEmittedEvents.FrameDetached}
*
* @Example
* An example of dumping frame tree:
*
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* await page.goto('https://www.google.com/chrome/browser/canary.html');
* dumpFrameTree(page.mainFrame(), '');
* await browser.close();
*
* function dumpFrameTree(frame, indent) {
* console.log(indent + frame.url());
* for (const child of frame.childFrames()) {
* dumpFrameTree(child, indent + ' ');
* }
* }
* })();
* ```
*
* @Example
* An example of getting text from an iframe element:
*
* ```js
* const frame = page.frames().find(frame => frame.name() === 'myframe');
* const text = await frame.$eval('.selector', element => element.textContent);
* console.log(text);
* ```
*
* @public
*/
export declare class Frame {
/**
* @internal
*/
_frameManager: FrameManager;
private _parentFrame?;
/**
* @internal
*/
_id: string;
private _url;
private _detached;
/**
* @internal
*/
_loaderId: string;
/**
* @internal
*/
_name?: string;
/**
* @internal
*/
_lifecycleEvents: Set<string>;
/**
* @internal
*/
_mainWorld: DOMWorld;
/**
* @internal
*/
_secondaryWorld: DOMWorld;
/**
* @internal
*/
_childFrames: Set<Frame>;
/**
* @internal
*/
_client: CDPSession;
/**
* @internal
*/
constructor(frameManager: FrameManager, parentFrame: Frame | null, frameId: string, client: CDPSession);
/**
* @internal
*/
_updateClient(client: CDPSession): void;
/**
* @remarks
*
* @returns `true` if the frame is an OOP frame, or `false` otherwise.
*/
isOOPFrame(): boolean;
/**
* @remarks
*
* `frame.goto` will throw an error if:
* - there's an SSL error (e.g. in case of self-signed certificates).
*
* - target URL is invalid.
*
* - the `timeout` is exceeded during navigation.
*
* - the remote server does not respond or is unreachable.
*
* - the main resource failed to load.
*
* `frame.goto` will not throw an error when any valid HTTP status code is
* returned by the remote server, including 404 "Not Found" and 500 "Internal
* Server Error". The status code for such responses can be retrieved by
* calling {@link HTTPResponse.status}.
*
* NOTE: `frame.goto` either throws an error or returns a main resource
* response. The only exceptions are navigation to `about:blank` or
* navigation to the same URL with a different hash, which would succeed and
* return `null`.
*
* NOTE: Headless mode doesn't support navigation to a PDF document. See
* the {@link https://bugs.chromium.org/p/chromium/issues/detail?id=761295 | upstream
* issue}.
*
* @param url - the URL to navigate the frame to. This should include the
* scheme, e.g. `https://`.
* @param options - navigation options. `waitUntil` is useful to define when
* the navigation should be considered successful - see the docs for
* {@link PuppeteerLifeCycleEvent} for more details.
*
* @returns A promise which resolves to the main resource response. In case of
* multiple redirects, the navigation will resolve with the response of the
* last redirect.
*/
goto(url: string, options?: {
referer?: string;
timeout?: number;
waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[];
}): Promise<HTTPResponse | null>;
/**
* @remarks
*
* This resolves when the frame navigates to a new URL. It is useful for when
* you run code which will indirectly cause the frame to navigate. Consider
* this example:
*
* ```js
* const [response] = await Promise.all([
* // The navigation promise resolves after navigation has finished
* frame.waitForNavigation(),
* // Clicking the link will indirectly cause a navigation
* frame.click('a.my-link'),
* ]);
* ```
*
* Usage of the {@link https://developer.mozilla.org/en-US/docs/Web/API/History_API | History API} to change the URL is considered a navigation.
*
* @param options - options to configure when the navigation is consided finished.
* @returns a promise that resolves when the frame navigates to a new URL.
*/
waitForNavigation(options?: {
timeout?: number;
waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[];
}): Promise<HTTPResponse | null>;
/**
* @internal
*/
client(): CDPSession;
/**
* @returns a promise that resolves to the frame's default execution context.
*/
executionContext(): Promise<ExecutionContext>;
/**
* @remarks
*
* The only difference between {@link Frame.evaluate} and
* `frame.evaluateHandle` is that `evaluateHandle` will return the value
* wrapped in an in-page object.
*
* This method behaves identically to {@link Page.evaluateHandle} except it's
* run within the context of the `frame`, rather than the entire page.
*
* @param pageFunction - a function that is run within the frame
* @param args - arguments to be passed to the pageFunction
*/
evaluateHandle<HandlerType extends JSHandle = JSHandle>(pageFunction: EvaluateHandleFn, ...args: SerializableOrJSHandle[]): Promise<HandlerType>;
/**
* @remarks
*
* This method behaves identically to {@link Page.evaluate} except it's run
* within the context of the `frame`, rather than the entire page.
*
* @param pageFunction - a function that is run within the frame
* @param args - arguments to be passed to the pageFunction
*/
evaluate<T extends EvaluateFn>(pageFunction: T, ...args: SerializableOrJSHandle[]): Promise<UnwrapPromiseLike<EvaluateFnReturnType<T>>>;
/**
* This method queries the frame for the given selector.
*
* @param selector - a selector to query for.
* @returns A promise which resolves to an `ElementHandle` pointing at the
* element, or `null` if it was not found.
*/
$<T extends Element = Element>(selector: string): Promise<ElementHandle<T> | null>;
/**
* This method evaluates the given XPath expression and returns the results.
*
* @param expression - the XPath expression to evaluate.
*/
$x(expression: string): Promise<ElementHandle[]>;
/**
* @remarks
*
* This method runs `document.querySelector` within
* the frame and passes it as the first argument to `pageFunction`.
*
* If `pageFunction` returns a Promise, then `frame.$eval` would wait for
* the promise to resolve and return its value.
*
* @example
*
* ```js
* const searchValue = await frame.$eval('#search', el => el.value);
* ```
*
* @param selector - the selector to query for
* @param pageFunction - the function to be evaluated in the frame's context
* @param args - additional arguments to pass to `pageFunction`
*/
$eval<ReturnType>(selector: string, pageFunction: (element: Element, ...args: unknown[]) => ReturnType | Promise<ReturnType>, ...args: SerializableOrJSHandle[]): Promise<WrapElementHandle<ReturnType>>;
/**
* @remarks
*
* This method runs `Array.from(document.querySelectorAll(selector))` within
* the frame and passes it as the first argument to `pageFunction`.
*
* If `pageFunction` returns a Promise, then `frame.$$eval` would wait for
* the promise to resolve and return its value.
*
* @example
*
* ```js
* const divsCounts = await frame.$$eval('div', divs => divs.length);
* ```
*
* @param selector - the selector to query for
* @param pageFunction - the function to be evaluated in the frame's context
* @param args - additional arguments to pass to `pageFunction`
*/
$$eval<ReturnType>(selector: string, pageFunction: (elements: Element[], ...args: unknown[]) => ReturnType | Promise<ReturnType>, ...args: SerializableOrJSHandle[]): Promise<WrapElementHandle<ReturnType>>;
/**
* This runs `document.querySelectorAll` in the frame and returns the result.
*
* @param selector - a selector to search for
* @returns An array of element handles pointing to the found frame elements.
*/
$$<T extends Element = Element>(selector: string): Promise<Array<ElementHandle<T>>>;
/**
* @returns the full HTML contents of the frame, including the doctype.
*/
content(): Promise<string>;
/**
* Set the content of the frame.
*
* @param html - HTML markup to assign to the page.
* @param options - options to configure how long before timing out and at
* what point to consider the content setting successful.
*/
setContent(html: string, options?: {
timeout?: number;
waitUntil?: PuppeteerLifeCycleEvent | PuppeteerLifeCycleEvent[];
}): Promise<void>;
/**
* @remarks
*
* If the name is empty, it returns the `id` attribute instead.
*
* Note: This value is calculated once when the frame is created, and will not
* update if the attribute is changed later.
*
* @returns the frame's `name` attribute as specified in the tag.
*/
name(): string;
/**
* @returns the frame's URL.
*/
url(): string;
/**
* @returns the parent `Frame`, if any. Detached and main frames return `null`.
*/
parentFrame(): Frame | null;
/**
* @returns an array of child frames.
*/
childFrames(): Frame[];
/**
* @returns `true` if the frame has been detached, or `false` otherwise.
*/
isDetached(): boolean;
/**
* Adds a `<script>` tag into the page with the desired url or content.
*
* @param options - configure the script to add to the page.
*
* @returns a promise that resolves to the added tag when the script's
* `onload` event fires or when the script content was injected into the
* frame.
*/
addScriptTag(options: FrameAddScriptTagOptions): Promise<ElementHandle>;
/**
* Adds a `<link rel="stylesheet">` tag into the page with the desired url or
* a `<style type="text/css">` tag with the content.
*
* @param options - configure the CSS to add to the page.
*
* @returns a promise that resolves to the added tag when the stylesheets's
* `onload` event fires or when the CSS content was injected into the
* frame.
*/
addStyleTag(options: FrameAddStyleTagOptions): Promise<ElementHandle>;
/**
*
* This method clicks the first element found that matches `selector`.
*
* @remarks
*
* This method scrolls the element into view if needed, and then uses
* {@link Page.mouse} to click in the center of the element. If there's no
* element matching `selector`, the method throws an error.
*
* Bear in mind that if `click()` triggers a navigation event and there's a
* separate `page.waitForNavigation()` promise to be resolved, you may end up
* with a race condition that yields unexpected results. The correct pattern
* for click and wait for navigation is the following:
*
* ```javascript
* const [response] = await Promise.all([
* page.waitForNavigation(waitOptions),
* frame.click(selector, clickOptions),
* ]);
* ```
* @param selector - the selector to search for to click. If there are
* multiple elements, the first will be clicked.
*/
click(selector: string, options?: {
delay?: number;
button?: MouseButton;
clickCount?: number;
}): Promise<void>;
/**
* This method fetches an element with `selector` and focuses it.
*
* @remarks
* If there's no element matching `selector`, the method throws an error.
*
* @param selector - the selector for the element to focus. If there are
* multiple elements, the first will be focused.
*/
focus(selector: string): Promise<void>;
/**
* This method fetches an element with `selector`, scrolls it into view if
* needed, and then uses {@link Page.mouse} to hover over the center of the
* element.
*
* @remarks
* If there's no element matching `selector`, the method throws an
*
* @param selector - the selector for the element to hover. If there are
* multiple elements, the first will be hovered.
*/
hover(selector: string): Promise<void>;
/**
* Triggers a `change` and `input` event once all the provided options have
* been selected.
*
* @remarks
*
* If there's no `<select>` element matching `selector`, the
* method throws an error.
*
* @example
* ```js
* frame.select('select#colors', 'blue'); // single selection
* frame.select('select#colors', 'red', 'green', 'blue'); // multiple selections
* ```
*
* @param selector - a selector to query the frame for
* @param values - an array of values to select. If the `<select>` has the
* `multiple` attribute, all values are considered, otherwise only the first
* one is taken into account.
* @returns the list of values that were successfully selected.
*/
select(selector: string, ...values: string[]): Promise<string[]>;
/**
* This method fetches an element with `selector`, scrolls it into view if
* needed, and then uses {@link Page.touchscreen} to tap in the center of the
* element.
*
* @remarks
*
* If there's no element matching `selector`, the method throws an error.
*
* @param selector - the selector to tap.
* @returns a promise that resolves when the element has been tapped.
*/
tap(selector: string): Promise<void>;
/**
* Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character
* in the text.
*
* @remarks
* To press a special key, like `Control` or `ArrowDown`, use
* {@link Keyboard.press}.
*
* @example
* ```js
* await frame.type('#mytextarea', 'Hello'); // Types instantly
* await frame.type('#mytextarea', 'World', {delay: 100}); // Types slower, like a user
* ```
*
* @param selector - the selector for the element to type into. If there are
* multiple the first will be used.
* @param text - text to type into the element
* @param options - takes one option, `delay`, which sets the time to wait
* between key presses in milliseconds. Defaults to `0`.
*
* @returns a promise that resolves when the typing is complete.
*/
type(selector: string, text: string, options?: {
delay: number;
}): Promise<void>;
/**
* @remarks
*
* This method behaves differently depending on the first parameter. If it's a
* `string`, it will be treated as a `selector` or `xpath` (if the string
* starts with `//`). This method then is a shortcut for
* {@link Frame.waitForSelector} or {@link Frame.waitForXPath}.
*
* If the first argument is a function this method is a shortcut for
* {@link Frame.waitForFunction}.
*
* If the first argument is a `number`, it's treated as a timeout in
* milliseconds and the method returns a promise which resolves after the
* timeout.
*
* @param selectorOrFunctionOrTimeout - a selector, predicate or timeout to
* wait for.
* @param options - optional waiting parameters.
* @param args - arguments to pass to `pageFunction`.
*
* @deprecated Don't use this method directly. Instead use the more explicit
* methods available: {@link Frame.waitForSelector},
* {@link Frame.waitForXPath}, {@link Frame.waitForFunction} or
* {@link Frame.waitForTimeout}.
*/
waitFor(selectorOrFunctionOrTimeout: string | number | Function, options?: Record<string, unknown>, ...args: SerializableOrJSHandle[]): Promise<JSHandle | null>;
/**
* Causes your script to wait for the given number of milliseconds.
*
* @remarks
* It's generally recommended to not wait for a number of seconds, but instead
* use {@link Frame.waitForSelector}, {@link Frame.waitForXPath} or
* {@link Frame.waitForFunction} to wait for exactly the conditions you want.
*
* @example
*
* Wait for 1 second:
*
* ```
* await frame.waitForTimeout(1000);
* ```
*
* @param milliseconds - the number of milliseconds to wait.
*/
waitForTimeout(milliseconds: number): Promise<void>;
/**
* @remarks
*
*
* Wait for the `selector` to appear in page. If at the moment of calling the
* method the `selector` already exists, the method will return immediately.
* If the selector doesn't appear after the `timeout` milliseconds of waiting,
* the function will throw.
*
* This method works across navigations.
*
* @example
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* const browser = await puppeteer.launch();
* const page = await browser.newPage();
* let currentURL;
* page.mainFrame()
* .waitForSelector('img')
* .then(() => console.log('First URL with image: ' + currentURL));
*
* for (currentURL of ['https://example.com', 'https://google.com', 'https://bbc.com']) {
* await page.goto(currentURL);
* }
* await browser.close();
* })();
* ```
* @param selector - the selector to wait for.
* @param options - options to define if the element should be visible and how
* long to wait before timing out.
* @returns a promise which resolves when an element matching the selector
* string is added to the DOM.
*/
waitForSelector(selector: string, options?: WaitForSelectorOptions): Promise<ElementHandle | null>;
/**
* @remarks
* Wait for the `xpath` to appear in page. If at the moment of calling the
* method the `xpath` already exists, the method will return immediately. If
* the xpath doesn't appear after the `timeout` milliseconds of waiting, the
* function will throw.
*
* For a code example, see the example for {@link Frame.waitForSelector}. That
* function behaves identically other than taking a CSS selector rather than
* an XPath.
*
* @param xpath - the XPath expression to wait for.
* @param options - options to configure the visiblity of the element and how
* long to wait before timing out.
*/
waitForXPath(xpath: string, options?: WaitForSelectorOptions): Promise<ElementHandle | null>;
/**
* @remarks
*
* @example
*
* The `waitForFunction` can be used to observe viewport size change:
* ```js
* const puppeteer = require('puppeteer');
*
* (async () => {
* . const browser = await puppeteer.launch();
* . const page = await browser.newPage();
* . const watchDog = page.mainFrame().waitForFunction('window.innerWidth < 100');
* . page.setViewport({width: 50, height: 50});
* . await watchDog;
* . await browser.close();
* })();
* ```
*
* To pass arguments from Node.js to the predicate of `page.waitForFunction` function:
*
* ```js
* const selector = '.foo';
* await frame.waitForFunction(
* selector => !!document.querySelector(selector),
* {}, // empty options object
* selector
*);
* ```
*
* @param pageFunction - the function to evaluate in the frame context.
* @param options - options to configure the polling method and timeout.
* @param args - arguments to pass to the `pageFunction`.
* @returns the promise which resolve when the `pageFunction` returns a truthy value.
*/
waitForFunction(pageFunction: Function | string, options?: FrameWaitForFunctionOptions, ...args: SerializableOrJSHandle[]): Promise<JSHandle>;
/**
* @returns the frame's title.
*/
title(): Promise<string>;
/**
* @internal
*/
_navigated(framePayload: Protocol.Page.Frame): void;
/**
* @internal
*/
_navigatedWithinDocument(url: string): void;
/**
* @internal
*/
_onLifecycleEvent(loaderId: string, name: string): void;
/**
* @internal
*/
_onLoadingStopped(): void;
/**
* @internal
*/
_detach(): void;
}
//# sourceMappingURL=FrameManager.d.ts.map

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,387 @@
/// <reference types="node" />
/**
* 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.
*/
import { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping.js';
import { EventEmitter } from './EventEmitter.js';
import { Frame } from './FrameManager.js';
import { HTTPResponse } from './HTTPResponse.js';
import { Protocol } from 'devtools-protocol';
/**
* @public
*/
export interface ContinueRequestOverrides {
/**
* If set, the request URL will change. This is not a redirect.
*/
url?: string;
method?: string;
postData?: string;
headers?: Record<string, string>;
}
/**
* @public
*/
export interface InterceptResolutionState {
action: InterceptResolutionAction;
priority?: number;
}
/**
* Required response data to fulfill a request with.
*
* @public
*/
export interface ResponseForRequest {
status: number;
/**
* Optional response headers. All values are converted to strings.
*/
headers: Record<string, unknown>;
contentType: string;
body: string | Buffer;
}
/**
* Resource types for HTTPRequests as perceived by the rendering engine.
*
* @public
*/
export declare type ResourceType = Lowercase<Protocol.Network.ResourceType>;
/**
* The default cooperative request interception resolution priority
*
* @public
*/
export declare const DEFAULT_INTERCEPT_RESOLUTION_PRIORITY = 0;
interface CDPSession extends EventEmitter {
send<T extends keyof ProtocolMapping.Commands>(method: T, ...paramArgs: ProtocolMapping.Commands[T]['paramsType']): Promise<ProtocolMapping.Commands[T]['returnType']>;
}
/**
*
* Represents an HTTP request sent by a page.
* @remarks
*
* Whenever the page sends a request, such as for a network resource, the
* following events are emitted by Puppeteer's `page`:
*
* - `request`: emitted when the request is issued by the page.
* - `requestfinished` - emitted when the response body is downloaded and the
* request is complete.
*
* If request fails at some point, then instead of `requestfinished` event the
* `requestfailed` event is emitted.
*
* All of these events provide an instance of `HTTPRequest` representing the
* request that occurred:
*
* ```
* page.on('request', request => ...)
* ```
*
* NOTE: HTTP Error responses, such as 404 or 503, are still successful
* responses from HTTP standpoint, so request will complete with
* `requestfinished` event.
*
* If request gets a 'redirect' response, the request is successfully finished
* with the `requestfinished` event, and a new request is issued to a
* redirected url.
*
* @public
*/
export declare class HTTPRequest {
/**
* @internal
*/
_requestId: string;
/**
* @internal
*/
_interceptionId: string;
/**
* @internal
*/
_failureText: any;
/**
* @internal
*/
_response: HTTPResponse | null;
/**
* @internal
*/
_fromMemoryCache: boolean;
/**
* @internal
*/
_redirectChain: HTTPRequest[];
private _client;
private _isNavigationRequest;
private _allowInterception;
private _interceptionHandled;
private _url;
private _resourceType;
private _method;
private _postData?;
private _headers;
private _frame;
private _continueRequestOverrides;
private _responseForRequest;
private _abortErrorReason;
private _interceptResolutionState;
private _interceptHandlers;
private _initiator;
/**
* @internal
*/
constructor(client: CDPSession, frame: Frame, interceptionId: string, allowInterception: boolean, event: Protocol.Network.RequestWillBeSentEvent, redirectChain: HTTPRequest[]);
/**
* @returns the URL of the request
*/
url(): string;
/**
* @returns the `ContinueRequestOverrides` that will be used
* if the interception is allowed to continue (ie, `abort()` and
* `respond()` aren't called).
*/
continueRequestOverrides(): ContinueRequestOverrides;
/**
* @returns The `ResponseForRequest` that gets used if the
* interception is allowed to respond (ie, `abort()` is not called).
*/
responseForRequest(): Partial<ResponseForRequest>;
/**
* @returns the most recent reason for aborting the request
*/
abortErrorReason(): Protocol.Network.ErrorReason;
/**
* @returns An InterceptResolutionState object describing the current resolution
* action and priority.
*
* InterceptResolutionState contains:
* action: InterceptResolutionAction
* priority?: number
*
* InterceptResolutionAction is one of: `abort`, `respond`, `continue`,
* `disabled`, `none`, or `already-handled`.
*/
interceptResolutionState(): InterceptResolutionState;
/**
* @returns `true` if the intercept resolution has already been handled,
* `false` otherwise.
*/
isInterceptResolutionHandled(): boolean;
/**
* Adds an async request handler to the processing queue.
* Deferred handlers are not guaranteed to execute in any particular order,
* but they are guaranteed to resolve before the request interception
* is finalized.
*/
enqueueInterceptAction(pendingHandler: () => void | PromiseLike<unknown>): void;
/**
* Awaits pending interception handlers and then decides how to fulfill
* the request interception.
*/
finalizeInterceptions(): Promise<void>;
/**
* Contains the request's resource type as it was perceived by the rendering
* engine.
*/
resourceType(): ResourceType;
/**
* @returns the method used (`GET`, `POST`, etc.)
*/
method(): string;
/**
* @returns the request's post body, if any.
*/
postData(): string | undefined;
/**
* @returns an object with HTTP headers associated with the request. All
* header names are lower-case.
*/
headers(): Record<string, string>;
/**
* @returns A matching `HTTPResponse` object, or null if the response has not
* been received yet.
*/
response(): HTTPResponse | null;
/**
* @returns the frame that initiated the request, or null if navigating to
* error pages.
*/
frame(): Frame | null;
/**
* @returns true if the request is the driver of the current frame's navigation.
*/
isNavigationRequest(): boolean;
/**
* @returns the initiator of the request.
*/
initiator(): Protocol.Network.Initiator;
/**
* A `redirectChain` is a chain of requests initiated to fetch a resource.
* @remarks
*
* `redirectChain` is shared between all the requests of the same chain.
*
* For example, if the website `http://example.com` has a single redirect to
* `https://example.com`, then the chain will contain one request:
*
* ```js
* const response = await page.goto('http://example.com');
* const chain = response.request().redirectChain();
* console.log(chain.length); // 1
* console.log(chain[0].url()); // 'http://example.com'
* ```
*
* If the website `https://google.com` has no redirects, then the chain will be empty:
*
* ```js
* const response = await page.goto('https://google.com');
* const chain = response.request().redirectChain();
* console.log(chain.length); // 0
* ```
*
* @returns the chain of requests - if a server responds with at least a
* single redirect, this chain will contain all requests that were redirected.
*/
redirectChain(): HTTPRequest[];
/**
* Access information about the request's failure.
*
* @remarks
*
* @example
*
* Example of logging all failed requests:
*
* ```js
* page.on('requestfailed', request => {
* console.log(request.url() + ' ' + request.failure().errorText);
* });
* ```
*
* @returns `null` unless the request failed. If the request fails this can
* return an object with `errorText` containing a human-readable error
* message, e.g. `net::ERR_FAILED`. It is not guaranteed that there will be
* failure text if the request fails.
*/
failure(): {
errorText: string;
} | null;
/**
* Continues request with optional request overrides.
*
* @remarks
*
* To use this, request
* interception should be enabled with {@link Page.setRequestInterception}.
*
* Exception is immediately thrown if the request interception is not enabled.
*
* @example
* ```js
* await page.setRequestInterception(true);
* page.on('request', request => {
* // Override headers
* const headers = Object.assign({}, request.headers(), {
* foo: 'bar', // set "foo" header
* origin: undefined, // remove "origin" header
* });
* request.continue({headers});
* });
* ```
*
* @param overrides - optional overrides to apply to the request.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*/
continue(overrides?: ContinueRequestOverrides, priority?: number): Promise<void>;
private _continue;
/**
* Fulfills a request with the given response.
*
* @remarks
*
* To use this, request
* interception should be enabled with {@link Page.setRequestInterception}.
*
* Exception is immediately thrown if the request interception is not enabled.
*
* @example
* An example of fulfilling all requests with 404 responses:
* ```js
* await page.setRequestInterception(true);
* page.on('request', request => {
* request.respond({
* status: 404,
* contentType: 'text/plain',
* body: 'Not Found!'
* });
* });
* ```
*
* NOTE: Mocking responses for dataURL requests is not supported.
* Calling `request.respond` for a dataURL request is a noop.
*
* @param response - the response to fulfill the request with.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*/
respond(response: Partial<ResponseForRequest>, priority?: number): Promise<void>;
private _respond;
/**
* Aborts a request.
*
* @remarks
* To use this, request interception should be enabled with
* {@link Page.setRequestInterception}. If it is not enabled, this method will
* throw an exception immediately.
*
* @param errorCode - optional error code to provide.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*/
abort(errorCode?: ErrorCode, priority?: number): Promise<void>;
private _abort;
}
/**
* @public
*/
export declare enum InterceptResolutionAction {
Abort = "abort",
Respond = "respond",
Continue = "continue",
Disabled = "disabled",
None = "none",
AlreadyHandled = "already-handled"
}
/**
* @public
*
* @deprecated please use {@link InterceptResolutionAction} instead.
*/
export declare type InterceptResolutionStrategy = InterceptResolutionAction;
/**
* @public
*/
export declare type ErrorCode = 'aborted' | 'accessdenied' | 'addressunreachable' | 'blockedbyclient' | 'blockedbyresponse' | 'connectionaborted' | 'connectionclosed' | 'connectionfailed' | 'connectionrefused' | 'connectionreset' | 'internetdisconnected' | 'namenotresolved' | 'timedout' | 'failed';
/**
* @public
*/
export declare type ActionResult = 'continue' | 'abort' | 'respond';
export {};
//# sourceMappingURL=HTTPRequest.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"HTTPRequest.d.ts","sourceRoot":"","sources":["../../../../src/common/HTTPRequest.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,594 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InterceptResolutionAction = exports.HTTPRequest = exports.DEFAULT_INTERCEPT_RESOLUTION_PRIORITY = void 0;
const assert_js_1 = require("./assert.js");
const helper_js_1 = require("./helper.js");
/**
* The default cooperative request interception resolution priority
*
* @public
*/
exports.DEFAULT_INTERCEPT_RESOLUTION_PRIORITY = 0;
/**
*
* Represents an HTTP request sent by a page.
* @remarks
*
* Whenever the page sends a request, such as for a network resource, the
* following events are emitted by Puppeteer's `page`:
*
* - `request`: emitted when the request is issued by the page.
* - `requestfinished` - emitted when the response body is downloaded and the
* request is complete.
*
* If request fails at some point, then instead of `requestfinished` event the
* `requestfailed` event is emitted.
*
* All of these events provide an instance of `HTTPRequest` representing the
* request that occurred:
*
* ```
* page.on('request', request => ...)
* ```
*
* NOTE: HTTP Error responses, such as 404 or 503, are still successful
* responses from HTTP standpoint, so request will complete with
* `requestfinished` event.
*
* If request gets a 'redirect' response, the request is successfully finished
* with the `requestfinished` event, and a new request is issued to a
* redirected url.
*
* @public
*/
class HTTPRequest {
/**
* @internal
*/
constructor(client, frame, interceptionId, allowInterception, event, redirectChain) {
/**
* @internal
*/
this._failureText = null;
/**
* @internal
*/
this._response = null;
/**
* @internal
*/
this._fromMemoryCache = false;
this._interceptionHandled = false;
this._headers = {};
this._client = client;
this._requestId = event.requestId;
this._isNavigationRequest =
event.requestId === event.loaderId && event.type === 'Document';
this._interceptionId = interceptionId;
this._allowInterception = allowInterception;
this._url = event.request.url;
this._resourceType = event.type.toLowerCase();
this._method = event.request.method;
this._postData = event.request.postData;
this._frame = frame;
this._redirectChain = redirectChain;
this._continueRequestOverrides = {};
this._interceptResolutionState = { action: InterceptResolutionAction.None };
this._interceptHandlers = [];
this._initiator = event.initiator;
for (const key of Object.keys(event.request.headers))
this._headers[key.toLowerCase()] = event.request.headers[key];
}
/**
* @returns the URL of the request
*/
url() {
return this._url;
}
/**
* @returns the `ContinueRequestOverrides` that will be used
* if the interception is allowed to continue (ie, `abort()` and
* `respond()` aren't called).
*/
continueRequestOverrides() {
(0, assert_js_1.assert)(this._allowInterception, 'Request Interception is not enabled!');
return this._continueRequestOverrides;
}
/**
* @returns The `ResponseForRequest` that gets used if the
* interception is allowed to respond (ie, `abort()` is not called).
*/
responseForRequest() {
(0, assert_js_1.assert)(this._allowInterception, 'Request Interception is not enabled!');
return this._responseForRequest;
}
/**
* @returns the most recent reason for aborting the request
*/
abortErrorReason() {
(0, assert_js_1.assert)(this._allowInterception, 'Request Interception is not enabled!');
return this._abortErrorReason;
}
/**
* @returns An InterceptResolutionState object describing the current resolution
* action and priority.
*
* InterceptResolutionState contains:
* action: InterceptResolutionAction
* priority?: number
*
* InterceptResolutionAction is one of: `abort`, `respond`, `continue`,
* `disabled`, `none`, or `already-handled`.
*/
interceptResolutionState() {
if (!this._allowInterception)
return { action: InterceptResolutionAction.Disabled };
if (this._interceptionHandled)
return { action: InterceptResolutionAction.AlreadyHandled };
return { ...this._interceptResolutionState };
}
/**
* @returns `true` if the intercept resolution has already been handled,
* `false` otherwise.
*/
isInterceptResolutionHandled() {
return this._interceptionHandled;
}
/**
* Adds an async request handler to the processing queue.
* Deferred handlers are not guaranteed to execute in any particular order,
* but they are guaranteed to resolve before the request interception
* is finalized.
*/
enqueueInterceptAction(pendingHandler) {
this._interceptHandlers.push(pendingHandler);
}
/**
* Awaits pending interception handlers and then decides how to fulfill
* the request interception.
*/
async finalizeInterceptions() {
await this._interceptHandlers.reduce((promiseChain, interceptAction) => promiseChain.then(interceptAction), Promise.resolve());
const { action } = this.interceptResolutionState();
switch (action) {
case 'abort':
return this._abort(this._abortErrorReason);
case 'respond':
return this._respond(this._responseForRequest);
case 'continue':
return this._continue(this._continueRequestOverrides);
}
}
/**
* Contains the request's resource type as it was perceived by the rendering
* engine.
*/
resourceType() {
return this._resourceType;
}
/**
* @returns the method used (`GET`, `POST`, etc.)
*/
method() {
return this._method;
}
/**
* @returns the request's post body, if any.
*/
postData() {
return this._postData;
}
/**
* @returns an object with HTTP headers associated with the request. All
* header names are lower-case.
*/
headers() {
return this._headers;
}
/**
* @returns A matching `HTTPResponse` object, or null if the response has not
* been received yet.
*/
response() {
return this._response;
}
/**
* @returns the frame that initiated the request, or null if navigating to
* error pages.
*/
frame() {
return this._frame;
}
/**
* @returns true if the request is the driver of the current frame's navigation.
*/
isNavigationRequest() {
return this._isNavigationRequest;
}
/**
* @returns the initiator of the request.
*/
initiator() {
return this._initiator;
}
/**
* A `redirectChain` is a chain of requests initiated to fetch a resource.
* @remarks
*
* `redirectChain` is shared between all the requests of the same chain.
*
* For example, if the website `http://example.com` has a single redirect to
* `https://example.com`, then the chain will contain one request:
*
* ```js
* const response = await page.goto('http://example.com');
* const chain = response.request().redirectChain();
* console.log(chain.length); // 1
* console.log(chain[0].url()); // 'http://example.com'
* ```
*
* If the website `https://google.com` has no redirects, then the chain will be empty:
*
* ```js
* const response = await page.goto('https://google.com');
* const chain = response.request().redirectChain();
* console.log(chain.length); // 0
* ```
*
* @returns the chain of requests - if a server responds with at least a
* single redirect, this chain will contain all requests that were redirected.
*/
redirectChain() {
return this._redirectChain.slice();
}
/**
* Access information about the request's failure.
*
* @remarks
*
* @example
*
* Example of logging all failed requests:
*
* ```js
* page.on('requestfailed', request => {
* console.log(request.url() + ' ' + request.failure().errorText);
* });
* ```
*
* @returns `null` unless the request failed. If the request fails this can
* return an object with `errorText` containing a human-readable error
* message, e.g. `net::ERR_FAILED`. It is not guaranteed that there will be
* failure text if the request fails.
*/
failure() {
if (!this._failureText)
return null;
return {
errorText: this._failureText,
};
}
/**
* Continues request with optional request overrides.
*
* @remarks
*
* To use this, request
* interception should be enabled with {@link Page.setRequestInterception}.
*
* Exception is immediately thrown if the request interception is not enabled.
*
* @example
* ```js
* await page.setRequestInterception(true);
* page.on('request', request => {
* // Override headers
* const headers = Object.assign({}, request.headers(), {
* foo: 'bar', // set "foo" header
* origin: undefined, // remove "origin" header
* });
* request.continue({headers});
* });
* ```
*
* @param overrides - optional overrides to apply to the request.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*/
async continue(overrides = {}, priority) {
// Request interception is not supported for data: urls.
if (this._url.startsWith('data:'))
return;
(0, assert_js_1.assert)(this._allowInterception, 'Request Interception is not enabled!');
(0, assert_js_1.assert)(!this._interceptionHandled, 'Request is already handled!');
if (priority === undefined) {
return this._continue(overrides);
}
this._continueRequestOverrides = overrides;
if (priority > this._interceptResolutionState.priority ||
this._interceptResolutionState.priority === undefined) {
this._interceptResolutionState = {
action: InterceptResolutionAction.Continue,
priority,
};
return;
}
if (priority === this._interceptResolutionState.priority) {
if (this._interceptResolutionState.action === 'abort' ||
this._interceptResolutionState.action === 'respond') {
return;
}
this._interceptResolutionState.action =
InterceptResolutionAction.Continue;
}
return;
}
async _continue(overrides = {}) {
const { url, method, postData, headers } = overrides;
this._interceptionHandled = true;
const postDataBinaryBase64 = postData
? Buffer.from(postData).toString('base64')
: undefined;
await this._client
.send('Fetch.continueRequest', {
requestId: this._interceptionId,
url,
method,
postData: postDataBinaryBase64,
headers: headers ? headersArray(headers) : undefined,
})
.catch((error) => {
this._interceptionHandled = false;
return handleError(error);
});
}
/**
* Fulfills a request with the given response.
*
* @remarks
*
* To use this, request
* interception should be enabled with {@link Page.setRequestInterception}.
*
* Exception is immediately thrown if the request interception is not enabled.
*
* @example
* An example of fulfilling all requests with 404 responses:
* ```js
* await page.setRequestInterception(true);
* page.on('request', request => {
* request.respond({
* status: 404,
* contentType: 'text/plain',
* body: 'Not Found!'
* });
* });
* ```
*
* NOTE: Mocking responses for dataURL requests is not supported.
* Calling `request.respond` for a dataURL request is a noop.
*
* @param response - the response to fulfill the request with.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*/
async respond(response, priority) {
// Mocking responses for dataURL requests is not currently supported.
if (this._url.startsWith('data:'))
return;
(0, assert_js_1.assert)(this._allowInterception, 'Request Interception is not enabled!');
(0, assert_js_1.assert)(!this._interceptionHandled, 'Request is already handled!');
if (priority === undefined) {
return this._respond(response);
}
this._responseForRequest = response;
if (priority > this._interceptResolutionState.priority ||
this._interceptResolutionState.priority === undefined) {
this._interceptResolutionState = {
action: InterceptResolutionAction.Respond,
priority,
};
return;
}
if (priority === this._interceptResolutionState.priority) {
if (this._interceptResolutionState.action === 'abort') {
return;
}
this._interceptResolutionState.action = InterceptResolutionAction.Respond;
}
}
async _respond(response) {
this._interceptionHandled = true;
const responseBody = response.body && helper_js_1.helper.isString(response.body)
? Buffer.from(response.body)
: response.body || null;
const responseHeaders = {};
if (response.headers) {
for (const header of Object.keys(response.headers)) {
const value = response.headers[header];
responseHeaders[header.toLowerCase()] = Array.isArray(value)
? value.map((item) => String(item))
: String(value);
}
}
if (response.contentType)
responseHeaders['content-type'] = response.contentType;
if (responseBody && !('content-length' in responseHeaders))
responseHeaders['content-length'] = String(Buffer.byteLength(responseBody));
await this._client
.send('Fetch.fulfillRequest', {
requestId: this._interceptionId,
responseCode: response.status || 200,
responsePhrase: STATUS_TEXTS[response.status || 200],
responseHeaders: headersArray(responseHeaders),
body: responseBody ? responseBody.toString('base64') : undefined,
})
.catch((error) => {
this._interceptionHandled = false;
return handleError(error);
});
}
/**
* Aborts a request.
*
* @remarks
* To use this, request interception should be enabled with
* {@link Page.setRequestInterception}. If it is not enabled, this method will
* throw an exception immediately.
*
* @param errorCode - optional error code to provide.
* @param priority - If provided, intercept is resolved using
* cooperative handling rules. Otherwise, intercept is resolved
* immediately.
*/
async abort(errorCode = 'failed', priority) {
// Request interception is not supported for data: urls.
if (this._url.startsWith('data:'))
return;
const errorReason = errorReasons[errorCode];
(0, assert_js_1.assert)(errorReason, 'Unknown error code: ' + errorCode);
(0, assert_js_1.assert)(this._allowInterception, 'Request Interception is not enabled!');
(0, assert_js_1.assert)(!this._interceptionHandled, 'Request is already handled!');
if (priority === undefined) {
return this._abort(errorReason);
}
this._abortErrorReason = errorReason;
if (priority >= this._interceptResolutionState.priority ||
this._interceptResolutionState.priority === undefined) {
this._interceptResolutionState = {
action: InterceptResolutionAction.Abort,
priority,
};
return;
}
}
async _abort(errorReason) {
this._interceptionHandled = true;
await this._client
.send('Fetch.failRequest', {
requestId: this._interceptionId,
errorReason,
})
.catch(handleError);
}
}
exports.HTTPRequest = HTTPRequest;
/**
* @public
*/
var InterceptResolutionAction;
(function (InterceptResolutionAction) {
InterceptResolutionAction["Abort"] = "abort";
InterceptResolutionAction["Respond"] = "respond";
InterceptResolutionAction["Continue"] = "continue";
InterceptResolutionAction["Disabled"] = "disabled";
InterceptResolutionAction["None"] = "none";
InterceptResolutionAction["AlreadyHandled"] = "already-handled";
})(InterceptResolutionAction = exports.InterceptResolutionAction || (exports.InterceptResolutionAction = {}));
const errorReasons = {
aborted: 'Aborted',
accessdenied: 'AccessDenied',
addressunreachable: 'AddressUnreachable',
blockedbyclient: 'BlockedByClient',
blockedbyresponse: 'BlockedByResponse',
connectionaborted: 'ConnectionAborted',
connectionclosed: 'ConnectionClosed',
connectionfailed: 'ConnectionFailed',
connectionrefused: 'ConnectionRefused',
connectionreset: 'ConnectionReset',
internetdisconnected: 'InternetDisconnected',
namenotresolved: 'NameNotResolved',
timedout: 'TimedOut',
failed: 'Failed',
};
function headersArray(headers) {
const result = [];
for (const name in headers) {
const value = headers[name];
if (!Object.is(value, undefined)) {
const values = Array.isArray(value) ? value : [value];
result.push(...values.map((value) => ({ name, value: value + '' })));
}
}
return result;
}
async function handleError(error) {
if (['Invalid header'].includes(error.originalMessage)) {
throw error;
}
// In certain cases, protocol will return error if the request was
// already canceled or the page was closed. We should tolerate these
// errors.
(0, helper_js_1.debugError)(error);
}
// List taken from
// https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
// with extra 306 and 418 codes.
const STATUS_TEXTS = {
'100': 'Continue',
'101': 'Switching Protocols',
'102': 'Processing',
'103': 'Early Hints',
'200': 'OK',
'201': 'Created',
'202': 'Accepted',
'203': 'Non-Authoritative Information',
'204': 'No Content',
'205': 'Reset Content',
'206': 'Partial Content',
'207': 'Multi-Status',
'208': 'Already Reported',
'226': 'IM Used',
'300': 'Multiple Choices',
'301': 'Moved Permanently',
'302': 'Found',
'303': 'See Other',
'304': 'Not Modified',
'305': 'Use Proxy',
'306': 'Switch Proxy',
'307': 'Temporary Redirect',
'308': 'Permanent Redirect',
'400': 'Bad Request',
'401': 'Unauthorized',
'402': 'Payment Required',
'403': 'Forbidden',
'404': 'Not Found',
'405': 'Method Not Allowed',
'406': 'Not Acceptable',
'407': 'Proxy Authentication Required',
'408': 'Request Timeout',
'409': 'Conflict',
'410': 'Gone',
'411': 'Length Required',
'412': 'Precondition Failed',
'413': 'Payload Too Large',
'414': 'URI Too Long',
'415': 'Unsupported Media Type',
'416': 'Range Not Satisfiable',
'417': 'Expectation Failed',
'418': "I'm a teapot",
'421': 'Misdirected Request',
'422': 'Unprocessable Entity',
'423': 'Locked',
'424': 'Failed Dependency',
'425': 'Too Early',
'426': 'Upgrade Required',
'428': 'Precondition Required',
'429': 'Too Many Requests',
'431': 'Request Header Fields Too Large',
'451': 'Unavailable For Legal Reasons',
'500': 'Internal Server Error',
'501': 'Not Implemented',
'502': 'Bad Gateway',
'503': 'Service Unavailable',
'504': 'Gateway Timeout',
'505': 'HTTP Version Not Supported',
'506': 'Variant Also Negotiates',
'507': 'Insufficient Storage',
'508': 'Loop Detected',
'510': 'Not Extended',
'511': 'Network Authentication Required',
};
//# sourceMappingURL=HTTPRequest.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,140 @@
/// <reference types="node" />
/**
* 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.
*/
import { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping.js';
import { EventEmitter } from './EventEmitter.js';
import { Frame } from './FrameManager.js';
import { HTTPRequest } from './HTTPRequest.js';
import { SecurityDetails } from './SecurityDetails.js';
import { Protocol } from 'devtools-protocol';
/**
* @public
*/
export interface RemoteAddress {
ip: string;
port: number;
}
interface CDPSession extends EventEmitter {
send<T extends keyof ProtocolMapping.Commands>(method: T, ...paramArgs: ProtocolMapping.Commands[T]['paramsType']): Promise<ProtocolMapping.Commands[T]['returnType']>;
}
/**
* The HTTPResponse class represents responses which are received by the
* {@link Page} class.
*
* @public
*/
export declare class HTTPResponse {
private _client;
private _request;
private _contentPromise;
private _bodyLoadedPromise;
private _bodyLoadedPromiseFulfill;
private _remoteAddress;
private _status;
private _statusText;
private _url;
private _fromDiskCache;
private _fromServiceWorker;
private _headers;
private _securityDetails;
private _timing;
/**
* @internal
*/
constructor(client: CDPSession, request: HTTPRequest, responsePayload: Protocol.Network.Response, extraInfo: Protocol.Network.ResponseReceivedExtraInfoEvent | null);
/**
* @internal
*/
_parseStatusTextFromExtrInfo(extraInfo: Protocol.Network.ResponseReceivedExtraInfoEvent | null): string | undefined;
/**
* @internal
*/
_resolveBody(err: Error | null): void;
/**
* @returns The IP address and port number used to connect to the remote
* server.
*/
remoteAddress(): RemoteAddress;
/**
* @returns The URL of the response.
*/
url(): string;
/**
* @returns True if the response was successful (status in the range 200-299).
*/
ok(): boolean;
/**
* @returns The status code of the response (e.g., 200 for a success).
*/
status(): number;
/**
* @returns The status text of the response (e.g. usually an "OK" for a
* success).
*/
statusText(): string;
/**
* @returns An object with HTTP headers associated with the response. All
* header names are lower-case.
*/
headers(): Record<string, string>;
/**
* @returns {@link SecurityDetails} if the response was received over the
* secure connection, or `null` otherwise.
*/
securityDetails(): SecurityDetails | null;
/**
* @returns Timing information related to the response.
*/
timing(): Protocol.Network.ResourceTiming | null;
/**
* @returns Promise which resolves to a buffer with response body.
*/
buffer(): Promise<Buffer>;
/**
* @returns Promise which resolves to a text representation of response body.
*/
text(): Promise<string>;
/**
*
* @returns Promise which resolves to a JSON representation of response body.
*
* @remarks
*
* This method will throw if the response body is not parsable via
* `JSON.parse`.
*/
json(): Promise<any>;
/**
* @returns A matching {@link HTTPRequest} object.
*/
request(): HTTPRequest;
/**
* @returns True if the response was served from either the browser's disk
* cache or memory cache.
*/
fromCache(): boolean;
/**
* @returns True if the response was served by a service worker.
*/
fromServiceWorker(): boolean;
/**
* @returns A {@link Frame} that initiated this response, or `null` if
* navigating to error pages.
*/
frame(): Frame | null;
}
export {};
//# sourceMappingURL=HTTPResponse.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"HTTPResponse.d.ts","sourceRoot":"","sources":["../../../../src/common/HTTPResponse.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AAE9E,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAG7C;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,UAAW,SAAQ,YAAY;IACvC,IAAI,CAAC,CAAC,SAAS,MAAM,eAAe,CAAC,QAAQ,EAC3C,MAAM,EAAE,CAAC,EACT,GAAG,SAAS,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,GACtD,OAAO,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;CACvD;AAED;;;;;GAKG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,kBAAkB,CAAwB;IAClD,OAAO,CAAC,yBAAyB,CAA8B;IAC/D,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,cAAc,CAAU;IAChC,OAAO,CAAC,kBAAkB,CAAU;IACpC,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,gBAAgB,CAAyB;IACjD,OAAO,CAAC,OAAO,CAAyC;IAExD;;OAEG;gBAED,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,WAAW,EACpB,eAAe,EAAE,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAC1C,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,8BAA8B,GAAG,IAAI;IA+BnE;;OAEG;IACH,4BAA4B,CAC1B,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,8BAA8B,GAAG,IAAI,GAChE,MAAM,GAAG,SAAS;IAWrB;;OAEG;IACH,YAAY,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI;IAIrC;;;OAGG;IACH,aAAa,IAAI,aAAa;IAI9B;;OAEG;IACH,GAAG,IAAI,MAAM;IAIb;;OAEG;IACH,EAAE,IAAI,OAAO;IAKb;;OAEG;IACH,MAAM,IAAI,MAAM;IAIhB;;;OAGG;IACH,UAAU,IAAI,MAAM;IAIpB;;;OAGG;IACH,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAIjC;;;OAGG;IACH,eAAe,IAAI,eAAe,GAAG,IAAI;IAIzC;;OAEG;IACH,MAAM,IAAI,QAAQ,CAAC,OAAO,CAAC,cAAc,GAAG,IAAI;IAIhD;;OAEG;IACH,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;IA6BzB;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;IAK7B;;;;;;;;OAQG;IACG,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC;IAK1B;;OAEG;IACH,OAAO,IAAI,WAAW;IAItB;;;OAGG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,iBAAiB,IAAI,OAAO;IAI5B;;;OAGG;IACH,KAAK,IAAI,KAAK,GAAG,IAAI;CAGtB"}

View File

@@ -0,0 +1,192 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.HTTPResponse = void 0;
const SecurityDetails_js_1 = require("./SecurityDetails.js");
const Errors_js_1 = require("./Errors.js");
/**
* The HTTPResponse class represents responses which are received by the
* {@link Page} class.
*
* @public
*/
class HTTPResponse {
/**
* @internal
*/
constructor(client, request, responsePayload, extraInfo) {
this._contentPromise = null;
this._headers = {};
this._client = client;
this._request = request;
this._bodyLoadedPromise = new Promise((fulfill) => {
this._bodyLoadedPromiseFulfill = fulfill;
});
this._remoteAddress = {
ip: responsePayload.remoteIPAddress,
port: responsePayload.remotePort,
};
this._statusText =
this._parseStatusTextFromExtrInfo(extraInfo) ||
responsePayload.statusText;
this._url = request.url();
this._fromDiskCache = !!responsePayload.fromDiskCache;
this._fromServiceWorker = !!responsePayload.fromServiceWorker;
this._status = extraInfo ? extraInfo.statusCode : responsePayload.status;
const headers = extraInfo ? extraInfo.headers : responsePayload.headers;
for (const key of Object.keys(headers))
this._headers[key.toLowerCase()] = headers[key];
this._securityDetails = responsePayload.securityDetails
? new SecurityDetails_js_1.SecurityDetails(responsePayload.securityDetails)
: null;
this._timing = responsePayload.timing;
}
/**
* @internal
*/
_parseStatusTextFromExtrInfo(extraInfo) {
if (!extraInfo || !extraInfo.headersText)
return;
const firstLine = extraInfo.headersText.split('\r', 1)[0];
if (!firstLine)
return;
const match = firstLine.match(/[^ ]* [^ ]* (.*)/);
if (!match)
return;
const statusText = match[1];
if (!statusText)
return;
return statusText;
}
/**
* @internal
*/
_resolveBody(err) {
return this._bodyLoadedPromiseFulfill(err);
}
/**
* @returns The IP address and port number used to connect to the remote
* server.
*/
remoteAddress() {
return this._remoteAddress;
}
/**
* @returns The URL of the response.
*/
url() {
return this._url;
}
/**
* @returns True if the response was successful (status in the range 200-299).
*/
ok() {
// TODO: document === 0 case?
return this._status === 0 || (this._status >= 200 && this._status <= 299);
}
/**
* @returns The status code of the response (e.g., 200 for a success).
*/
status() {
return this._status;
}
/**
* @returns The status text of the response (e.g. usually an "OK" for a
* success).
*/
statusText() {
return this._statusText;
}
/**
* @returns An object with HTTP headers associated with the response. All
* header names are lower-case.
*/
headers() {
return this._headers;
}
/**
* @returns {@link SecurityDetails} if the response was received over the
* secure connection, or `null` otherwise.
*/
securityDetails() {
return this._securityDetails;
}
/**
* @returns Timing information related to the response.
*/
timing() {
return this._timing;
}
/**
* @returns Promise which resolves to a buffer with response body.
*/
buffer() {
if (!this._contentPromise) {
this._contentPromise = this._bodyLoadedPromise.then(async (error) => {
if (error)
throw error;
try {
const response = await this._client.send('Network.getResponseBody', {
requestId: this._request._requestId,
});
return Buffer.from(response.body, response.base64Encoded ? 'base64' : 'utf8');
}
catch (error) {
if (error instanceof Errors_js_1.ProtocolError &&
error.originalMessage === 'No resource with given identifier found') {
throw new Errors_js_1.ProtocolError('Could not load body for this request. This might happen if the request is a preflight request.');
}
throw error;
}
});
}
return this._contentPromise;
}
/**
* @returns Promise which resolves to a text representation of response body.
*/
async text() {
const content = await this.buffer();
return content.toString('utf8');
}
/**
*
* @returns Promise which resolves to a JSON representation of response body.
*
* @remarks
*
* This method will throw if the response body is not parsable via
* `JSON.parse`.
*/
async json() {
const content = await this.text();
return JSON.parse(content);
}
/**
* @returns A matching {@link HTTPRequest} object.
*/
request() {
return this._request;
}
/**
* @returns True if the response was served from either the browser's disk
* cache or memory cache.
*/
fromCache() {
return this._fromDiskCache || this._request._fromMemoryCache;
}
/**
* @returns True if the response was served by a service worker.
*/
fromServiceWorker() {
return this._fromServiceWorker;
}
/**
* @returns A {@link Frame} that initiated this response, or `null` if
* navigating to error pages.
*/
frame() {
return this._request.frame();
}
}
exports.HTTPResponse = HTTPResponse;
//# sourceMappingURL=HTTPResponse.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"HTTPResponse.js","sourceRoot":"","sources":["../../../../src/common/HTTPResponse.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,359 @@
/**
* 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 { CDPSession } from './Connection.js';
import { KeyInput } from './USKeyboardLayout.js';
import { Protocol } from 'devtools-protocol';
import { Point } from './JSHandle.js';
/**
* Keyboard provides an api for managing a virtual keyboard.
* The high level api is {@link Keyboard."type"},
* which takes raw characters and generates proper keydown, keypress/input,
* and keyup events on your page.
*
* @remarks
* For finer control, you can use {@link Keyboard.down},
* {@link Keyboard.up}, and {@link Keyboard.sendCharacter}
* to manually fire events as if they were generated from a real keyboard.
*
* On MacOS, keyboard shortcuts like `⌘ A` -\> Select All do not work.
* See {@link https://github.com/puppeteer/puppeteer/issues/1313 | #1313}.
*
* @example
* An example of holding down `Shift` in order to select and delete some text:
* ```js
* await page.keyboard.type('Hello World!');
* await page.keyboard.press('ArrowLeft');
*
* await page.keyboard.down('Shift');
* for (let i = 0; i < ' World'.length; i++)
* await page.keyboard.press('ArrowLeft');
* await page.keyboard.up('Shift');
*
* await page.keyboard.press('Backspace');
* // Result text will end up saying 'Hello!'
* ```
*
* @example
* An example of pressing `A`
* ```js
* await page.keyboard.down('Shift');
* await page.keyboard.press('KeyA');
* await page.keyboard.up('Shift');
* ```
*
* @public
*/
export declare class Keyboard {
private _client;
/** @internal */
_modifiers: number;
private _pressedKeys;
/** @internal */
constructor(client: CDPSession);
/**
* Dispatches a `keydown` event.
*
* @remarks
* If `key` is a single character and no modifier keys besides `Shift`
* are being held down, a `keypress`/`input` event will also generated.
* The `text` option can be specified to force an input event to be generated.
* If `key` is a modifier key, `Shift`, `Meta`, `Control`, or `Alt`,
* subsequent key presses will be sent with that modifier active.
* To release the modifier key, use {@link Keyboard.up}.
*
* After the key is pressed once, subsequent calls to
* {@link Keyboard.down} will have
* {@link https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat | repeat}
* set to true. To release the key, use {@link Keyboard.up}.
*
* Modifier keys DO influence {@link Keyboard.down}.
* Holding down `Shift` will type the text in upper case.
*
* @param key - Name of key to press, such as `ArrowLeft`.
* See {@link KeyInput} for a list of all key names.
*
* @param options - An object of options. Accepts text which, if specified,
* generates an input event with this text.
*/
down(key: KeyInput, options?: {
text?: string;
}): Promise<void>;
private _modifierBit;
private _keyDescriptionForString;
/**
* Dispatches a `keyup` event.
*
* @param key - Name of key to release, such as `ArrowLeft`.
* See {@link KeyInput | KeyInput}
* for a list of all key names.
*/
up(key: KeyInput): Promise<void>;
/**
* Dispatches a `keypress` and `input` event.
* This does not send a `keydown` or `keyup` event.
*
* @remarks
* Modifier keys DO NOT effect {@link Keyboard.sendCharacter | Keyboard.sendCharacter}.
* Holding down `Shift` will not type the text in upper case.
*
* @example
* ```js
* page.keyboard.sendCharacter('嗨');
* ```
*
* @param char - Character to send into the page.
*/
sendCharacter(char: string): Promise<void>;
private charIsKey;
/**
* Sends a `keydown`, `keypress`/`input`,
* and `keyup` event for each character in the text.
*
* @remarks
* To press a special key, like `Control` or `ArrowDown`,
* use {@link Keyboard.press}.
*
* Modifier keys DO NOT effect `keyboard.type`.
* Holding down `Shift` will not type the text in upper case.
*
* @example
* ```js
* await page.keyboard.type('Hello'); // Types instantly
* await page.keyboard.type('World', {delay: 100}); // Types slower, like a user
* ```
*
* @param text - A text to type into a focused element.
* @param options - An object of options. Accepts delay which,
* if specified, is the time to wait between `keydown` and `keyup` in milliseconds.
* Defaults to 0.
*/
type(text: string, options?: {
delay?: number;
}): Promise<void>;
/**
* Shortcut for {@link Keyboard.down}
* and {@link Keyboard.up}.
*
* @remarks
* If `key` is a single character and no modifier keys besides `Shift`
* are being held down, a `keypress`/`input` event will also generated.
* The `text` option can be specified to force an input event to be generated.
*
* Modifier keys DO effect {@link Keyboard.press}.
* Holding down `Shift` will type the text in upper case.
*
* @param key - Name of key to press, such as `ArrowLeft`.
* See {@link KeyInput} for a list of all key names.
*
* @param options - An object of options. Accepts text which, if specified,
* generates an input event with this text. Accepts delay which,
* if specified, is the time to wait between `keydown` and `keyup` in milliseconds.
* Defaults to 0.
*/
press(key: KeyInput, options?: {
delay?: number;
text?: string;
}): Promise<void>;
}
/**
* @public
*/
export declare type MouseButton = 'left' | 'right' | 'middle' | 'back' | 'forward';
/**
* @public
*/
export interface MouseOptions {
button?: MouseButton;
clickCount?: number;
}
/**
* @public
*/
export interface MouseWheelOptions {
deltaX?: number;
deltaY?: number;
}
/**
* The Mouse class operates in main-frame CSS pixels
* relative to the top-left corner of the viewport.
* @remarks
* Every `page` object has its own Mouse, accessible with [`page.mouse`](#pagemouse).
*
* @example
* ```js
* // Using page.mouse to trace a 100x100 square.
* await page.mouse.move(0, 0);
* await page.mouse.down();
* await page.mouse.move(0, 100);
* await page.mouse.move(100, 100);
* await page.mouse.move(100, 0);
* await page.mouse.move(0, 0);
* await page.mouse.up();
* ```
*
* **Note**: The mouse events trigger synthetic `MouseEvent`s.
* This means that it does not fully replicate the functionality of what a normal user
* would be able to do with their mouse.
*
* For example, dragging and selecting text is not possible using `page.mouse`.
* Instead, you can use the {@link https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/getSelection | `DocumentOrShadowRoot.getSelection()`} functionality implemented in the platform.
*
* @example
* For example, if you want to select all content between nodes:
* ```js
* await page.evaluate((from, to) => {
* const selection = from.getRootNode().getSelection();
* const range = document.createRange();
* range.setStartBefore(from);
* range.setEndAfter(to);
* selection.removeAllRanges();
* selection.addRange(range);
* }, fromJSHandle, toJSHandle);
* ```
* If you then would want to copy-paste your selection, you can use the clipboard api:
* ```js
* // The clipboard api does not allow you to copy, unless the tab is focused.
* await page.bringToFront();
* await page.evaluate(() => {
* // Copy the selected content to the clipboard
* document.execCommand('copy');
* // Obtain the content of the clipboard as a string
* return navigator.clipboard.readText();
* });
* ```
* **Note**: If you want access to the clipboard API,
* you have to give it permission to do so:
* ```js
* await browser.defaultBrowserContext().overridePermissions(
* '<your origin>', ['clipboard-read', 'clipboard-write']
* );
* ```
* @public
*/
export declare class Mouse {
private _client;
private _keyboard;
private _x;
private _y;
private _button;
/**
* @internal
*/
constructor(client: CDPSession, keyboard: Keyboard);
/**
* Dispatches a `mousemove` event.
* @param x - Horizontal position of the mouse.
* @param y - Vertical position of the mouse.
* @param options - Optional object. If specified, the `steps` property
* sends intermediate `mousemove` events when set to `1` (default).
*/
move(x: number, y: number, options?: {
steps?: number;
}): Promise<void>;
/**
* Shortcut for `mouse.move`, `mouse.down` and `mouse.up`.
* @param x - Horizontal position of the mouse.
* @param y - Vertical position of the mouse.
* @param options - Optional `MouseOptions`.
*/
click(x: number, y: number, options?: MouseOptions & {
delay?: number;
}): Promise<void>;
/**
* Dispatches a `mousedown` event.
* @param options - Optional `MouseOptions`.
*/
down(options?: MouseOptions): Promise<void>;
/**
* Dispatches a `mouseup` event.
* @param options - Optional `MouseOptions`.
*/
up(options?: MouseOptions): Promise<void>;
/**
* Dispatches a `mousewheel` event.
* @param options - Optional: `MouseWheelOptions`.
*
* @example
* An example of zooming into an element:
* ```js
* await page.goto('https://mdn.mozillademos.org/en-US/docs/Web/API/Element/wheel_event$samples/Scaling_an_element_via_the_wheel?revision=1587366');
*
* const elem = await page.$('div');
* const boundingBox = await elem.boundingBox();
* await page.mouse.move(
* boundingBox.x + boundingBox.width / 2,
* boundingBox.y + boundingBox.height / 2
* );
*
* await page.mouse.wheel({ deltaY: -100 })
* ```
*/
wheel(options?: MouseWheelOptions): Promise<void>;
/**
* Dispatches a `drag` event.
* @param start - starting point for drag
* @param target - point to drag to
*/
drag(start: Point, target: Point): Promise<Protocol.Input.DragData>;
/**
* Dispatches a `dragenter` event.
* @param target - point for emitting `dragenter` event
* @param data - drag data containing items and operations mask
*/
dragEnter(target: Point, data: Protocol.Input.DragData): Promise<void>;
/**
* Dispatches a `dragover` event.
* @param target - point for emitting `dragover` event
* @param data - drag data containing items and operations mask
*/
dragOver(target: Point, data: Protocol.Input.DragData): Promise<void>;
/**
* Performs a dragenter, dragover, and drop in sequence.
* @param target - point to drop on
* @param data - drag data containing items and operations mask
*/
drop(target: Point, data: Protocol.Input.DragData): Promise<void>;
/**
* Performs a drag, dragenter, dragover, and drop in sequence.
* @param target - point to drag from
* @param target - point to drop on
* @param options - An object of options. Accepts delay which,
* if specified, is the time to wait between `dragover` and `drop` in milliseconds.
* Defaults to 0.
*/
dragAndDrop(start: Point, target: Point, options?: {
delay?: number;
}): Promise<void>;
}
/**
* The Touchscreen class exposes touchscreen events.
* @public
*/
export declare class Touchscreen {
private _client;
private _keyboard;
/**
* @internal
*/
constructor(client: CDPSession, keyboard: Keyboard);
/**
* Dispatches a `touchstart` and `touchend` event.
* @param x - Horizontal position of the tap.
* @param y - Vertical position of the tap.
*/
tap(x: number, y: number): Promise<void>;
}
//# sourceMappingURL=Input.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../../../src/common/Input.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,544 @@
"use strict";
/**
* 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Touchscreen = exports.Mouse = exports.Keyboard = void 0;
const assert_js_1 = require("./assert.js");
const USKeyboardLayout_js_1 = require("./USKeyboardLayout.js");
/**
* Keyboard provides an api for managing a virtual keyboard.
* The high level api is {@link Keyboard."type"},
* which takes raw characters and generates proper keydown, keypress/input,
* and keyup events on your page.
*
* @remarks
* For finer control, you can use {@link Keyboard.down},
* {@link Keyboard.up}, and {@link Keyboard.sendCharacter}
* to manually fire events as if they were generated from a real keyboard.
*
* On MacOS, keyboard shortcuts like `⌘ A` -\> Select All do not work.
* See {@link https://github.com/puppeteer/puppeteer/issues/1313 | #1313}.
*
* @example
* An example of holding down `Shift` in order to select and delete some text:
* ```js
* await page.keyboard.type('Hello World!');
* await page.keyboard.press('ArrowLeft');
*
* await page.keyboard.down('Shift');
* for (let i = 0; i < ' World'.length; i++)
* await page.keyboard.press('ArrowLeft');
* await page.keyboard.up('Shift');
*
* await page.keyboard.press('Backspace');
* // Result text will end up saying 'Hello!'
* ```
*
* @example
* An example of pressing `A`
* ```js
* await page.keyboard.down('Shift');
* await page.keyboard.press('KeyA');
* await page.keyboard.up('Shift');
* ```
*
* @public
*/
class Keyboard {
/** @internal */
constructor(client) {
/** @internal */
this._modifiers = 0;
this._pressedKeys = new Set();
this._client = client;
}
/**
* Dispatches a `keydown` event.
*
* @remarks
* If `key` is a single character and no modifier keys besides `Shift`
* are being held down, a `keypress`/`input` event will also generated.
* The `text` option can be specified to force an input event to be generated.
* If `key` is a modifier key, `Shift`, `Meta`, `Control`, or `Alt`,
* subsequent key presses will be sent with that modifier active.
* To release the modifier key, use {@link Keyboard.up}.
*
* After the key is pressed once, subsequent calls to
* {@link Keyboard.down} will have
* {@link https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat | repeat}
* set to true. To release the key, use {@link Keyboard.up}.
*
* Modifier keys DO influence {@link Keyboard.down}.
* Holding down `Shift` will type the text in upper case.
*
* @param key - Name of key to press, such as `ArrowLeft`.
* See {@link KeyInput} for a list of all key names.
*
* @param options - An object of options. Accepts text which, if specified,
* generates an input event with this text.
*/
async down(key, options = { text: undefined }) {
const description = this._keyDescriptionForString(key);
const autoRepeat = this._pressedKeys.has(description.code);
this._pressedKeys.add(description.code);
this._modifiers |= this._modifierBit(description.key);
const text = options.text === undefined ? description.text : options.text;
await this._client.send('Input.dispatchKeyEvent', {
type: text ? 'keyDown' : 'rawKeyDown',
modifiers: this._modifiers,
windowsVirtualKeyCode: description.keyCode,
code: description.code,
key: description.key,
text: text,
unmodifiedText: text,
autoRepeat,
location: description.location,
isKeypad: description.location === 3,
});
}
_modifierBit(key) {
if (key === 'Alt')
return 1;
if (key === 'Control')
return 2;
if (key === 'Meta')
return 4;
if (key === 'Shift')
return 8;
return 0;
}
_keyDescriptionForString(keyString) {
const shift = this._modifiers & 8;
const description = {
key: '',
keyCode: 0,
code: '',
text: '',
location: 0,
};
const definition = USKeyboardLayout_js_1.keyDefinitions[keyString];
(0, assert_js_1.assert)(definition, `Unknown key: "${keyString}"`);
if (definition.key)
description.key = definition.key;
if (shift && definition.shiftKey)
description.key = definition.shiftKey;
if (definition.keyCode)
description.keyCode = definition.keyCode;
if (shift && definition.shiftKeyCode)
description.keyCode = definition.shiftKeyCode;
if (definition.code)
description.code = definition.code;
if (definition.location)
description.location = definition.location;
if (description.key.length === 1)
description.text = description.key;
if (definition.text)
description.text = definition.text;
if (shift && definition.shiftText)
description.text = definition.shiftText;
// if any modifiers besides shift are pressed, no text should be sent
if (this._modifiers & ~8)
description.text = '';
return description;
}
/**
* Dispatches a `keyup` event.
*
* @param key - Name of key to release, such as `ArrowLeft`.
* See {@link KeyInput | KeyInput}
* for a list of all key names.
*/
async up(key) {
const description = this._keyDescriptionForString(key);
this._modifiers &= ~this._modifierBit(description.key);
this._pressedKeys.delete(description.code);
await this._client.send('Input.dispatchKeyEvent', {
type: 'keyUp',
modifiers: this._modifiers,
key: description.key,
windowsVirtualKeyCode: description.keyCode,
code: description.code,
location: description.location,
});
}
/**
* Dispatches a `keypress` and `input` event.
* This does not send a `keydown` or `keyup` event.
*
* @remarks
* Modifier keys DO NOT effect {@link Keyboard.sendCharacter | Keyboard.sendCharacter}.
* Holding down `Shift` will not type the text in upper case.
*
* @example
* ```js
* page.keyboard.sendCharacter('嗨');
* ```
*
* @param char - Character to send into the page.
*/
async sendCharacter(char) {
await this._client.send('Input.insertText', { text: char });
}
charIsKey(char) {
return !!USKeyboardLayout_js_1.keyDefinitions[char];
}
/**
* Sends a `keydown`, `keypress`/`input`,
* and `keyup` event for each character in the text.
*
* @remarks
* To press a special key, like `Control` or `ArrowDown`,
* use {@link Keyboard.press}.
*
* Modifier keys DO NOT effect `keyboard.type`.
* Holding down `Shift` will not type the text in upper case.
*
* @example
* ```js
* await page.keyboard.type('Hello'); // Types instantly
* await page.keyboard.type('World', {delay: 100}); // Types slower, like a user
* ```
*
* @param text - A text to type into a focused element.
* @param options - An object of options. Accepts delay which,
* if specified, is the time to wait between `keydown` and `keyup` in milliseconds.
* Defaults to 0.
*/
async type(text, options = {}) {
const delay = options.delay || null;
for (const char of text) {
if (this.charIsKey(char)) {
await this.press(char, { delay });
}
else {
if (delay)
await new Promise((f) => setTimeout(f, delay));
await this.sendCharacter(char);
}
}
}
/**
* Shortcut for {@link Keyboard.down}
* and {@link Keyboard.up}.
*
* @remarks
* If `key` is a single character and no modifier keys besides `Shift`
* are being held down, a `keypress`/`input` event will also generated.
* The `text` option can be specified to force an input event to be generated.
*
* Modifier keys DO effect {@link Keyboard.press}.
* Holding down `Shift` will type the text in upper case.
*
* @param key - Name of key to press, such as `ArrowLeft`.
* See {@link KeyInput} for a list of all key names.
*
* @param options - An object of options. Accepts text which, if specified,
* generates an input event with this text. Accepts delay which,
* if specified, is the time to wait between `keydown` and `keyup` in milliseconds.
* Defaults to 0.
*/
async press(key, options = {}) {
const { delay = null } = options;
await this.down(key, options);
if (delay)
await new Promise((f) => setTimeout(f, options.delay));
await this.up(key);
}
}
exports.Keyboard = Keyboard;
/**
* The Mouse class operates in main-frame CSS pixels
* relative to the top-left corner of the viewport.
* @remarks
* Every `page` object has its own Mouse, accessible with [`page.mouse`](#pagemouse).
*
* @example
* ```js
* // Using page.mouse to trace a 100x100 square.
* await page.mouse.move(0, 0);
* await page.mouse.down();
* await page.mouse.move(0, 100);
* await page.mouse.move(100, 100);
* await page.mouse.move(100, 0);
* await page.mouse.move(0, 0);
* await page.mouse.up();
* ```
*
* **Note**: The mouse events trigger synthetic `MouseEvent`s.
* This means that it does not fully replicate the functionality of what a normal user
* would be able to do with their mouse.
*
* For example, dragging and selecting text is not possible using `page.mouse`.
* Instead, you can use the {@link https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/getSelection | `DocumentOrShadowRoot.getSelection()`} functionality implemented in the platform.
*
* @example
* For example, if you want to select all content between nodes:
* ```js
* await page.evaluate((from, to) => {
* const selection = from.getRootNode().getSelection();
* const range = document.createRange();
* range.setStartBefore(from);
* range.setEndAfter(to);
* selection.removeAllRanges();
* selection.addRange(range);
* }, fromJSHandle, toJSHandle);
* ```
* If you then would want to copy-paste your selection, you can use the clipboard api:
* ```js
* // The clipboard api does not allow you to copy, unless the tab is focused.
* await page.bringToFront();
* await page.evaluate(() => {
* // Copy the selected content to the clipboard
* document.execCommand('copy');
* // Obtain the content of the clipboard as a string
* return navigator.clipboard.readText();
* });
* ```
* **Note**: If you want access to the clipboard API,
* you have to give it permission to do so:
* ```js
* await browser.defaultBrowserContext().overridePermissions(
* '<your origin>', ['clipboard-read', 'clipboard-write']
* );
* ```
* @public
*/
class Mouse {
/**
* @internal
*/
constructor(client, keyboard) {
this._x = 0;
this._y = 0;
this._button = 'none';
this._client = client;
this._keyboard = keyboard;
}
/**
* Dispatches a `mousemove` event.
* @param x - Horizontal position of the mouse.
* @param y - Vertical position of the mouse.
* @param options - Optional object. If specified, the `steps` property
* sends intermediate `mousemove` events when set to `1` (default).
*/
async move(x, y, options = {}) {
const { steps = 1 } = options;
const fromX = this._x, fromY = this._y;
this._x = x;
this._y = y;
for (let i = 1; i <= steps; i++) {
await this._client.send('Input.dispatchMouseEvent', {
type: 'mouseMoved',
button: this._button,
x: fromX + (this._x - fromX) * (i / steps),
y: fromY + (this._y - fromY) * (i / steps),
modifiers: this._keyboard._modifiers,
});
}
}
/**
* Shortcut for `mouse.move`, `mouse.down` and `mouse.up`.
* @param x - Horizontal position of the mouse.
* @param y - Vertical position of the mouse.
* @param options - Optional `MouseOptions`.
*/
async click(x, y, options = {}) {
const { delay = null } = options;
if (delay !== null) {
await this.move(x, y);
await this.down(options);
await new Promise((f) => setTimeout(f, delay));
await this.up(options);
}
else {
await this.move(x, y);
await this.down(options);
await this.up(options);
}
}
/**
* Dispatches a `mousedown` event.
* @param options - Optional `MouseOptions`.
*/
async down(options = {}) {
const { button = 'left', clickCount = 1 } = options;
this._button = button;
await this._client.send('Input.dispatchMouseEvent', {
type: 'mousePressed',
button,
x: this._x,
y: this._y,
modifiers: this._keyboard._modifiers,
clickCount,
});
}
/**
* Dispatches a `mouseup` event.
* @param options - Optional `MouseOptions`.
*/
async up(options = {}) {
const { button = 'left', clickCount = 1 } = options;
this._button = 'none';
await this._client.send('Input.dispatchMouseEvent', {
type: 'mouseReleased',
button,
x: this._x,
y: this._y,
modifiers: this._keyboard._modifiers,
clickCount,
});
}
/**
* Dispatches a `mousewheel` event.
* @param options - Optional: `MouseWheelOptions`.
*
* @example
* An example of zooming into an element:
* ```js
* await page.goto('https://mdn.mozillademos.org/en-US/docs/Web/API/Element/wheel_event$samples/Scaling_an_element_via_the_wheel?revision=1587366');
*
* const elem = await page.$('div');
* const boundingBox = await elem.boundingBox();
* await page.mouse.move(
* boundingBox.x + boundingBox.width / 2,
* boundingBox.y + boundingBox.height / 2
* );
*
* await page.mouse.wheel({ deltaY: -100 })
* ```
*/
async wheel(options = {}) {
const { deltaX = 0, deltaY = 0 } = options;
await this._client.send('Input.dispatchMouseEvent', {
type: 'mouseWheel',
x: this._x,
y: this._y,
deltaX,
deltaY,
modifiers: this._keyboard._modifiers,
pointerType: 'mouse',
});
}
/**
* Dispatches a `drag` event.
* @param start - starting point for drag
* @param target - point to drag to
*/
async drag(start, target) {
const promise = new Promise((resolve) => {
this._client.once('Input.dragIntercepted', (event) => resolve(event.data));
});
await this.move(start.x, start.y);
await this.down();
await this.move(target.x, target.y);
return promise;
}
/**
* Dispatches a `dragenter` event.
* @param target - point for emitting `dragenter` event
* @param data - drag data containing items and operations mask
*/
async dragEnter(target, data) {
await this._client.send('Input.dispatchDragEvent', {
type: 'dragEnter',
x: target.x,
y: target.y,
modifiers: this._keyboard._modifiers,
data,
});
}
/**
* Dispatches a `dragover` event.
* @param target - point for emitting `dragover` event
* @param data - drag data containing items and operations mask
*/
async dragOver(target, data) {
await this._client.send('Input.dispatchDragEvent', {
type: 'dragOver',
x: target.x,
y: target.y,
modifiers: this._keyboard._modifiers,
data,
});
}
/**
* Performs a dragenter, dragover, and drop in sequence.
* @param target - point to drop on
* @param data - drag data containing items and operations mask
*/
async drop(target, data) {
await this._client.send('Input.dispatchDragEvent', {
type: 'drop',
x: target.x,
y: target.y,
modifiers: this._keyboard._modifiers,
data,
});
}
/**
* Performs a drag, dragenter, dragover, and drop in sequence.
* @param target - point to drag from
* @param target - point to drop on
* @param options - An object of options. Accepts delay which,
* if specified, is the time to wait between `dragover` and `drop` in milliseconds.
* Defaults to 0.
*/
async dragAndDrop(start, target, options = {}) {
const { delay = null } = options;
const data = await this.drag(start, target);
await this.dragEnter(target, data);
await this.dragOver(target, data);
if (delay) {
await new Promise((resolve) => setTimeout(resolve, delay));
}
await this.drop(target, data);
await this.up();
}
}
exports.Mouse = Mouse;
/**
* The Touchscreen class exposes touchscreen events.
* @public
*/
class Touchscreen {
/**
* @internal
*/
constructor(client, keyboard) {
this._client = client;
this._keyboard = keyboard;
}
/**
* Dispatches a `touchstart` and `touchend` event.
* @param x - Horizontal position of the tap.
* @param y - Vertical position of the tap.
*/
async tap(x, y) {
const touchPoints = [{ x: Math.round(x), y: Math.round(y) }];
await this._client.send('Input.dispatchTouchEvent', {
type: 'touchStart',
touchPoints,
modifiers: this._keyboard._modifiers,
});
await this._client.send('Input.dispatchTouchEvent', {
type: 'touchEnd',
touchPoints: [],
modifiers: this._keyboard._modifiers,
});
}
}
exports.Touchscreen = Touchscreen;
//# sourceMappingURL=Input.js.map

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More