diff --git a/.eslintrc.js b/.eslintrc.js index 3e403562..32b5d161 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -96,6 +96,8 @@ module.exports = { "rules": { "no-unused-vars": 0, "@typescript-eslint/no-unused-vars": 2, + "func-call-spacing": 0, + "@typescript-eslint/func-call-spacing": 2, "semi": 0, "@typescript-eslint/semi": 2, "@typescript-eslint/no-empty-function": 0, diff --git a/README.md b/README.md index afbe88db..7bd43280 100644 --- a/README.md +++ b/README.md @@ -292,9 +292,25 @@ Puppeteer creates its own browser user profile which it **cleans up on every run - debug your test inside chromium like a boss! - + + +## Usage with TypeScript + +We have recently completed a migration to move the Puppeteer source code from JavaScript to TypeScript and we're currently working on shipping type definitions for TypeScript with Puppeteer's npm package. + +Until this work is complete we recommend installing the Puppeteer type definitions from the [DefinitelyTyped](https://definitelytyped.org/) repository: + +```bash +npm install --save-dev @types/puppeteer +``` + +The types that you'll see appearing in the Puppeteer source code are based off the great work of those who have contributed to the `@types/puppeteer` package. We really appreciate the hard work those people put in to providing high quality TypeScript definitions for Puppeteer's users. + + + + ## Contributing to Puppeteer Check out [contributing guide](https://github.com/puppeteer/puppeteer/blob/main/CONTRIBUTING.md) to get an overview of Puppeteer development. diff --git a/new-docs/puppeteer.elementhandle.__eval.md b/new-docs/puppeteer.elementhandle.__eval.md index 62184b0b..f351b5ef 100644 --- a/new-docs/puppeteer.elementhandle.__eval.md +++ b/new-docs/puppeteer.elementhandle.__eval.md @@ -11,7 +11,7 @@ If `pageFunction` returns a Promise, then `frame.$$eval` would wait for the prom Signature: ```typescript -$$eval(selector: string, pageFunction: Function | string, ...args: unknown[]): Promise; +$$eval(selector: string, pageFunction: EvaluateFn | string, ...args: SerializableOrJSHandle[]): Promise; ``` ## Parameters @@ -19,8 +19,8 @@ $$eval(selector: string, pageFunction: Function | string | Parameter | Type | Description | | --- | --- | --- | | selector | string | | -| pageFunction | Function \| string | | -| args | unknown\[\] | | +| pageFunction | [EvaluateFn](./puppeteer.evaluatefn.md) \| string | | +| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)\[\] | | Returns: diff --git a/new-docs/puppeteer.elementhandle._eval.md b/new-docs/puppeteer.elementhandle._eval.md index 51719ae1..f0c8b871 100644 --- a/new-docs/puppeteer.elementhandle._eval.md +++ b/new-docs/puppeteer.elementhandle._eval.md @@ -11,7 +11,7 @@ If `pageFunction` returns a Promise, then `frame.$eval` would wait for the promi Signature: ```typescript -$eval(selector: string, pageFunction: Function | string, ...args: unknown[]): Promise; +$eval(selector: string, pageFunction: EvaluateFn | string, ...args: SerializableOrJSHandle[]): Promise; ``` ## Parameters @@ -19,8 +19,8 @@ $eval(selector: string, pageFunction: Function | string, | Parameter | Type | Description | | --- | --- | --- | | selector | string | | -| pageFunction | Function \| string | | -| args | unknown\[\] | | +| pageFunction | [EvaluateFn](./puppeteer.evaluatefn.md) \| string | | +| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)\[\] | | Returns: diff --git a/new-docs/puppeteer.evaluatefn.md b/new-docs/puppeteer.evaluatefn.md new file mode 100644 index 00000000..8647ef2b --- /dev/null +++ b/new-docs/puppeteer.evaluatefn.md @@ -0,0 +1,12 @@ + + +[Home](./index.md) > [puppeteer](./puppeteer.md) > [EvaluateFn](./puppeteer.evaluatefn.md) + +## EvaluateFn type + + +Signature: + +```typescript +export declare type EvaluateFn = string | ((arg1: T, ...args: any[]) => any); +``` diff --git a/new-docs/puppeteer.evaluatefnreturntype.md b/new-docs/puppeteer.evaluatefnreturntype.md new file mode 100644 index 00000000..471823e3 --- /dev/null +++ b/new-docs/puppeteer.evaluatefnreturntype.md @@ -0,0 +1,12 @@ + + +[Home](./index.md) > [puppeteer](./puppeteer.md) > [EvaluateFnReturnType](./puppeteer.evaluatefnreturntype.md) + +## EvaluateFnReturnType type + + +Signature: + +```typescript +export declare type EvaluateFnReturnType = T extends (...args: any[]) => infer R ? R : unknown; +``` diff --git a/new-docs/puppeteer.frame.__eval.md b/new-docs/puppeteer.frame.__eval.md index 0a7d7a9e..889af679 100644 --- a/new-docs/puppeteer.frame.__eval.md +++ b/new-docs/puppeteer.frame.__eval.md @@ -7,7 +7,7 @@ Signature: ```typescript -$$eval(selector: string, pageFunction: Function | string, ...args: unknown[]): Promise; +$$eval(selector: string, pageFunction: EvaluateFn | string, ...args: SerializableOrJSHandle[]): Promise; ``` ## Parameters @@ -15,8 +15,8 @@ $$eval(selector: string, pageFunction: Function | string | Parameter | Type | Description | | --- | --- | --- | | selector | string | | -| pageFunction | Function \| string | | -| args | unknown\[\] | | +| pageFunction | [EvaluateFn](./puppeteer.evaluatefn.md) \| string | | +| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)\[\] | | Returns: diff --git a/new-docs/puppeteer.frame._eval.md b/new-docs/puppeteer.frame._eval.md index 0d5d3066..6eb63bae 100644 --- a/new-docs/puppeteer.frame._eval.md +++ b/new-docs/puppeteer.frame._eval.md @@ -7,7 +7,7 @@ Signature: ```typescript -$eval(selector: string, pageFunction: Function | string, ...args: unknown[]): Promise; +$eval(selector: string, pageFunction: EvaluateFn | string, ...args: SerializableOrJSHandle[]): Promise; ``` ## Parameters @@ -15,8 +15,8 @@ $eval(selector: string, pageFunction: Function | string, | Parameter | Type | Description | | --- | --- | --- | | selector | string | | -| pageFunction | Function \| string | | -| args | unknown\[\] | | +| pageFunction | [EvaluateFn](./puppeteer.evaluatefn.md) \| string | | +| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)\[\] | | Returns: diff --git a/new-docs/puppeteer.jshandle.evaluate.md b/new-docs/puppeteer.jshandle.evaluate.md index fef1efe8..c8cd3227 100644 --- a/new-docs/puppeteer.jshandle.evaluate.md +++ b/new-docs/puppeteer.jshandle.evaluate.md @@ -9,19 +9,19 @@ This method passes this handle as the first argument to `pageFunction`. Signature: ```typescript -evaluate(pageFunction: Function | string, ...args: unknown[]): Promise; +evaluate(pageFunction: T | string, ...args: SerializableOrJSHandle[]): Promise>; ``` ## Parameters | Parameter | Type | Description | | --- | --- | --- | -| pageFunction | Function \| string | | -| args | unknown\[\] | | +| pageFunction | T \| string | | +| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)\[\] | | Returns: -Promise<ReturnType> +Promise<[EvaluateFnReturnType](./puppeteer.evaluatefnreturntype.md)<T>> ## Example diff --git a/new-docs/puppeteer.jsonarray.md b/new-docs/puppeteer.jsonarray.md new file mode 100644 index 00000000..fea5db9a --- /dev/null +++ b/new-docs/puppeteer.jsonarray.md @@ -0,0 +1,12 @@ + + +[Home](./index.md) > [puppeteer](./puppeteer.md) > [JSONArray](./puppeteer.jsonarray.md) + +## JSONArray type + + +Signature: + +```typescript +export declare type JSONArray = Serializable[]; +``` diff --git a/new-docs/puppeteer.jsonobject.md b/new-docs/puppeteer.jsonobject.md new file mode 100644 index 00000000..609425b7 --- /dev/null +++ b/new-docs/puppeteer.jsonobject.md @@ -0,0 +1,12 @@ + + +[Home](./index.md) > [puppeteer](./puppeteer.md) > [JSONObject](./puppeteer.jsonobject.md) + +## JSONObject interface + + +Signature: + +```typescript +export interface JSONObject +``` diff --git a/new-docs/puppeteer.md b/new-docs/puppeteer.md index 8b2c127a..200dab24 100644 --- a/new-docs/puppeteer.md +++ b/new-docs/puppeteer.md @@ -52,6 +52,7 @@ | [BrowserFetcherOptions](./puppeteer.browserfetcheroptions.md) | | | [ClickOptions](./puppeteer.clickoptions.md) | | | [ConsoleMessageLocation](./puppeteer.consolemessagelocation.md) | | +| [JSONObject](./puppeteer.jsonobject.md) | | | [KeyDefinition](./puppeteer.keydefinition.md) | 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 athttp://www.apache.org/licenses/LICENSE-2.0Unless 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. | | [Metrics](./puppeteer.metrics.md) | | | [PressOptions](./puppeteer.pressoptions.md) | | @@ -73,7 +74,12 @@ | Type Alias | Description | | --- | --- | | [ConsoleMessageType](./puppeteer.consolemessagetype.md) | The supported types for console messages. | +| [EvaluateFn](./puppeteer.evaluatefn.md) | | +| [EvaluateFnReturnType](./puppeteer.evaluatefnreturntype.md) | | +| [JSONArray](./puppeteer.jsonarray.md) | | | [KeyInput](./puppeteer.keyinput.md) | | | [MouseButtonInput](./puppeteer.mousebuttoninput.md) | | | [PuppeteerErrors](./puppeteer.puppeteererrors.md) | | +| [Serializable](./puppeteer.serializable.md) | | +| [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md) | | diff --git a/new-docs/puppeteer.page.__eval.md b/new-docs/puppeteer.page.__eval.md index 4c7800a5..3bcb6aea 100644 --- a/new-docs/puppeteer.page.__eval.md +++ b/new-docs/puppeteer.page.__eval.md @@ -7,7 +7,7 @@ Signature: ```typescript -$$eval(selector: string, pageFunction: Function | string, ...args: unknown[]): Promise; +$$eval(selector: string, pageFunction: EvaluateFn | string, ...args: SerializableOrJSHandle[]): Promise; ``` ## Parameters @@ -15,8 +15,8 @@ $$eval(selector: string, pageFunction: Function | string | Parameter | Type | Description | | --- | --- | --- | | selector | string | | -| pageFunction | Function \| string | | -| args | unknown\[\] | | +| pageFunction | [EvaluateFn](./puppeteer.evaluatefn.md) \| string | | +| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)\[\] | | Returns: diff --git a/new-docs/puppeteer.page._eval.md b/new-docs/puppeteer.page._eval.md index d5b18ad8..8b1c1d7d 100644 --- a/new-docs/puppeteer.page._eval.md +++ b/new-docs/puppeteer.page._eval.md @@ -7,7 +7,7 @@ Signature: ```typescript -$eval(selector: string, pageFunction: Function | string, ...args: unknown[]): Promise; +$eval(selector: string, pageFunction: EvaluateFn | string, ...args: SerializableOrJSHandle[]): Promise; ``` ## Parameters @@ -15,8 +15,8 @@ $eval(selector: string, pageFunction: Function | string, | Parameter | Type | Description | | --- | --- | --- | | selector | string | | -| pageFunction | Function \| string | | -| args | unknown\[\] | | +| pageFunction | [EvaluateFn](./puppeteer.evaluatefn.md) \| string | | +| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)\[\] | | Returns: diff --git a/new-docs/puppeteer.serializable.md b/new-docs/puppeteer.serializable.md new file mode 100644 index 00000000..8b7a7df8 --- /dev/null +++ b/new-docs/puppeteer.serializable.md @@ -0,0 +1,12 @@ + + +[Home](./index.md) > [puppeteer](./puppeteer.md) > [Serializable](./puppeteer.serializable.md) + +## Serializable type + + +Signature: + +```typescript +export declare type Serializable = number | string | boolean | null | JSONArray | JSONObject; +``` diff --git a/new-docs/puppeteer.serializableorjshandle.md b/new-docs/puppeteer.serializableorjshandle.md new file mode 100644 index 00000000..84ca6eed --- /dev/null +++ b/new-docs/puppeteer.serializableorjshandle.md @@ -0,0 +1,12 @@ + + +[Home](./index.md) > [puppeteer](./puppeteer.md) > [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md) + +## SerializableOrJSHandle type + + +Signature: + +```typescript +export declare type SerializableOrJSHandle = Serializable | JSHandle; +``` diff --git a/src/api-docs-entry.ts b/src/api-docs-entry.ts index 8e8ac591..4a04e31c 100644 --- a/src/api-docs-entry.ts +++ b/src/api-docs-entry.ts @@ -48,3 +48,4 @@ export * from './common/Errors'; export * from './common/Tracing'; export * from './common/WebWorker'; export * from './common/USKeyboardLayout'; +export * from './common/EvalTypes'; diff --git a/src/common/DOMWorld.ts b/src/common/DOMWorld.ts index 5600e557..3ea66d50 100644 --- a/src/common/DOMWorld.ts +++ b/src/common/DOMWorld.ts @@ -24,6 +24,7 @@ import { TimeoutSettings } from './TimeoutSettings'; import { MouseButtonInput } from './Input'; import { FrameManager, Frame } from './FrameManager'; import { getQueryHandlerAndSelector, QueryHandler } from './QueryHandler'; +import { EvaluateFn, SerializableOrJSHandle } from './EvalTypes'; import { isNode } from '../environment'; // This predicateQueryHandler is declared here so that TypeScript knows about it @@ -155,8 +156,8 @@ export class DOMWorld { async $eval( selector: string, - pageFunction: Function | string, - ...args: unknown[] + pageFunction: EvaluateFn | string, + ...args: SerializableOrJSHandle[] ): Promise { const document = await this._document(); return document.$eval(selector, pageFunction, ...args); @@ -164,8 +165,8 @@ export class DOMWorld { async $$eval( selector: string, - pageFunction: Function | string, - ...args: unknown[] + pageFunction: EvaluateFn | string, + ...args: SerializableOrJSHandle[] ): Promise { const document = await this._document(); const value = await document.$$eval( diff --git a/src/common/EvalTypes.ts b/src/common/EvalTypes.ts new file mode 100644 index 00000000..c898d22b --- /dev/null +++ b/src/common/EvalTypes.ts @@ -0,0 +1,58 @@ +/** + * 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'; + +/** + * @public + */ +export type EvaluateFn = string | ((arg1: T, ...args: any[]) => any); +/** + * @public + */ +export type EvaluateFnReturnType = T extends ( + ...args: any[] +) => infer R + ? R + : unknown; + +/** + * @public + */ +export type Serializable = + | number + | string + | boolean + | null + | JSONArray + | JSONObject; + +/** + * @public + */ +export type JSONArray = Serializable[]; + +/** + * @public + */ +export interface JSONObject { + [key: string]: Serializable; +} + +/** + * @public + */ +export type SerializableOrJSHandle = Serializable | JSHandle; diff --git a/src/common/FrameManager.ts b/src/common/FrameManager.ts index 6e56c753..859b649e 100644 --- a/src/common/FrameManager.ts +++ b/src/common/FrameManager.ts @@ -29,6 +29,7 @@ import { MouseButtonInput } from './Input'; import { Page } from './Page'; import { HTTPResponse } from './HTTPResponse'; import Protocol from '../protocol'; +import { EvaluateFn, SerializableOrJSHandle } from './EvalTypes'; const UTILITY_WORLD_NAME = '__puppeteer_utility_world__'; @@ -454,16 +455,16 @@ export class Frame { async $eval( selector: string, - pageFunction: Function | string, - ...args: unknown[] + pageFunction: EvaluateFn | string, + ...args: SerializableOrJSHandle[] ): Promise { return this._mainWorld.$eval(selector, pageFunction, ...args); } async $$eval( selector: string, - pageFunction: Function | string, - ...args: unknown[] + pageFunction: EvaluateFn | string, + ...args: SerializableOrJSHandle[] ): Promise { return this._mainWorld.$$eval(selector, pageFunction, ...args); } diff --git a/src/common/JSHandle.ts b/src/common/JSHandle.ts index 4273db86..2a8f0265 100644 --- a/src/common/JSHandle.ts +++ b/src/common/JSHandle.ts @@ -23,6 +23,11 @@ import { KeyInput } from './USKeyboardLayout'; import { FrameManager, Frame } from './FrameManager'; import { getQueryHandlerAndSelector } from './QueryHandler'; import Protocol from '../protocol'; +import { + EvaluateFn, + SerializableOrJSHandle, + EvaluateFnReturnType, +} from './EvalTypes'; /** * @public @@ -113,11 +118,12 @@ export class JSHandle { * expect(await tweetHandle.evaluate(node => node.innerText)).toBe('10'); * ``` */ - async evaluate( - pageFunction: Function | string, - ...args: unknown[] - ): Promise { - return await this.executionContext().evaluate( + + async evaluate( + pageFunction: T | string, + ...args: SerializableOrJSHandle[] + ): Promise> { + return await this.executionContext().evaluate>( pageFunction, this, ...args @@ -307,46 +313,48 @@ export class ElementHandle extends JSHandle { } private async _scrollIntoViewIfNeeded(): Promise { - const error = await this.evaluate>( - async (element: HTMLElement, pageJavascriptEnabled: boolean) => { - if (!element.isConnected) return 'Node is detached from document'; - if (element.nodeType !== Node.ELEMENT_NODE) - return 'Node is not of type HTMLElement'; - // force-scroll if page's javascript is disabled. - if (!pageJavascriptEnabled) { - element.scrollIntoView({ - block: 'center', - inline: 'center', - // Chrome still supports behavior: instant but it's not in the spec - // so TS shouts We don't want to make this breaking change in - // Puppeteer yet so we'll ignore the line. - // @ts-ignore - behavior: 'instant', - }); - return false; - } - const visibleRatio = await new Promise((resolve) => { - const observer = new IntersectionObserver((entries) => { - resolve(entries[0].intersectionRatio); - observer.disconnect(); - }); - observer.observe(element); + const error = await this.evaluate< + ( + element: HTMLElement, + pageJavascriptEnabled: boolean + ) => Promise + >(async (element, pageJavascriptEnabled) => { + if (!element.isConnected) return 'Node is detached from document'; + if (element.nodeType !== Node.ELEMENT_NODE) + return 'Node is not of type HTMLElement'; + // force-scroll if page's javascript is disabled. + if (!pageJavascriptEnabled) { + element.scrollIntoView({ + block: 'center', + inline: 'center', + // Chrome still supports behavior: instant but it's not in the spec + // so TS shouts We don't want to make this breaking change in + // Puppeteer yet so we'll ignore the line. + // @ts-ignore + behavior: 'instant', }); - if (visibleRatio !== 1.0) { - element.scrollIntoView({ - block: 'center', - inline: 'center', - // Chrome still supports behavior: instant but it's not in the spec - // so TS shouts We don't want to make this breaking change in - // Puppeteer yet so we'll ignore the line. - // @ts-ignore - behavior: 'instant', - }); - } return false; - }, - this._page.isJavaScriptEnabled() - ); + } + const visibleRatio = await new Promise((resolve) => { + const observer = new IntersectionObserver((entries) => { + resolve(entries[0].intersectionRatio); + observer.disconnect(); + }); + observer.observe(element); + }); + if (visibleRatio !== 1.0) { + element.scrollIntoView({ + block: 'center', + inline: 'center', + // Chrome still supports behavior: instant but it's not in the spec + // so TS shouts We don't want to make this breaking change in + // Puppeteer yet so we'll ignore the line. + // @ts-ignore + behavior: 'instant', + }); + } + return false; + }, this._page.isJavaScriptEnabled()); if (error) throw new Error(error); } @@ -491,9 +499,9 @@ export class ElementHandle extends JSHandle { * relative to the {@link https://nodejs.org/api/process.html#process_process_cwd | current working directory} */ async uploadFile(...filePaths: string[]): Promise { - const isMultiple = await this.evaluate( - (element: HTMLInputElement) => element.multiple - ); + const isMultiple = await this.evaluate< + (element: HTMLInputElement) => boolean + >((element) => element.multiple); assert( filePaths.length <= 1 || isMultiple, 'Multiple file uploads only work with ' @@ -772,15 +780,15 @@ export class ElementHandle extends JSHandle { */ async $eval( selector: string, - pageFunction: Function | string, - ...args: unknown[] + pageFunction: EvaluateFn | string, + ...args: SerializableOrJSHandle[] ): Promise { const elementHandle = await this.$(selector); if (!elementHandle) throw new Error( `Error: failed to find element matching selector "${selector}"` ); - const result = await elementHandle.evaluate( + const result = await elementHandle.evaluate<(...args: any[]) => ReturnType>( pageFunction, ...args ); @@ -813,8 +821,8 @@ export class ElementHandle extends JSHandle { */ async $$eval( selector: string, - pageFunction: Function | string, - ...args: unknown[] + pageFunction: EvaluateFn | string, + ...args: SerializableOrJSHandle[] ): Promise { const defaultHandler = (element: Element, selector: string) => Array.from(element.querySelectorAll(selector)); @@ -827,7 +835,7 @@ export class ElementHandle extends JSHandle { queryHandler, updatedSelector ); - const result = await arrayHandle.evaluate( + const result = await arrayHandle.evaluate<(...args: any[]) => ReturnType>( pageFunction, ...args ); @@ -868,16 +876,18 @@ export class ElementHandle extends JSHandle { * Resolves to true if the element is visible in the current viewport. */ async isIntersectingViewport(): Promise { - return await this.evaluate>(async (element) => { - const visibleRatio = await new Promise((resolve) => { - const observer = new IntersectionObserver((entries) => { - resolve(entries[0].intersectionRatio); - observer.disconnect(); + return await this.evaluate<(element: Element) => Promise>( + async (element) => { + const visibleRatio = await new Promise((resolve) => { + const observer = new IntersectionObserver((entries) => { + resolve(entries[0].intersectionRatio); + observer.disconnect(); + }); + observer.observe(element); }); - observer.observe(element); - }); - return visibleRatio > 0; - }); + return visibleRatio > 0; + } + ); } } diff --git a/src/common/Page.ts b/src/common/Page.ts index ebe5bdce..0fd724fb 100644 --- a/src/common/Page.ts +++ b/src/common/Page.ts @@ -42,6 +42,7 @@ import { FileChooser } from './FileChooser'; import { ConsoleMessage, ConsoleMessageType } from './ConsoleMessage'; import { PuppeteerLifeCycleEvent } from './LifecycleWatcher'; import Protocol from '../protocol'; +import { EvaluateFn, SerializableOrJSHandle } from './EvalTypes'; const writeFileAsync = promisify(fs.writeFile); @@ -514,16 +515,16 @@ export class Page extends EventEmitter { async $eval( selector: string, - pageFunction: Function | string, - ...args: unknown[] + pageFunction: EvaluateFn | string, + ...args: SerializableOrJSHandle[] ): Promise { return this.mainFrame().$eval(selector, pageFunction, ...args); } async $$eval( selector: string, - pageFunction: Function | string, - ...args: unknown[] + pageFunction: EvaluateFn | string, + ...args: SerializableOrJSHandle[] ): Promise { return this.mainFrame().$$eval(selector, pageFunction, ...args); }