Skip to content

Commit

Permalink
feat(types): add (and fix) evaluateHandle types (#6130)
Browse files Browse the repository at this point in the history
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'));
```
  • Loading branch information
jackfranklin committed Jul 1, 2020
1 parent 3c0dc45 commit 8370ec8
Show file tree
Hide file tree
Showing 21 changed files with 235 additions and 97 deletions.
30 changes: 24 additions & 6 deletions docs/api.md
Expand Up @@ -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).

Expand All @@ -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])
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
12 changes: 12 additions & 0 deletions new-docs/puppeteer.evaluatehandlefn.md
@@ -0,0 +1,12 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [puppeteer](./puppeteer.md) &gt; [EvaluateHandleFn](./puppeteer.evaluatehandlefn.md)

## EvaluateHandleFn type


<b>Signature:</b>

```typescript
export declare type EvaluateHandleFn = string | ((...args: unknown[]) => unknown);
```
8 changes: 4 additions & 4 deletions new-docs/puppeteer.executioncontext.evaluatehandle.md
Expand Up @@ -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&lt;[JSHandle](./puppeteer.jshandle.md)<!-- -->&gt;
Promise&lt;HandleType&gt;
A promise that resolves to the return value of the given function as an in-page object (a [JSHandle](./puppeteer.jshandle.md)<!-- -->).
Expand Down
8 changes: 4 additions & 4 deletions new-docs/puppeteer.frame.evaluatehandle.md
Expand Up @@ -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&lt;[JSHandle](./puppeteer.jshandle.md)<!-- -->&gt;
Promise&lt;HandlerType&gt;
4 changes: 2 additions & 2 deletions new-docs/puppeteer.frame.waitfor.md
Expand Up @@ -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
Expand All @@ -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>

Expand Down
4 changes: 2 additions & 2 deletions new-docs/puppeteer.frame.waitforfunction.md
Expand Up @@ -10,7 +10,7 @@
waitForFunction(pageFunction: Function | string, options?: {
polling?: string | number;
timeout?: number;
}, ...args: unknown[]): Promise<JSHandle>;
}, ...args: SerializableOrJSHandle[]): Promise<JSHandle>;
```

## Parameters
Expand All @@ -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>

Expand Down
8 changes: 4 additions & 4 deletions new-docs/puppeteer.jshandle.evaluatehandle.md
Expand Up @@ -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&lt;[JSHandle](./puppeteer.jshandle.md)<!-- -->&gt;
Promise&lt;HandleType&gt;
## Remarks
Expand Down
1 change: 1 addition & 0 deletions new-docs/puppeteer.md
Expand Up @@ -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) | |
Expand Down
53 changes: 49 additions & 4 deletions new-docs/puppeteer.page.evaluatehandle.md
Expand Up @@ -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&lt;[JSHandle](./puppeteer.jshandle.md)<!-- -->&gt;
Promise&lt;HandlerType&gt;
## 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>(...);
```

4 changes: 2 additions & 2 deletions new-docs/puppeteer.page.waitfor.md
Expand Up @@ -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
Expand All @@ -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>

Expand Down
4 changes: 2 additions & 2 deletions new-docs/puppeteer.page.waitforfunction.md
Expand Up @@ -10,7 +10,7 @@
waitForFunction(pageFunction: Function | string, options?: {
timeout?: number;
polling?: string | number;
}, ...args: unknown[]): Promise<JSHandle>;
}, ...args: SerializableOrJSHandle[]): Promise<JSHandle>;
```

## Parameters
Expand All @@ -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>

Expand Down
6 changes: 3 additions & 3 deletions new-docs/puppeteer.webworker.evaluatehandle.md
Expand Up @@ -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>
Expand Down

0 comments on commit 8370ec8

Please sign in to comment.