mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
chore: migrate src/JSHandle to TS (#5703)
* chore: migrate src/JSHandle to TS There's a few TODOs in here that all depend on typing the `ExecutionContext.evaluateHandle` properly so that you can properly declare what types you're expecting back. Once I've done that file (it's next on my list) I will loop back and improve the types here, fixing these TODOs. * Fix doclint for {}
This commit is contained in:
parent
42893d8755
commit
8d5d76ed70
@ -17,6 +17,9 @@
|
||||
// Used as a TypeDef
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const {CDPSession} = require('./Connection');
|
||||
// Used as a TypeDef
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const {ElementHandle} = require('./JSHandle');
|
||||
|
||||
/**
|
||||
* @typedef {Object} SerializedAXNode
|
||||
@ -64,7 +67,7 @@ class Accessibility {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{interestingOnly?: boolean, root?: ?Puppeteer.ElementHandle}=} options
|
||||
* @param {{interestingOnly?: boolean, root?: ?ElementHandle}=} options
|
||||
* @return {!Promise<!SerializedAXNode>}
|
||||
*/
|
||||
async snapshot(options = {}) {
|
||||
|
@ -18,6 +18,9 @@ const fs = require('fs');
|
||||
const {helper, assert} = require('./helper');
|
||||
const {LifecycleWatcher} = require('./LifecycleWatcher');
|
||||
const {TimeoutError} = require('./Errors');
|
||||
// Used as a TypeDef
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const {JSHandle, ElementHandle} = require('./JSHandle');
|
||||
|
||||
// Used as a TypeDef
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
@ -39,7 +42,7 @@ class DOMWorld {
|
||||
this._frame = frame;
|
||||
this._timeoutSettings = timeoutSettings;
|
||||
|
||||
/** @type {?Promise<!Puppeteer.ElementHandle>} */
|
||||
/** @type {?Promise<!ElementHandle>} */
|
||||
this._documentPromise = null;
|
||||
/** @type {!Promise<!Puppeteer.ExecutionContext>} */
|
||||
this._contextPromise;
|
||||
@ -100,7 +103,7 @@ class DOMWorld {
|
||||
/**
|
||||
* @param {Function|string} pageFunction
|
||||
* @param {!Array<*>} args
|
||||
* @return {!Promise<!Puppeteer.JSHandle>}
|
||||
* @return {!Promise<!JSHandle>}
|
||||
*/
|
||||
async evaluateHandle(pageFunction, ...args) {
|
||||
const context = await this.executionContext();
|
||||
@ -119,7 +122,7 @@ class DOMWorld {
|
||||
|
||||
/**
|
||||
* @param {string} selector
|
||||
* @return {!Promise<?Puppeteer.ElementHandle>}
|
||||
* @return {!Promise<?ElementHandle>}
|
||||
*/
|
||||
async $(selector) {
|
||||
const document = await this._document();
|
||||
@ -128,7 +131,7 @@ class DOMWorld {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!Promise<!Puppeteer.ElementHandle>}
|
||||
* @return {!Promise<!ElementHandle>}
|
||||
*/
|
||||
async _document() {
|
||||
if (this._documentPromise)
|
||||
@ -142,7 +145,7 @@ class DOMWorld {
|
||||
|
||||
/**
|
||||
* @param {string} expression
|
||||
* @return {!Promise<!Array<!Puppeteer.ElementHandle>>}
|
||||
* @return {!Promise<!Array<!ElementHandle>>}
|
||||
*/
|
||||
async $x(expression) {
|
||||
const document = await this._document();
|
||||
@ -175,7 +178,7 @@ class DOMWorld {
|
||||
|
||||
/**
|
||||
* @param {string} selector
|
||||
* @return {!Promise<!Array<!Puppeteer.ElementHandle>>}
|
||||
* @return {!Promise<!Array<!ElementHandle>>}
|
||||
*/
|
||||
async $$(selector) {
|
||||
const document = await this._document();
|
||||
@ -225,7 +228,7 @@ class DOMWorld {
|
||||
|
||||
/**
|
||||
* @param {!{url?: string, path?: string, content?: string, type?: string}} options
|
||||
* @return {!Promise<!Puppeteer.ElementHandle>}
|
||||
* @return {!Promise<!ElementHandle>}
|
||||
*/
|
||||
async addScriptTag(options) {
|
||||
const {
|
||||
@ -296,7 +299,7 @@ class DOMWorld {
|
||||
|
||||
/**
|
||||
* @param {!{url?: string, path?: string, content?: string}} options
|
||||
* @return {!Promise<!Puppeteer.ElementHandle>}
|
||||
* @return {!Promise<!ElementHandle>}
|
||||
*/
|
||||
async addStyleTag(options) {
|
||||
const {
|
||||
@ -431,7 +434,7 @@ class DOMWorld {
|
||||
/**
|
||||
* @param {string} selector
|
||||
* @param {!{visible?: boolean, hidden?: boolean, timeout?: number}=} options
|
||||
* @return {!Promise<?Puppeteer.ElementHandle>}
|
||||
* @return {!Promise<?ElementHandle>}
|
||||
*/
|
||||
waitForSelector(selector, options) {
|
||||
return this._waitForSelectorOrXPath(selector, false, options);
|
||||
@ -440,7 +443,7 @@ class DOMWorld {
|
||||
/**
|
||||
* @param {string} xpath
|
||||
* @param {!{visible?: boolean, hidden?: boolean, timeout?: number}=} options
|
||||
* @return {!Promise<?Puppeteer.ElementHandle>}
|
||||
* @return {!Promise<?ElementHandle>}
|
||||
*/
|
||||
waitForXPath(xpath, options) {
|
||||
return this._waitForSelectorOrXPath(xpath, true, options);
|
||||
@ -449,7 +452,7 @@ class DOMWorld {
|
||||
/**
|
||||
* @param {Function|string} pageFunction
|
||||
* @param {!{polling?: string|number, timeout?: number}=} options
|
||||
* @return {!Promise<!Puppeteer.JSHandle>}
|
||||
* @return {!Promise<!JSHandle>}
|
||||
*/
|
||||
waitForFunction(pageFunction, options = {}, ...args) {
|
||||
const {
|
||||
@ -470,7 +473,7 @@ class DOMWorld {
|
||||
* @param {string} selectorOrXPath
|
||||
* @param {boolean} isXPath
|
||||
* @param {!{visible?: boolean, hidden?: boolean, timeout?: number}=} options
|
||||
* @return {!Promise<?Puppeteer.ElementHandle>}
|
||||
* @return {!Promise<?ElementHandle>}
|
||||
*/
|
||||
async _waitForSelectorOrXPath(selectorOrXPath, isXPath, options = {}) {
|
||||
const {
|
||||
@ -568,7 +571,7 @@ class WaitTask {
|
||||
|
||||
async rerun() {
|
||||
const runCount = ++this._runCount;
|
||||
/** @type {?Puppeteer.JSHandle} */
|
||||
/** @type {?JSHandle} */
|
||||
let success = null;
|
||||
let error = null;
|
||||
try {
|
||||
|
@ -15,10 +15,12 @@
|
||||
*/
|
||||
|
||||
const {helper, assert} = require('./helper');
|
||||
const {createJSHandle, JSHandle} = require('./JSHandle');
|
||||
// Used as a TypeDef
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const {CDPSession} = require('./Connection');
|
||||
// Used as a TypeDef
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const {createJSHandle, JSHandle, ElementHandle} = require('./JSHandle');
|
||||
|
||||
const EVALUATION_SCRIPT_URL = '__puppeteer_evaluation_script__';
|
||||
const SOURCE_URL_REGEX = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/m;
|
||||
@ -187,19 +189,19 @@ class ExecutionContext {
|
||||
|
||||
/**
|
||||
* @param {Protocol.DOM.BackendNodeId} backendNodeId
|
||||
* @return {Promise<Puppeteer.ElementHandle>}
|
||||
* @return {Promise<ElementHandle>}
|
||||
*/
|
||||
async _adoptBackendNodeId(backendNodeId) {
|
||||
const {object} = await this._client.send('DOM.resolveNode', {
|
||||
backendNodeId: backendNodeId,
|
||||
executionContextId: this._contextId,
|
||||
});
|
||||
return /** @type {Puppeteer.ElementHandle}*/(createJSHandle(this, object));
|
||||
return /** @type {ElementHandle}*/(createJSHandle(this, object));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Puppeteer.ElementHandle} elementHandle
|
||||
* @return {Promise<Puppeteer.ElementHandle>}
|
||||
* @param {ElementHandle} elementHandle
|
||||
* @return {Promise<ElementHandle>}
|
||||
*/
|
||||
async _adoptElementHandle(elementHandle) {
|
||||
assert(elementHandle.executionContext() !== this, 'Cannot adopt handle that already belongs to this execution context');
|
||||
|
@ -27,6 +27,9 @@ const {TimeoutSettings} = require('./TimeoutSettings');
|
||||
// Used as a TypeDef
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const {CDPSession} = require('./Connection');
|
||||
// Used as a TypeDef
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const {JSHandle, ElementHandle} = require('./JSHandle');
|
||||
|
||||
const UTILITY_WORLD_NAME = '__puppeteer_utility_world__';
|
||||
|
||||
@ -432,7 +435,7 @@ class Frame {
|
||||
/**
|
||||
* @param {Function|string} pageFunction
|
||||
* @param {!Array<*>} args
|
||||
* @return {!Promise<!Puppeteer.JSHandle>}
|
||||
* @return {!Promise<!JSHandle>}
|
||||
*/
|
||||
async evaluateHandle(pageFunction, ...args) {
|
||||
return this._mainWorld.evaluateHandle(pageFunction, ...args);
|
||||
@ -449,7 +452,7 @@ class Frame {
|
||||
|
||||
/**
|
||||
* @param {string} selector
|
||||
* @return {!Promise<?Puppeteer.ElementHandle>}
|
||||
* @return {!Promise<?ElementHandle>}
|
||||
*/
|
||||
async $(selector) {
|
||||
return this._mainWorld.$(selector);
|
||||
@ -457,7 +460,7 @@ class Frame {
|
||||
|
||||
/**
|
||||
* @param {string} expression
|
||||
* @return {!Promise<!Array<!Puppeteer.ElementHandle>>}
|
||||
* @return {!Promise<!Array<!ElementHandle>>}
|
||||
*/
|
||||
async $x(expression) {
|
||||
return this._mainWorld.$x(expression);
|
||||
@ -485,7 +488,7 @@ class Frame {
|
||||
|
||||
/**
|
||||
* @param {string} selector
|
||||
* @return {!Promise<!Array<!Puppeteer.ElementHandle>>}
|
||||
* @return {!Promise<!Array<!ElementHandle>>}
|
||||
*/
|
||||
async $$(selector) {
|
||||
return this._mainWorld.$$(selector);
|
||||
@ -543,7 +546,7 @@ class Frame {
|
||||
|
||||
/**
|
||||
* @param {!{url?: string, path?: string, content?: string, type?: string}} options
|
||||
* @return {!Promise<!Puppeteer.ElementHandle>}
|
||||
* @return {!Promise<!ElementHandle>}
|
||||
*/
|
||||
async addScriptTag(options) {
|
||||
return this._mainWorld.addScriptTag(options);
|
||||
@ -551,7 +554,7 @@ class Frame {
|
||||
|
||||
/**
|
||||
* @param {!{url?: string, path?: string, content?: string}} options
|
||||
* @return {!Promise<!Puppeteer.ElementHandle>}
|
||||
* @return {!Promise<!ElementHandle>}
|
||||
*/
|
||||
async addStyleTag(options) {
|
||||
return this._mainWorld.addStyleTag(options);
|
||||
@ -608,7 +611,7 @@ class Frame {
|
||||
* @param {(string|number|Function)} selectorOrFunctionOrTimeout
|
||||
* @param {!Object=} options
|
||||
* @param {!Array<*>} args
|
||||
* @return {!Promise<?Puppeteer.JSHandle>}
|
||||
* @return {!Promise<?JSHandle>}
|
||||
*/
|
||||
waitFor(selectorOrFunctionOrTimeout, options = {}, ...args) {
|
||||
const xPathPattern = '//';
|
||||
@ -629,7 +632,7 @@ class Frame {
|
||||
/**
|
||||
* @param {string} selector
|
||||
* @param {!{visible?: boolean, hidden?: boolean, timeout?: number}=} options
|
||||
* @return {!Promise<?Puppeteer.ElementHandle>}
|
||||
* @return {!Promise<?ElementHandle>}
|
||||
*/
|
||||
async waitForSelector(selector, options) {
|
||||
const handle = await this._secondaryWorld.waitForSelector(selector, options);
|
||||
@ -644,7 +647,7 @@ class Frame {
|
||||
/**
|
||||
* @param {string} xpath
|
||||
* @param {!{visible?: boolean, hidden?: boolean, timeout?: number}=} options
|
||||
* @return {!Promise<?Puppeteer.ElementHandle>}
|
||||
* @return {!Promise<?ElementHandle>}
|
||||
*/
|
||||
async waitForXPath(xpath, options) {
|
||||
const handle = await this._secondaryWorld.waitForXPath(xpath, options);
|
||||
@ -659,7 +662,7 @@ class Frame {
|
||||
/**
|
||||
* @param {Function|string} pageFunction
|
||||
* @param {!{polling?: string|number, timeout?: number}=} options
|
||||
* @return {!Promise<!Puppeteer.JSHandle>}
|
||||
* @return {!Promise<!JSHandle>}
|
||||
*/
|
||||
waitForFunction(pageFunction, options = {}, ...args) {
|
||||
return this._mainWorld.waitForFunction(pageFunction, options, ...args);
|
||||
|
@ -14,12 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const {helper, assert, debugError} = require('./helper');
|
||||
// CDPSession is used only as a typedef
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const {CDPSession} = require('./Connection');
|
||||
import {helper, assert, debugError} from './helper';
|
||||
import {CDPSession} from './Connection';
|
||||
|
||||
function createJSHandle(context, remoteObject) {
|
||||
interface BoxModel {
|
||||
content: Array<{x: number; y: number}>;
|
||||
padding: Array<{x: number; y: number}>;
|
||||
border: Array<{x: number; y: number}>;
|
||||
margin: Array<{x: number; y: number}>;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export function createJSHandle(context: Puppeteer.ExecutionContext, remoteObject: Protocol.Runtime.RemoteObject): JSHandle {
|
||||
const frame = context.frame();
|
||||
if (remoteObject.subtype === 'node' && frame) {
|
||||
const frameManager = frame._frameManager;
|
||||
@ -28,49 +35,31 @@ function createJSHandle(context, remoteObject) {
|
||||
return new JSHandle(context, context._client, remoteObject);
|
||||
}
|
||||
|
||||
class JSHandle {
|
||||
/**
|
||||
* @param {!Puppeteer.ExecutionContext} context
|
||||
* @param {!CDPSession} client
|
||||
* @param {!Protocol.Runtime.RemoteObject} remoteObject
|
||||
*/
|
||||
constructor(context, client, remoteObject) {
|
||||
export class JSHandle {
|
||||
_context: Puppeteer.ExecutionContext;
|
||||
_client: CDPSession;
|
||||
_remoteObject: Protocol.Runtime.RemoteObject;
|
||||
_disposed = false;
|
||||
|
||||
constructor(context: Puppeteer.ExecutionContext, client: CDPSession, remoteObject: Protocol.Runtime.RemoteObject) {
|
||||
this._context = context;
|
||||
this._client = client;
|
||||
this._remoteObject = remoteObject;
|
||||
this._disposed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!Puppeteer.ExecutionContext}
|
||||
*/
|
||||
executionContext() {
|
||||
executionContext(): Puppeteer.ExecutionContext {
|
||||
return this._context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Function|String} pageFunction
|
||||
* @param {!Array<*>} args
|
||||
* @return {!Promise<(!Object|undefined)>}
|
||||
*/
|
||||
async evaluate(pageFunction, ...args) {
|
||||
async evaluate<T extends any>(pageFunction: Function | string, ...args: any[]): Promise<T | undefined> {
|
||||
return await this.executionContext().evaluate(pageFunction, this, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Function|string} pageFunction
|
||||
* @param {!Array<*>} args
|
||||
* @return {!Promise<!Puppeteer.JSHandle>}
|
||||
*/
|
||||
async evaluateHandle(pageFunction, ...args) {
|
||||
async evaluateHandle(pageFunction: Function | string, ...args: any[]): Promise<JSHandle> {
|
||||
return await this.executionContext().evaluateHandle(pageFunction, this, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} propertyName
|
||||
* @return {!Promise<?JSHandle>}
|
||||
*/
|
||||
async getProperty(propertyName) {
|
||||
async getProperty(propertyName: string): Promise<JSHandle | undefined> {
|
||||
const objectHandle = await this.evaluateHandle((object, propertyName) => {
|
||||
const result = {__proto__: null};
|
||||
result[propertyName] = object[propertyName];
|
||||
@ -82,15 +71,12 @@ class JSHandle {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!Promise<!Map<string, !JSHandle>>}
|
||||
*/
|
||||
async getProperties() {
|
||||
async getProperties(): Promise<Map<string, JSHandle>> {
|
||||
const response = await this._client.send('Runtime.getProperties', {
|
||||
objectId: this._remoteObject.objectId,
|
||||
ownProperties: true
|
||||
});
|
||||
const result = new Map();
|
||||
const result = new Map<string, JSHandle>();
|
||||
for (const property of response.result) {
|
||||
if (!property.enumerable)
|
||||
continue;
|
||||
@ -99,10 +85,7 @@ class JSHandle {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!Promise<?Object>}
|
||||
*/
|
||||
async jsonValue() {
|
||||
async jsonValue(): Promise<{}> {
|
||||
if (this._remoteObject.objectId) {
|
||||
const response = await this._client.send('Runtime.callFunctionOn', {
|
||||
functionDeclaration: 'function() { return this; }',
|
||||
@ -115,25 +98,19 @@ class JSHandle {
|
||||
return helper.valueFromRemoteObject(this._remoteObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {?Puppeteer.ElementHandle}
|
||||
*/
|
||||
asElement() {
|
||||
/* This always returns null but children can define this and return an ElementHandle */
|
||||
asElement(): ElementHandle | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
async dispose() {
|
||||
async dispose(): Promise<void> {
|
||||
if (this._disposed)
|
||||
return;
|
||||
this._disposed = true;
|
||||
await helper.releaseObject(this._client, this._remoteObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @return {string}
|
||||
*/
|
||||
toString() {
|
||||
toString(): string {
|
||||
if (this._remoteObject.objectId) {
|
||||
const type = this._remoteObject.subtype || this._remoteObject.type;
|
||||
return 'JSHandle@' + type;
|
||||
@ -142,7 +119,9 @@ class JSHandle {
|
||||
}
|
||||
}
|
||||
|
||||
class ElementHandle extends JSHandle {
|
||||
export class ElementHandle extends JSHandle {
|
||||
_page: Puppeteer.Page;
|
||||
_frameManager: Puppeteer.FrameManager;
|
||||
/**
|
||||
* @param {!Puppeteer.ExecutionContext} context
|
||||
* @param {!CDPSession} client
|
||||
@ -150,27 +129,19 @@ class ElementHandle extends JSHandle {
|
||||
* @param {!Puppeteer.Page} page
|
||||
* @param {!Puppeteer.FrameManager} frameManager
|
||||
*/
|
||||
constructor(context, client, remoteObject, page, frameManager) {
|
||||
constructor(context: Puppeteer.ExecutionContext, client: CDPSession, remoteObject: Protocol.Runtime.RemoteObject, page: Puppeteer.Page, frameManager: Puppeteer.FrameManager) {
|
||||
super(context, client, remoteObject);
|
||||
this._client = client;
|
||||
this._remoteObject = remoteObject;
|
||||
this._page = page;
|
||||
this._frameManager = frameManager;
|
||||
this._disposed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @return {?ElementHandle}
|
||||
*/
|
||||
asElement() {
|
||||
asElement(): ElementHandle | null {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!Promise<?Puppeteer.Frame>}
|
||||
*/
|
||||
async contentFrame() {
|
||||
async contentFrame(): Promise<Puppeteer.Frame | null> {
|
||||
const nodeInfo = await this._client.send('DOM.describeNode', {
|
||||
objectId: this._remoteObject.objectId
|
||||
});
|
||||
@ -179,8 +150,8 @@ class ElementHandle extends JSHandle {
|
||||
return this._frameManager.frame(nodeInfo.node.frameId);
|
||||
}
|
||||
|
||||
async _scrollIntoViewIfNeeded() {
|
||||
const error = await this.evaluate(async(element, pageJavascriptEnabled) => {
|
||||
async _scrollIntoViewIfNeeded(): Promise<void> {
|
||||
const error = await this.evaluate<string | false>(async(element, pageJavascriptEnabled) => {
|
||||
if (!element.isConnected)
|
||||
return 'Node is detached from document';
|
||||
if (element.nodeType !== Node.ELEMENT_NODE)
|
||||
@ -201,14 +172,12 @@ class ElementHandle extends JSHandle {
|
||||
element.scrollIntoView({block: 'center', inline: 'center', behavior: 'instant'});
|
||||
return false;
|
||||
}, this._page._javascriptEnabled);
|
||||
|
||||
if (error)
|
||||
throw new Error(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!Promise<!{x: number, y: number}>}
|
||||
*/
|
||||
async _clickablePoint() {
|
||||
async _clickablePoint(): Promise<{x: number; y: number}> {
|
||||
const [result, layoutMetrics] = await Promise.all([
|
||||
this._client.send('DOM.getContentQuads', {
|
||||
objectId: this._remoteObject.objectId
|
||||
@ -236,20 +205,13 @@ class ElementHandle extends JSHandle {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!Promise<void|Protocol.DOM.getBoxModelReturnValue>}
|
||||
*/
|
||||
_getBoxModel() {
|
||||
_getBoxModel(): Promise<void | Protocol.DOM.getBoxModelReturnValue> {
|
||||
return this._client.send('DOM.getBoxModel', {
|
||||
objectId: this._remoteObject.objectId
|
||||
}).catch(error => debugError(error));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Array<number>} quad
|
||||
* @return {!Array<{x: number, y: number}>}
|
||||
*/
|
||||
_fromProtocolQuad(quad) {
|
||||
_fromProtocolQuad(quad: number[]): Array<{x: number; y: number}> {
|
||||
return [
|
||||
{x: quad[0], y: quad[1]},
|
||||
{x: quad[2], y: quad[3]},
|
||||
@ -264,23 +226,20 @@ class ElementHandle extends JSHandle {
|
||||
* @param {number} height
|
||||
* @return {!Array<{x: number, y: number}>}
|
||||
*/
|
||||
_intersectQuadWithViewport(quad, width, height) {
|
||||
_intersectQuadWithViewport(quad: Array<{x: number; y: number}>, width: number, height: number): Array<{x: number; y: number}> {
|
||||
return quad.map(point => ({
|
||||
x: Math.min(Math.max(point.x, 0), width),
|
||||
y: Math.min(Math.max(point.y, 0), height),
|
||||
}));
|
||||
}
|
||||
|
||||
async hover() {
|
||||
async hover(): Promise<void> {
|
||||
await this._scrollIntoViewIfNeeded();
|
||||
const {x, y} = await this._clickablePoint();
|
||||
await this._page.mouse.move(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!{delay?: number, button?: "left"|"right"|"middle", clickCount?: number}=} options
|
||||
*/
|
||||
async click(options) {
|
||||
async click(options: {delay?: number; button?: 'left'|'right'|'middle'; clickCount?: number}): Promise<void> {
|
||||
await this._scrollIntoViewIfNeeded();
|
||||
const {x, y} = await this._clickablePoint();
|
||||
await this._page.mouse.click(x, y, options);
|
||||
@ -290,10 +249,15 @@ class ElementHandle extends JSHandle {
|
||||
* @param {!Array<string>} values
|
||||
* @return {!Promise<!Array<string>>}
|
||||
*/
|
||||
async select(...values) {
|
||||
async select(...values: string[]): Promise<string[]> {
|
||||
for (const value of values)
|
||||
assert(helper.isString(value), 'Values must be strings. Found value "' + value + '" of type "' + (typeof value) + '"');
|
||||
return this.evaluate((element, values) => {
|
||||
|
||||
/* TODO(jacktfranklin@): once ExecutionContext is TypeScript, and
|
||||
* its evaluate function is properly typed with generics we can
|
||||
* return here and remove the typecasting
|
||||
*/
|
||||
return this.evaluate((element: HTMLSelectElement, values: string[]) => {
|
||||
if (element.nodeName.toLowerCase() !== 'select')
|
||||
throw new Error('Element is not a <select> element.');
|
||||
|
||||
@ -310,15 +274,13 @@ class ElementHandle extends JSHandle {
|
||||
}, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Array<string>} filePaths
|
||||
*/
|
||||
async uploadFile(...filePaths) {
|
||||
async uploadFile(...filePaths: string[]): Promise<void> {
|
||||
const isMultiple = await this.evaluate(element => element.multiple);
|
||||
assert(filePaths.length <= 1 || isMultiple, 'Multiple file uploads only work with <input type=file multiple>');
|
||||
|
||||
// This import is only needed for `uploadFile`, so keep it scoped here to avoid paying
|
||||
// the cost unnecessarily.
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const path = require('path');
|
||||
const files = filePaths.map(filePath => path.resolve(filePath));
|
||||
const {objectId} = this._remoteObject;
|
||||
@ -341,38 +303,27 @@ class ElementHandle extends JSHandle {
|
||||
}
|
||||
}
|
||||
|
||||
async tap() {
|
||||
async tap(): Promise<void> {
|
||||
await this._scrollIntoViewIfNeeded();
|
||||
const {x, y} = await this._clickablePoint();
|
||||
await this._page.touchscreen.tap(x, y);
|
||||
}
|
||||
|
||||
async focus() {
|
||||
async focus(): Promise<void> {
|
||||
await this.evaluate(element => element.focus());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} text
|
||||
* @param {{delay: (number|undefined)}=} options
|
||||
*/
|
||||
async type(text, options) {
|
||||
async type(text: string, options?: {delay: number}): Promise<void> {
|
||||
await this.focus();
|
||||
await this._page.keyboard.type(text, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @param {!{delay?: number, text?: string}=} options
|
||||
*/
|
||||
async press(key, options) {
|
||||
async press(key: string, options?: {delay?: number; text?: string}): Promise<void> {
|
||||
await this.focus();
|
||||
await this._page.keyboard.press(key, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!Promise<?{x: number, y: number, width: number, height: number}>}
|
||||
*/
|
||||
async boundingBox() {
|
||||
async boundingBox(): Promise<{x: number; y: number; width: number; height: number}> {
|
||||
const result = await this._getBoxModel();
|
||||
|
||||
if (!result)
|
||||
@ -390,7 +341,7 @@ class ElementHandle extends JSHandle {
|
||||
/**
|
||||
* @return {!Promise<?BoxModel>}
|
||||
*/
|
||||
async boxModel() {
|
||||
async boxModel(): Promise<BoxModel | null> {
|
||||
const result = await this._getBoxModel();
|
||||
|
||||
if (!result)
|
||||
@ -407,12 +358,7 @@ class ElementHandle extends JSHandle {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {!Object=} options
|
||||
* @returns {!Promise<string|!Buffer>}
|
||||
*/
|
||||
async screenshot(options = {}) {
|
||||
async screenshot(options = {}): Promise<string|Buffer> {
|
||||
let needsViewportReset = false;
|
||||
|
||||
let boundingBox = await this.boundingBox();
|
||||
@ -453,11 +399,7 @@ class ElementHandle extends JSHandle {
|
||||
return imageData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} selector
|
||||
* @return {!Promise<?ElementHandle>}
|
||||
*/
|
||||
async $(selector) {
|
||||
async $(selector: string): Promise<ElementHandle | null> {
|
||||
const handle = await this.evaluateHandle(
|
||||
(element, selector) => element.querySelector(selector),
|
||||
selector
|
||||
@ -473,7 +415,7 @@ class ElementHandle extends JSHandle {
|
||||
* @param {string} selector
|
||||
* @return {!Promise<!Array<!ElementHandle>>}
|
||||
*/
|
||||
async $$(selector) {
|
||||
async $$(selector: string): Promise<ElementHandle[]> {
|
||||
const arrayHandle = await this.evaluateHandle(
|
||||
(element, selector) => element.querySelectorAll(selector),
|
||||
selector
|
||||
@ -489,13 +431,7 @@ class ElementHandle extends JSHandle {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} selector
|
||||
* @param {Function|String} pageFunction
|
||||
* @param {!Array<*>} args
|
||||
* @return {!Promise<(!Object|undefined)>}
|
||||
*/
|
||||
async $eval(selector, pageFunction, ...args) {
|
||||
async $eval<T extends any>(selector: string, pageFunction: Function|string, ...args: any[]): Promise<T | undefined> {
|
||||
const elementHandle = await this.$(selector);
|
||||
if (!elementHandle)
|
||||
throw new Error(`Error: failed to find element matching selector "${selector}"`);
|
||||
@ -504,13 +440,10 @@ class ElementHandle extends JSHandle {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} selector
|
||||
* @param {Function|String} pageFunction
|
||||
* @param {!Array<*>} args
|
||||
* @return {!Promise<(!Object|undefined)>}
|
||||
*/
|
||||
async $$eval(selector, pageFunction, ...args) {
|
||||
// TODO(jacktfranklin@): consider the types here
|
||||
// we might want $$eval<SelectorType> which returns Promise<SelectorType[]>?
|
||||
// Once ExecutionContext.evaluate is properly typed we can improve this a bunch
|
||||
async $$eval<T>(selector: string, pageFunction: Function | string, ...args: any[]): Promise<T | undefined> {
|
||||
const arrayHandle = await this.evaluateHandle(
|
||||
(element, selector) => Array.from(element.querySelectorAll(selector)),
|
||||
selector
|
||||
@ -521,11 +454,7 @@ class ElementHandle extends JSHandle {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} expression
|
||||
* @return {!Promise<!Array<!ElementHandle>>}
|
||||
*/
|
||||
async $x(expression) {
|
||||
async $x(expression: string): Promise<ElementHandle[]> {
|
||||
const arrayHandle = await this.evaluateHandle(
|
||||
(element, expression) => {
|
||||
const document = element.ownerDocument || element;
|
||||
@ -549,10 +478,7 @@ class ElementHandle extends JSHandle {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {!Promise<boolean>}
|
||||
*/
|
||||
isIntersectingViewport() {
|
||||
isIntersectingViewport(): Promise<boolean> {
|
||||
return this.evaluate(async element => {
|
||||
const visibleRatio = await new Promise(resolve => {
|
||||
const observer = new IntersectionObserver(entries => {
|
||||
@ -566,7 +492,7 @@ class ElementHandle extends JSHandle {
|
||||
}
|
||||
}
|
||||
|
||||
function computeQuadArea(quad) {
|
||||
function computeQuadArea(quad: Array<{x: number; y: number}>): number {
|
||||
// Compute sum of all directed areas of adjacent triangles
|
||||
// https://en.wikipedia.org/wiki/Polygon#Simple_polygons
|
||||
let area = 0;
|
||||
@ -577,15 +503,3 @@ function computeQuadArea(quad) {
|
||||
}
|
||||
return Math.abs(area);
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} BoxModel
|
||||
* @property {!Array<!{x: number, y: number}>} content
|
||||
* @property {!Array<!{x: number, y: number}>} padding
|
||||
* @property {!Array<!{x: number, y: number}>} border
|
||||
* @property {!Array<!{x: number, y: number}>} margin
|
||||
* @property {number} width
|
||||
* @property {number} height
|
||||
*/
|
||||
|
||||
module.exports = {createJSHandle, JSHandle, ElementHandle};
|
36
src/Page.js
36
src/Page.js
@ -29,7 +29,9 @@ const Tracing = require('./Tracing');
|
||||
const {helper, debugError, assert} = require('./helper');
|
||||
const {Coverage} = require('./Coverage');
|
||||
const {Worker: PuppeteerWorker} = require('./Worker');
|
||||
const {createJSHandle} = require('./JSHandle');
|
||||
// Import used as typedef
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const {createJSHandle, JSHandle, ElementHandle} = require('./JSHandle');
|
||||
const {Accessibility} = require('./Accessibility');
|
||||
const {TimeoutSettings} = require('./TimeoutSettings');
|
||||
|
||||
@ -316,7 +318,7 @@ class Page extends EventEmitter {
|
||||
|
||||
/**
|
||||
* @param {string} selector
|
||||
* @return {!Promise<?Puppeteer.ElementHandle>}
|
||||
* @return {!Promise<?ElementHandle>}
|
||||
*/
|
||||
async $(selector) {
|
||||
return this.mainFrame().$(selector);
|
||||
@ -325,7 +327,7 @@ class Page extends EventEmitter {
|
||||
/**
|
||||
* @param {Function|string} pageFunction
|
||||
* @param {!Array<*>} args
|
||||
* @return {!Promise<!Puppeteer.JSHandle>}
|
||||
* @return {!Promise<!JSHandle>}
|
||||
*/
|
||||
async evaluateHandle(pageFunction, ...args) {
|
||||
const context = await this.mainFrame().executionContext();
|
||||
@ -333,8 +335,8 @@ class Page extends EventEmitter {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Puppeteer.JSHandle} prototypeHandle
|
||||
* @return {!Promise<!Puppeteer.JSHandle>}
|
||||
* @param {!JSHandle} prototypeHandle
|
||||
* @return {!Promise<!JSHandle>}
|
||||
*/
|
||||
async queryObjects(prototypeHandle) {
|
||||
const context = await this.mainFrame().executionContext();
|
||||
@ -363,7 +365,7 @@ class Page extends EventEmitter {
|
||||
|
||||
/**
|
||||
* @param {string} selector
|
||||
* @return {!Promise<!Array<!Puppeteer.ElementHandle>>}
|
||||
* @return {!Promise<!Array<!ElementHandle>>}
|
||||
*/
|
||||
async $$(selector) {
|
||||
return this.mainFrame().$$(selector);
|
||||
@ -371,7 +373,7 @@ class Page extends EventEmitter {
|
||||
|
||||
/**
|
||||
* @param {string} expression
|
||||
* @return {!Promise<!Array<!Puppeteer.ElementHandle>>}
|
||||
* @return {!Promise<!Array<!ElementHandle>>}
|
||||
*/
|
||||
async $x(expression) {
|
||||
return this.mainFrame().$x(expression);
|
||||
@ -429,7 +431,7 @@ class Page extends EventEmitter {
|
||||
|
||||
/**
|
||||
* @param {!{url?: string, path?: string, content?: string, type?: string}} options
|
||||
* @return {!Promise<!Puppeteer.ElementHandle>}
|
||||
* @return {!Promise<!ElementHandle>}
|
||||
*/
|
||||
async addScriptTag(options) {
|
||||
return this.mainFrame().addScriptTag(options);
|
||||
@ -437,7 +439,7 @@ class Page extends EventEmitter {
|
||||
|
||||
/**
|
||||
* @param {!{url?: string, path?: string, content?: string}} options
|
||||
* @return {!Promise<!Puppeteer.ElementHandle>}
|
||||
* @return {!Promise<!ElementHandle>}
|
||||
*/
|
||||
async addStyleTag(options) {
|
||||
return this.mainFrame().addStyleTag(options);
|
||||
@ -617,7 +619,7 @@ class Page extends EventEmitter {
|
||||
|
||||
/**
|
||||
* @param {string} type
|
||||
* @param {!Array<!Puppeteer.JSHandle>} args
|
||||
* @param {!Array<!JSHandle>} args
|
||||
* @param {Protocol.Runtime.StackTrace=} stackTrace
|
||||
*/
|
||||
_addConsoleMessage(type, args, stackTrace) {
|
||||
@ -1126,7 +1128,7 @@ class Page extends EventEmitter {
|
||||
* @param {(string|number|Function)} selectorOrFunctionOrTimeout
|
||||
* @param {!{visible?: boolean, hidden?: boolean, timeout?: number, polling?: string|number}=} options
|
||||
* @param {!Array<*>} args
|
||||
* @return {!Promise<!Puppeteer.JSHandle>}
|
||||
* @return {!Promise<!JSHandle>}
|
||||
*/
|
||||
waitFor(selectorOrFunctionOrTimeout, options = {}, ...args) {
|
||||
return this.mainFrame().waitFor(selectorOrFunctionOrTimeout, options, ...args);
|
||||
@ -1135,7 +1137,7 @@ class Page extends EventEmitter {
|
||||
/**
|
||||
* @param {string} selector
|
||||
* @param {!{visible?: boolean, hidden?: boolean, timeout?: number}=} options
|
||||
* @return {!Promise<?Puppeteer.ElementHandle>}
|
||||
* @return {!Promise<?ElementHandle>}
|
||||
*/
|
||||
waitForSelector(selector, options = {}) {
|
||||
return this.mainFrame().waitForSelector(selector, options);
|
||||
@ -1144,7 +1146,7 @@ class Page extends EventEmitter {
|
||||
/**
|
||||
* @param {string} xpath
|
||||
* @param {!{visible?: boolean, hidden?: boolean, timeout?: number}=} options
|
||||
* @return {!Promise<?Puppeteer.ElementHandle>}
|
||||
* @return {!Promise<?ElementHandle>}
|
||||
*/
|
||||
waitForXPath(xpath, options = {}) {
|
||||
return this.mainFrame().waitForXPath(xpath, options);
|
||||
@ -1154,7 +1156,7 @@ class Page extends EventEmitter {
|
||||
* @param {Function} pageFunction
|
||||
* @param {!{polling?: string|number, timeout?: number}=} options
|
||||
* @param {!Array<*>} args
|
||||
* @return {!Promise<!Puppeteer.JSHandle>}
|
||||
* @return {!Promise<!JSHandle>}
|
||||
*/
|
||||
waitForFunction(pageFunction, options = {}, ...args) {
|
||||
return this.mainFrame().waitForFunction(pageFunction, options, ...args);
|
||||
@ -1322,7 +1324,7 @@ class ConsoleMessage {
|
||||
/**
|
||||
* @param {string} type
|
||||
* @param {string} text
|
||||
* @param {!Array<!Puppeteer.JSHandle>} args
|
||||
* @param {!Array<!JSHandle>} args
|
||||
* @param {ConsoleMessage.Location} location
|
||||
*/
|
||||
constructor(type, text, args, location = {}) {
|
||||
@ -1347,7 +1349,7 @@ class ConsoleMessage {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!Array<!Puppeteer.JSHandle>}
|
||||
* @return {!Array<!JSHandle>}
|
||||
*/
|
||||
args() {
|
||||
return this._args;
|
||||
@ -1364,7 +1366,7 @@ class ConsoleMessage {
|
||||
class FileChooser {
|
||||
/**
|
||||
* @param {CDPSession} client
|
||||
* @param {Puppeteer.ElementHandle} element
|
||||
* @param {ElementHandle} element
|
||||
* @param {!Protocol.Page.fileChooserOpenedPayload} event
|
||||
*/
|
||||
constructor(client, element, event) {
|
||||
|
3
src/externs.d.ts
vendored
3
src/externs.d.ts
vendored
@ -3,7 +3,6 @@ import {Target as RealTarget} from './Target.js';
|
||||
import {Page as RealPage} from './Page.js';
|
||||
import {Mouse as RealMouse, Keyboard as RealKeyboard, Touchscreen as RealTouchscreen} from './Input.js';
|
||||
import {Frame as RealFrame, FrameManager as RealFrameManager} from './FrameManager.js';
|
||||
import {JSHandle as RealJSHandle, ElementHandle as RealElementHandle} from './JSHandle.js';
|
||||
import {DOMWorld as RealDOMWorld} from './DOMWorld.js';
|
||||
import {ExecutionContext as RealExecutionContext} from './ExecutionContext.js';
|
||||
import { NetworkManager as RealNetworkManager, Request as RealRequest, Response as RealResponse } from './NetworkManager.js';
|
||||
@ -19,8 +18,6 @@ declare global {
|
||||
export class Frame extends RealFrame {}
|
||||
export class FrameManager extends RealFrameManager {}
|
||||
export class NetworkManager extends RealNetworkManager {}
|
||||
export class ElementHandle extends RealElementHandle {}
|
||||
export class JSHandle extends RealJSHandle {}
|
||||
export class DOMWorld extends RealDOMWorld {}
|
||||
export class ExecutionContext extends RealExecutionContext {}
|
||||
export class Page extends RealPage { }
|
||||
|
@ -152,7 +152,7 @@ function checkSources(sources) {
|
||||
*/
|
||||
function serializeType(type, circular = []) {
|
||||
let typeName = checker.typeToString(type);
|
||||
if (typeName === 'any' || typeName === '{ [x: string]: string; }')
|
||||
if (typeName === 'any' || typeName === '{ [x: string]: string; }' || typeName === '{}')
|
||||
typeName = 'Object';
|
||||
const nextCircular = [typeName].concat(circular);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user