mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
feat(types): add (and fix) evaluateHandle
types (#6130)
This change started as a small change to pull types from DefinitelyTyped over to Puppeteer for the `evaluateHandle` function but instead ended up also fixing what looks to be a long standing issue with our existing documentation. `evaluateHandle` can in fact return an `ElementHandle` rather than a `JSHandle`. Note that `ElementHandle` extends `JSHandle` so whilst the docs are technically correct (all ElementHandles are JSHandles) it's confusing because JSHandles don't have methods like `click` on them, but ElementHandles do. if you return something that is an HTML element: ``` const button = page.evaluateHandle(() => document.querySelector('button')); // this is an ElementHandle, not a JSHandle ``` Therefore I've updated the original docs and added a large explanation to the TSDoc for `page.evaluateHandle`. In TypeScript land we'll assume the function will return a `JSHandle` but you can tell TS otherwise via the generic argument, which can only be `JSHandle` (the default) or `ElementHandle`: ``` const button = page.evaluateHandle<ElementHandle>(() => document.querySelector('button')); ```
This commit is contained in:
parent
3c0dc45e47
commit
8370ec88ae
30
docs/api.md
30
docs/api.md
@ -1456,7 +1456,7 @@ Shortcut for [page.mainFrame().evaluate(pageFunction, ...args)](#frameevaluatepa
|
||||
#### page.evaluateHandle(pageFunction[, ...args])
|
||||
- `pageFunction` <[function]|[string]> Function to be evaluated in the page context
|
||||
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
|
||||
- returns: <[Promise]<[JSHandle]>> Promise which resolves to the return value of `pageFunction` as in-page object (JSHandle)
|
||||
- returns: <[Promise]<[JSHandle]|[ElementHandle]>> Promise which resolves to the return value of `pageFunction` as an in-page object.
|
||||
|
||||
The only difference between `page.evaluate` and `page.evaluateHandle` is that `page.evaluateHandle` returns in-page object (JSHandle).
|
||||
|
||||
@ -1475,6 +1475,14 @@ console.log(await resultHandle.jsonValue());
|
||||
await resultHandle.dispose();
|
||||
```
|
||||
|
||||
This function will return a [JSHandle] by default, however if your `pageFunction` returns an HTML element you will get back an `ElementHandle`:
|
||||
|
||||
```js
|
||||
const button = await page.evaluateHandle(() => document.querySelector('button'))
|
||||
// button is an ElementHandle, so you can call methods such as click:
|
||||
await button.click();
|
||||
```
|
||||
|
||||
Shortcut for [page.mainFrame().executionContext().evaluateHandle(pageFunction, ...args)](#executioncontextevaluatehandlepagefunction-args).
|
||||
|
||||
#### page.evaluateOnNewDocument(pageFunction[, ...args])
|
||||
@ -2298,12 +2306,14 @@ Shortcut for [(await worker.executionContext()).evaluate(pageFunction, ...args)]
|
||||
#### webWorker.evaluateHandle(pageFunction[, ...args])
|
||||
- `pageFunction` <[function]|[string]> Function to be evaluated in the page context
|
||||
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
|
||||
- returns: <[Promise]<[JSHandle]>> Promise which resolves to the return value of `pageFunction` as in-page object (JSHandle)
|
||||
- returns: <[Promise]<[JSHandle]|[ElementHandle]>> Promise which resolves to the return value of `pageFunction` as an in-page object.
|
||||
|
||||
The only difference between `worker.evaluate` and `worker.evaluateHandle` is that `worker.evaluateHandle` returns in-page object (JSHandle).
|
||||
|
||||
If the function passed to the `worker.evaluateHandle` returns a [Promise], then `worker.evaluateHandle` would wait for the promise to resolve and return its value.
|
||||
|
||||
If the function returns an element, the returned handle is an [ElementHandle].
|
||||
|
||||
Shortcut for [(await worker.executionContext()).evaluateHandle(pageFunction, ...args)](#executioncontextevaluatehandlepagefunction-args).
|
||||
|
||||
#### webWorker.executionContext()
|
||||
@ -2855,12 +2865,14 @@ await bodyHandle.dispose();
|
||||
#### frame.evaluateHandle(pageFunction[, ...args])
|
||||
- `pageFunction` <[function]|[string]> Function to be evaluated in the page context
|
||||
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
|
||||
- returns: <[Promise]<[JSHandle]>> Promise which resolves to the return value of `pageFunction` as in-page object (JSHandle)
|
||||
- returns: <[Promise]<[JSHandle]|[ElementHandle]>> Promise which resolves to the return value of `pageFunction` as an in-page object.
|
||||
|
||||
The only difference between `frame.evaluate` and `frame.evaluateHandle` is that `frame.evaluateHandle` returns in-page object (JSHandle).
|
||||
|
||||
If the function, passed to the `frame.evaluateHandle`, returns a [Promise], then `frame.evaluateHandle` would wait for the promise to resolve and return its value.
|
||||
|
||||
If the function returns an element, the returned handle is an [ElementHandle].
|
||||
|
||||
```js
|
||||
const aWindowHandle = await frame.evaluateHandle(() => Promise.resolve(window));
|
||||
aWindowHandle; // Handle for the window object.
|
||||
@ -3184,10 +3196,12 @@ console.log(result); // prints '3'.
|
||||
#### executionContext.evaluateHandle(pageFunction[, ...args])
|
||||
- `pageFunction` <[function]|[string]> Function to be evaluated in the `executionContext`
|
||||
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
|
||||
- returns: <[Promise]<[JSHandle]>> Promise which resolves to the return value of `pageFunction` as in-page object (JSHandle)
|
||||
- returns: <[Promise]<[JSHandle]|[ElementHandle]>> Promise which resolves to the return value of `pageFunction` as an in-page object.
|
||||
|
||||
The only difference between `executionContext.evaluate` and `executionContext.evaluateHandle` is that `executionContext.evaluateHandle` returns in-page object (JSHandle).
|
||||
|
||||
If the function returns an element, the returned handle is an [ElementHandle].
|
||||
|
||||
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.
|
||||
|
||||
```js
|
||||
@ -3277,12 +3291,14 @@ expect(await tweetHandle.evaluate(node => node.innerText)).toBe('10');
|
||||
#### jsHandle.evaluateHandle(pageFunction[, ...args])
|
||||
- `pageFunction` <[function]|[string]> Function to be evaluated
|
||||
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
|
||||
- returns: <[Promise]<[JSHandle]>> Promise which resolves to the return value of `pageFunction` as in-page object (JSHandle)
|
||||
- returns: <[Promise]<[JSHandle]|[ElementHandle]>> Promise which resolves to the return value of `pageFunction` as an in-page object.
|
||||
|
||||
This method passes this handle as the first argument to `pageFunction`.
|
||||
|
||||
The only difference between `jsHandle.evaluate` and `jsHandle.evaluateHandle` is that `executionContext.evaluateHandle` returns in-page object (JSHandle).
|
||||
|
||||
If the function returns an element, the returned handle is an [ElementHandle].
|
||||
|
||||
If the function passed to the `jsHandle.evaluateHandle` returns a [Promise], then `jsHandle.evaluateHandle` would wait for the promise to resolve and return its value.
|
||||
|
||||
See [Page.evaluateHandle](#pageevaluatehandlepagefunction-args) for more details.
|
||||
@ -3466,12 +3482,14 @@ expect(await tweetHandle.evaluate(node => node.innerText)).toBe('10');
|
||||
#### elementHandle.evaluateHandle(pageFunction[, ...args])
|
||||
- `pageFunction` <[function]|[string]> Function to be evaluated
|
||||
- `...args` <...[Serializable]|[JSHandle]> Arguments to pass to `pageFunction`
|
||||
- returns: <[Promise]<[JSHandle]>> Promise which resolves to the return value of `pageFunction` as in-page object (JSHandle)
|
||||
- returns: <[Promise]<[JSHandle]|[ElementHandle]>> Promise which resolves to the return value of `pageFunction` as an in-page object.
|
||||
|
||||
This method passes this handle as the first argument to `pageFunction`.
|
||||
|
||||
The only difference between `evaluateHandle.evaluate` and `evaluateHandle.evaluateHandle` is that `executionContext.evaluateHandle` returns in-page object (JSHandle).
|
||||
|
||||
If the function returns an element, the returned handle is an [ElementHandle].
|
||||
|
||||
If the function passed to the `evaluateHandle.evaluateHandle` returns a [Promise], then `evaluateHandle.evaluateHandle` would wait for the promise to resolve and return its value.
|
||||
|
||||
See [Page.evaluateHandle](#pageevaluatehandlepagefunction-args) for more details.
|
||||
|
12
new-docs/puppeteer.evaluatehandlefn.md
Normal file
12
new-docs/puppeteer.evaluatehandlefn.md
Normal file
@ -0,0 +1,12 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [puppeteer](./puppeteer.md) > [EvaluateHandleFn](./puppeteer.evaluatehandlefn.md)
|
||||
|
||||
## EvaluateHandleFn type
|
||||
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type EvaluateHandleFn = string | ((...args: unknown[]) => unknown);
|
||||
```
|
@ -7,19 +7,19 @@
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
evaluateHandle(pageFunction: Function | string, ...args: unknown[]): Promise<JSHandle>;
|
||||
evaluateHandle<HandleType extends JSHandle | ElementHandle = JSHandle>(pageFunction: EvaluateHandleFn, ...args: SerializableOrJSHandle[]): Promise<HandleType>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| pageFunction | Function \| string | a function to be evaluated in the <code>executionContext</code> |
|
||||
| args | unknown\[\] | argument to pass to the page function |
|
||||
| pageFunction | [EvaluateHandleFn](./puppeteer.evaluatehandlefn.md) | a function to be evaluated in the <code>executionContext</code> |
|
||||
| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)<!-- -->\[\] | argument to pass to the page function |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
Promise<[JSHandle](./puppeteer.jshandle.md)<!-- -->>
|
||||
Promise<HandleType>
|
||||
|
||||
A promise that resolves to the return value of the given function as an in-page object (a [JSHandle](./puppeteer.jshandle.md)<!-- -->).
|
||||
|
||||
|
@ -7,17 +7,17 @@
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
evaluateHandle(pageFunction: Function | string, ...args: unknown[]): Promise<JSHandle>;
|
||||
evaluateHandle<HandlerType extends JSHandle = JSHandle>(pageFunction: EvaluateHandleFn, ...args: SerializableOrJSHandle[]): Promise<HandlerType>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| pageFunction | Function \| string | |
|
||||
| args | unknown\[\] | |
|
||||
| pageFunction | [EvaluateHandleFn](./puppeteer.evaluatehandlefn.md) | |
|
||||
| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)<!-- -->\[\] | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
Promise<[JSHandle](./puppeteer.jshandle.md)<!-- -->>
|
||||
Promise<HandlerType>
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
waitFor(selectorOrFunctionOrTimeout: string | number | Function, options?: {}, ...args: unknown[]): Promise<JSHandle | null>;
|
||||
waitFor(selectorOrFunctionOrTimeout: string | number | Function, options?: {}, ...args: SerializableOrJSHandle[]): Promise<JSHandle | null>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
@ -16,7 +16,7 @@ waitFor(selectorOrFunctionOrTimeout: string | number | Function, options?: {}, .
|
||||
| --- | --- | --- |
|
||||
| selectorOrFunctionOrTimeout | string \| number \| Function | |
|
||||
| options | {} | |
|
||||
| args | unknown\[\] | |
|
||||
| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)<!-- -->\[\] | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
waitForFunction(pageFunction: Function | string, options?: {
|
||||
polling?: string | number;
|
||||
timeout?: number;
|
||||
}, ...args: unknown[]): Promise<JSHandle>;
|
||||
}, ...args: SerializableOrJSHandle[]): Promise<JSHandle>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
@ -19,7 +19,7 @@ waitForFunction(pageFunction: Function | string, options?: {
|
||||
| --- | --- | --- |
|
||||
| pageFunction | Function \| string | |
|
||||
| options | { polling?: string \| number; timeout?: number; } | |
|
||||
| args | unknown\[\] | |
|
||||
| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)<!-- -->\[\] | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
|
@ -9,19 +9,19 @@ This method passes this handle as the first argument to `pageFunction`<!-- -->.
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
evaluateHandle(pageFunction: Function | string, ...args: unknown[]): Promise<JSHandle>;
|
||||
evaluateHandle<HandleType extends JSHandle | ElementHandle = JSHandle>(pageFunction: EvaluateHandleFn, ...args: SerializableOrJSHandle[]): Promise<HandleType>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| pageFunction | Function \| string | |
|
||||
| args | unknown\[\] | |
|
||||
| pageFunction | [EvaluateHandleFn](./puppeteer.evaluatehandlefn.md) | |
|
||||
| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)<!-- -->\[\] | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
Promise<[JSHandle](./puppeteer.jshandle.md)<!-- -->>
|
||||
Promise<HandleType>
|
||||
|
||||
## Remarks
|
||||
|
||||
|
@ -82,6 +82,7 @@
|
||||
| [ConsoleMessageType](./puppeteer.consolemessagetype.md) | The supported types for console messages. |
|
||||
| [EvaluateFn](./puppeteer.evaluatefn.md) | |
|
||||
| [EvaluateFnReturnType](./puppeteer.evaluatefnreturntype.md) | |
|
||||
| [EvaluateHandleFn](./puppeteer.evaluatehandlefn.md) | |
|
||||
| [JSONArray](./puppeteer.jsonarray.md) | |
|
||||
| [KeyInput](./puppeteer.keyinput.md) | |
|
||||
| [MouseButtonInput](./puppeteer.mousebuttoninput.md) | |
|
||||
|
@ -7,17 +7,62 @@
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
evaluateHandle(pageFunction: Function | string, ...args: unknown[]): Promise<JSHandle>;
|
||||
evaluateHandle<HandlerType extends JSHandle = JSHandle>(pageFunction: EvaluateHandleFn, ...args: SerializableOrJSHandle[]): Promise<HandlerType>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| pageFunction | Function \| string | |
|
||||
| args | unknown\[\] | |
|
||||
| pageFunction | [EvaluateHandleFn](./puppeteer.evaluatehandlefn.md) | a function that is run within the page |
|
||||
| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)<!-- -->\[\] | arguments to be passed to the pageFunction |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
Promise<[JSHandle](./puppeteer.jshandle.md)<!-- -->>
|
||||
Promise<HandlerType>
|
||||
|
||||
## Remarks
|
||||
|
||||
The only difference between [page.evaluate](./puppeteer.page.evaluate.md) and `page.evaluateHandle` is that `evaluateHandle` will return the value wrapped in an in-page object.
|
||||
|
||||
If the function passed to `page.evaluteHandle` returns a Promise, the function will wait for the promise to resolve and return its value.
|
||||
|
||||
You can pass a string instead of a function (although functions are recommended as they are easier to debug and use with TypeScript):
|
||||
|
||||
## Example 1
|
||||
|
||||
|
||||
```
|
||||
const aHandle = await page.evaluateHandle('document')
|
||||
|
||||
```
|
||||
|
||||
## Example 2
|
||||
|
||||
[JSHandle](./puppeteer.jshandle.md) instances can be passed as arguments to the `pageFunction`<!-- -->:
|
||||
|
||||
```
|
||||
const aHandle = await page.evaluateHandle(() => document.body);
|
||||
const resultHandle = await page.evaluateHandle(body => body.innerHTML, aHandle);
|
||||
console.log(await resultHandle.jsonValue());
|
||||
await resultHandle.dispose();
|
||||
|
||||
```
|
||||
Most of the time this function returns a [JSHandle](./puppeteer.jshandle.md)<!-- -->, but if `pageFunction` returns a reference to an element, you instead get an [ElementHandle](./puppeteer.elementhandle.md) back:
|
||||
|
||||
## Example 3
|
||||
|
||||
|
||||
```
|
||||
const button = await page.evaluateHandle(() => document.querySelector('button'));
|
||||
// can call `click` because `button` is an `ElementHandle`
|
||||
await button.click();
|
||||
|
||||
```
|
||||
The TypeScript definitions assume that `evaluateHandle` returns a `JSHandle`<!-- -->, but if you know it's going to return an `ElementHandle`<!-- -->, pass it as the generic argument:
|
||||
|
||||
```
|
||||
const button = await page.evaluateHandle<ElementHandle>(...);
|
||||
|
||||
```
|
||||
|
||||
|
@ -12,7 +12,7 @@ waitFor(selectorOrFunctionOrTimeout: string | number | Function, options?: {
|
||||
hidden?: boolean;
|
||||
timeout?: number;
|
||||
polling?: string | number;
|
||||
}, ...args: unknown[]): Promise<JSHandle>;
|
||||
}, ...args: SerializableOrJSHandle[]): Promise<JSHandle>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
@ -21,7 +21,7 @@ waitFor(selectorOrFunctionOrTimeout: string | number | Function, options?: {
|
||||
| --- | --- | --- |
|
||||
| selectorOrFunctionOrTimeout | string \| number \| Function | |
|
||||
| options | { visible?: boolean; hidden?: boolean; timeout?: number; polling?: string \| number; } | |
|
||||
| args | unknown\[\] | |
|
||||
| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)<!-- -->\[\] | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
waitForFunction(pageFunction: Function | string, options?: {
|
||||
timeout?: number;
|
||||
polling?: string | number;
|
||||
}, ...args: unknown[]): Promise<JSHandle>;
|
||||
}, ...args: SerializableOrJSHandle[]): Promise<JSHandle>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
@ -19,7 +19,7 @@ waitForFunction(pageFunction: Function | string, options?: {
|
||||
| --- | --- | --- |
|
||||
| pageFunction | Function \| string | |
|
||||
| options | { timeout?: number; polling?: string \| number; } | |
|
||||
| args | unknown\[\] | |
|
||||
| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)<!-- -->\[\] | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
|
@ -9,15 +9,15 @@ The only difference between `worker.evaluate` and `worker.evaluateHandle` is tha
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
evaluateHandle(pageFunction: Function | string, ...args: any[]): Promise<JSHandle>;
|
||||
evaluateHandle<HandlerType extends JSHandle = JSHandle>(pageFunction: EvaluateHandleFn, ...args: SerializableOrJSHandle[]): Promise<JSHandle>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| pageFunction | Function \| string | Function to be evaluated in the page context. |
|
||||
| args | any\[\] | Arguments to pass to <code>pageFunction</code>. |
|
||||
| pageFunction | [EvaluateHandleFn](./puppeteer.evaluatehandlefn.md) | Function to be evaluated in the page context. |
|
||||
| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)<!-- -->\[\] | Arguments to pass to <code>pageFunction</code>. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
|
@ -24,7 +24,11 @@ import { TimeoutSettings } from './TimeoutSettings';
|
||||
import { MouseButtonInput } from './Input';
|
||||
import { FrameManager, Frame } from './FrameManager';
|
||||
import { getQueryHandlerAndSelector, QueryHandler } from './QueryHandler';
|
||||
import { EvaluateFn, SerializableOrJSHandle } from './EvalTypes';
|
||||
import {
|
||||
EvaluateFn,
|
||||
SerializableOrJSHandle,
|
||||
EvaluateHandleFn,
|
||||
} from './EvalTypes';
|
||||
import { isNode } from '../environment';
|
||||
|
||||
// This predicateQueryHandler is declared here so that TypeScript knows about it
|
||||
@ -103,15 +107,10 @@ export class DOMWorld {
|
||||
return this._contextPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Function|string} pageFunction
|
||||
* @param {!Array<*>} args
|
||||
* @returns {!Promise<!JSHandle>}
|
||||
*/
|
||||
async evaluateHandle(
|
||||
pageFunction: Function | string,
|
||||
...args: unknown[]
|
||||
): Promise<JSHandle> {
|
||||
async evaluateHandle<HandlerType extends JSHandle = JSHandle>(
|
||||
pageFunction: EvaluateHandleFn,
|
||||
...args: SerializableOrJSHandle[]
|
||||
): Promise<HandlerType> {
|
||||
const context = await this.executionContext();
|
||||
return context.evaluateHandle(pageFunction, ...args);
|
||||
}
|
||||
@ -470,7 +469,7 @@ export class DOMWorld {
|
||||
waitForFunction(
|
||||
pageFunction: Function | string,
|
||||
options: { polling?: string | number; timeout?: number } = {},
|
||||
...args: unknown[]
|
||||
...args: SerializableOrJSHandle[]
|
||||
): Promise<JSHandle> {
|
||||
const {
|
||||
polling = 'raf',
|
||||
@ -581,7 +580,7 @@ class WaitTask {
|
||||
_polling: string | number;
|
||||
_timeout: number;
|
||||
_predicateBody: string;
|
||||
_args: unknown[];
|
||||
_args: SerializableOrJSHandle[];
|
||||
_runCount = 0;
|
||||
promise: Promise<JSHandle>;
|
||||
_resolve: (x: JSHandle) => void;
|
||||
@ -596,7 +595,7 @@ class WaitTask {
|
||||
title: string,
|
||||
polling: string | number,
|
||||
timeout: number,
|
||||
...args: unknown[]
|
||||
...args: SerializableOrJSHandle[]
|
||||
) {
|
||||
if (helper.isString(polling))
|
||||
assert(
|
||||
|
@ -29,6 +29,11 @@ export type EvaluateFnReturnType<T extends EvaluateFn> = T extends (
|
||||
? R
|
||||
: unknown;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type EvaluateHandleFn = string | ((...args: unknown[]) => unknown);
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
|
@ -21,6 +21,7 @@ import { CDPSession } from './Connection';
|
||||
import { DOMWorld } from './DOMWorld';
|
||||
import { Frame } from './FrameManager';
|
||||
import Protocol from '../protocol';
|
||||
import { EvaluateHandleFn, SerializableOrJSHandle } from './EvalTypes';
|
||||
|
||||
export const EVALUATION_SCRIPT_URL = '__puppeteer_evaluation_script__';
|
||||
const SOURCE_URL_REGEX = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/m;
|
||||
@ -175,15 +176,15 @@ export class ExecutionContext {
|
||||
* @returns A promise that resolves to the return value of the given function
|
||||
* as an in-page object (a {@link JSHandle}).
|
||||
*/
|
||||
async evaluateHandle(
|
||||
pageFunction: Function | string,
|
||||
...args: unknown[]
|
||||
): Promise<JSHandle> {
|
||||
return this._evaluateInternal<JSHandle>(false, pageFunction, ...args);
|
||||
async evaluateHandle<HandleType extends JSHandle | ElementHandle = JSHandle>(
|
||||
pageFunction: EvaluateHandleFn,
|
||||
...args: SerializableOrJSHandle[]
|
||||
): Promise<HandleType> {
|
||||
return this._evaluateInternal<HandleType>(false, pageFunction, ...args);
|
||||
}
|
||||
|
||||
private async _evaluateInternal<ReturnType>(
|
||||
returnByValue,
|
||||
returnByValue: boolean,
|
||||
pageFunction: Function | string,
|
||||
...args: unknown[]
|
||||
): Promise<ReturnType> {
|
||||
|
@ -29,7 +29,11 @@ import { MouseButtonInput } from './Input';
|
||||
import { Page } from './Page';
|
||||
import { HTTPResponse } from './HTTPResponse';
|
||||
import Protocol from '../protocol';
|
||||
import { EvaluateFn, SerializableOrJSHandle } from './EvalTypes';
|
||||
import {
|
||||
EvaluateFn,
|
||||
SerializableOrJSHandle,
|
||||
EvaluateHandleFn,
|
||||
} from './EvalTypes';
|
||||
|
||||
const UTILITY_WORLD_NAME = '__puppeteer_utility_world__';
|
||||
|
||||
@ -431,11 +435,11 @@ export class Frame {
|
||||
return this._mainWorld.executionContext();
|
||||
}
|
||||
|
||||
async evaluateHandle(
|
||||
pageFunction: Function | string,
|
||||
...args: unknown[]
|
||||
): Promise<JSHandle> {
|
||||
return this._mainWorld.evaluateHandle(pageFunction, ...args);
|
||||
async evaluateHandle<HandlerType extends JSHandle = JSHandle>(
|
||||
pageFunction: EvaluateHandleFn,
|
||||
...args: SerializableOrJSHandle[]
|
||||
): Promise<HandlerType> {
|
||||
return this._mainWorld.evaluateHandle<HandlerType>(pageFunction, ...args);
|
||||
}
|
||||
|
||||
async evaluate<ReturnType extends any>(
|
||||
@ -562,7 +566,7 @@ export class Frame {
|
||||
waitFor(
|
||||
selectorOrFunctionOrTimeout: string | number | Function,
|
||||
options: {} = {},
|
||||
...args: unknown[]
|
||||
...args: SerializableOrJSHandle[]
|
||||
): Promise<JSHandle | null> {
|
||||
const xPathPattern = '//';
|
||||
|
||||
@ -619,7 +623,7 @@ export class Frame {
|
||||
waitForFunction(
|
||||
pageFunction: Function | string,
|
||||
options: { polling?: string | number; timeout?: number } = {},
|
||||
...args: unknown[]
|
||||
...args: SerializableOrJSHandle[]
|
||||
): Promise<JSHandle> {
|
||||
return this._mainWorld.waitForFunction(pageFunction, options, ...args);
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import {
|
||||
EvaluateFn,
|
||||
SerializableOrJSHandle,
|
||||
EvaluateFnReturnType,
|
||||
EvaluateHandleFn,
|
||||
} from './EvalTypes';
|
||||
|
||||
export interface BoxModel {
|
||||
@ -174,10 +175,10 @@ export class JSHandle {
|
||||
*
|
||||
* See {@link Page.evaluateHandle} for more details.
|
||||
*/
|
||||
async evaluateHandle(
|
||||
pageFunction: Function | string,
|
||||
...args: unknown[]
|
||||
): Promise<JSHandle> {
|
||||
async evaluateHandle<HandleType extends JSHandle | ElementHandle = JSHandle>(
|
||||
pageFunction: EvaluateHandleFn,
|
||||
...args: SerializableOrJSHandle[]
|
||||
): Promise<HandleType> {
|
||||
return await this.executionContext().evaluateHandle(
|
||||
pageFunction,
|
||||
this,
|
||||
@ -891,19 +892,22 @@ export class ElementHandle extends JSHandle {
|
||||
* @param expression - Expression to {@link https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate | evaluate}
|
||||
*/
|
||||
async $x(expression: string): Promise<ElementHandle[]> {
|
||||
const arrayHandle = await this.evaluateHandle((element, expression) => {
|
||||
const document = element.ownerDocument || element;
|
||||
const iterator = document.evaluate(
|
||||
expression,
|
||||
element,
|
||||
null,
|
||||
XPathResult.ORDERED_NODE_ITERATOR_TYPE
|
||||
);
|
||||
const array = [];
|
||||
let item;
|
||||
while ((item = iterator.iterateNext())) array.push(item);
|
||||
return array;
|
||||
}, expression);
|
||||
const arrayHandle = await this.evaluateHandle(
|
||||
(element: Document, expression: string) => {
|
||||
const document = element.ownerDocument || element;
|
||||
const iterator = document.evaluate(
|
||||
expression,
|
||||
element,
|
||||
null,
|
||||
XPathResult.ORDERED_NODE_ITERATOR_TYPE
|
||||
);
|
||||
const array = [];
|
||||
let item;
|
||||
while ((item = iterator.iterateNext())) array.push(item);
|
||||
return array;
|
||||
},
|
||||
expression
|
||||
);
|
||||
const properties = await arrayHandle.getProperties();
|
||||
await arrayHandle.dispose();
|
||||
const result = [];
|
||||
|
@ -42,7 +42,11 @@ import { FileChooser } from './FileChooser';
|
||||
import { ConsoleMessage, ConsoleMessageType } from './ConsoleMessage';
|
||||
import { PuppeteerLifeCycleEvent } from './LifecycleWatcher';
|
||||
import Protocol from '../protocol';
|
||||
import { EvaluateFn, SerializableOrJSHandle } from './EvalTypes';
|
||||
import {
|
||||
EvaluateFn,
|
||||
SerializableOrJSHandle,
|
||||
EvaluateHandleFn,
|
||||
} from './EvalTypes';
|
||||
|
||||
const writeFileAsync = promisify(fs.writeFile);
|
||||
|
||||
@ -639,12 +643,61 @@ export class Page extends EventEmitter {
|
||||
return this.mainFrame().$(selector);
|
||||
}
|
||||
|
||||
async evaluateHandle(
|
||||
pageFunction: Function | string,
|
||||
...args: unknown[]
|
||||
): Promise<JSHandle> {
|
||||
/**
|
||||
* @remarks
|
||||
*
|
||||
* The only difference between {@link Page.evaluate | page.evaluate} and
|
||||
* `page.evaluateHandle` is that `evaluateHandle` will return the value
|
||||
* wrapped in an in-page object.
|
||||
*
|
||||
* If the function passed to `page.evaluteHandle` returns a Promise, the
|
||||
* function will wait for the promise to resolve and return its value.
|
||||
*
|
||||
* You can pass a string instead of a function (although functions are
|
||||
* recommended as they are easier to debug and use with TypeScript):
|
||||
*
|
||||
* @example
|
||||
* ```
|
||||
* const aHandle = await page.evaluateHandle('document')
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* {@link JSHandle} instances can be passed as arguments to the `pageFunction`:
|
||||
* ```
|
||||
* const aHandle = await page.evaluateHandle(() => document.body);
|
||||
* const resultHandle = await page.evaluateHandle(body => body.innerHTML, aHandle);
|
||||
* console.log(await resultHandle.jsonValue());
|
||||
* await resultHandle.dispose();
|
||||
* ```
|
||||
*
|
||||
* Most of the time this function returns a {@link JSHandle},
|
||||
* but if `pageFunction` returns a reference to an element,
|
||||
* you instead get an {@link ElementHandle} back:
|
||||
*
|
||||
* @example
|
||||
* ```
|
||||
* const button = await page.evaluateHandle(() => document.querySelector('button'));
|
||||
* // can call `click` because `button` is an `ElementHandle`
|
||||
* await button.click();
|
||||
* ```
|
||||
*
|
||||
* The TypeScript definitions assume that `evaluateHandle` returns
|
||||
* a `JSHandle`, but if you know it's going to return an
|
||||
* `ElementHandle`, pass it as the generic argument:
|
||||
*
|
||||
* ```
|
||||
* const button = await page.evaluateHandle<ElementHandle>(...);
|
||||
* ```
|
||||
*
|
||||
* @param pageFunction - a function that is run within the page
|
||||
* @param args - arguments to be passed to the pageFunction
|
||||
*/
|
||||
async evaluateHandle<HandlerType extends JSHandle = JSHandle>(
|
||||
pageFunction: EvaluateHandleFn,
|
||||
...args: SerializableOrJSHandle[]
|
||||
): Promise<HandlerType> {
|
||||
const context = await this.mainFrame().executionContext();
|
||||
return context.evaluateHandle(pageFunction, ...args);
|
||||
return context.evaluateHandle<HandlerType>(pageFunction, ...args);
|
||||
}
|
||||
|
||||
async queryObjects(prototypeHandle: JSHandle): Promise<JSHandle> {
|
||||
@ -1471,7 +1524,7 @@ export class Page extends EventEmitter {
|
||||
timeout?: number;
|
||||
polling?: string | number;
|
||||
} = {},
|
||||
...args: unknown[]
|
||||
...args: SerializableOrJSHandle[]
|
||||
): Promise<JSHandle> {
|
||||
return this.mainFrame().waitFor(
|
||||
selectorOrFunctionOrTimeout,
|
||||
@ -1508,7 +1561,7 @@ export class Page extends EventEmitter {
|
||||
timeout?: number;
|
||||
polling?: string | number;
|
||||
} = {},
|
||||
...args: unknown[]
|
||||
...args: SerializableOrJSHandle[]
|
||||
): Promise<JSHandle> {
|
||||
return this.mainFrame().waitForFunction(pageFunction, options, ...args);
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import { ExecutionContext } from './ExecutionContext';
|
||||
import { JSHandle } from './JSHandle';
|
||||
import { CDPSession } from './Connection';
|
||||
import Protocol from '../protocol';
|
||||
import { EvaluateHandleFn, SerializableOrJSHandle } from './EvalTypes';
|
||||
|
||||
type ConsoleAPICalledCallback = (
|
||||
eventType: string,
|
||||
@ -152,11 +153,11 @@ export class WebWorker extends EventEmitter {
|
||||
* @param args - Arguments to pass to `pageFunction`.
|
||||
* @returns Promise which resolves to the return value of `pageFunction`.
|
||||
*/
|
||||
async evaluateHandle(
|
||||
pageFunction: Function | string,
|
||||
...args: any[]
|
||||
async evaluateHandle<HandlerType extends JSHandle = JSHandle>(
|
||||
pageFunction: EvaluateHandleFn,
|
||||
...args: SerializableOrJSHandle[]
|
||||
): Promise<JSHandle> {
|
||||
return (await this._executionContextPromise).evaluateHandle(
|
||||
return (await this._executionContextPromise).evaluateHandle<HandlerType>(
|
||||
pageFunction,
|
||||
...args
|
||||
);
|
||||
|
@ -182,17 +182,11 @@ describe('ElementHandle specs', function () {
|
||||
const { page, server } = getTestState();
|
||||
|
||||
await page.goto(server.PREFIX + '/shadow.html');
|
||||
const buttonHandle = await page.evaluateHandle(
|
||||
const buttonHandle = await page.evaluateHandle<ElementHandle>(
|
||||
// @ts-expect-error button is expected to be in the page's scope.
|
||||
() => button
|
||||
);
|
||||
// TODO (@jackfranklin): TS types are off here. evaluateHandle returns a
|
||||
// JSHandle but that doesn't have a click() method. In this case it seems
|
||||
// to return an ElementHandle. I'm not sure if the tests are wrong here
|
||||
// and should use evaluate<ElementHandle> or if the type of evaluateHandle
|
||||
// should change to enable the user to tell us they are expecting an
|
||||
// ElementHandle rather than the default JSHandle.
|
||||
await (buttonHandle as ElementHandle).click();
|
||||
await buttonHandle.click();
|
||||
expect(
|
||||
await page.evaluate(
|
||||
// @ts-expect-error clicked is expected to be in the page's scope.
|
||||
|
@ -53,6 +53,7 @@ describe('JSHandle', function () {
|
||||
const aHandle = await page.evaluateHandle(() => document.body);
|
||||
let error = null;
|
||||
await page
|
||||
// @ts-expect-error we are deliberately passing a bad type here (nested object)
|
||||
.evaluateHandle((opts) => opts.elem.querySelector('p'), {
|
||||
elem: aHandle,
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user