mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
feat(types): add types for page.$$eval
(#6139)
* feat(types): add types for `page.$$eval` * Add new-docs for $$eval * fix example * linting
This commit is contained in:
parent
f7857d27c4
commit
5049b83186
@ -11,7 +11,7 @@ If `pageFunction` returns a Promise, then `frame.$$eval` would wait for the prom
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
$$eval<ReturnType extends any>(selector: string, pageFunction: EvaluateFn | string, ...args: SerializableOrJSHandle[]): Promise<ReturnType>;
|
||||
$$eval<ReturnType>(selector: string, pageFunction: (elements: Element[], ...args: unknown[]) => ReturnType | Promise<ReturnType>, ...args: SerializableOrJSHandle[]): Promise<WrapElementHandle<ReturnType>>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
@ -19,12 +19,12 @@ $$eval<ReturnType extends any>(selector: string, pageFunction: EvaluateFn | stri
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| selector | string | |
|
||||
| pageFunction | [EvaluateFn](./puppeteer.evaluatefn.md) \| string | |
|
||||
| pageFunction | (elements: Element\[\], ...args: unknown\[\]) => ReturnType \| Promise<ReturnType> | |
|
||||
| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)<!-- -->\[\] | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
Promise<ReturnType>
|
||||
Promise<[WrapElementHandle](./puppeteer.wrapelementhandle.md)<!-- --><ReturnType>>
|
||||
|
||||
## Example 1
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
$$eval<ReturnType extends any>(selector: string, pageFunction: EvaluateFn | string, ...args: SerializableOrJSHandle[]): Promise<ReturnType>;
|
||||
$$eval<ReturnType>(selector: string, pageFunction: (elements: Element[], ...args: unknown[]) => ReturnType | Promise<ReturnType>, ...args: SerializableOrJSHandle[]): Promise<WrapElementHandle<ReturnType>>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
@ -15,10 +15,10 @@ $$eval<ReturnType extends any>(selector: string, pageFunction: EvaluateFn | stri
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| selector | string | |
|
||||
| pageFunction | [EvaluateFn](./puppeteer.evaluatefn.md) \| string | |
|
||||
| pageFunction | (elements: Element\[\], ...args: unknown\[\]) => ReturnType \| Promise<ReturnType> | |
|
||||
| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)<!-- -->\[\] | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
Promise<ReturnType>
|
||||
Promise<[WrapElementHandle](./puppeteer.wrapelementhandle.md)<!-- --><ReturnType>>
|
||||
|
||||
|
@ -9,7 +9,7 @@ This method runs `Array.from(document.querySelectorAll(selector))` within the pa
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
$$eval<ReturnType extends any>(selector: string, pageFunction: EvaluateFn | string, ...args: SerializableOrJSHandle[]): Promise<ReturnType>;
|
||||
$$eval<ReturnType>(selector: string, pageFunction: (elements: Element[], ...args: unknown[]) => ReturnType | Promise<ReturnType>, ...args: SerializableOrJSHandle[]): Promise<WrapElementHandle<ReturnType>>;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
@ -17,14 +17,14 @@ $$eval<ReturnType extends any>(selector: string, pageFunction: EvaluateFn | stri
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| selector | string | the [selector](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors) to query for |
|
||||
| pageFunction | [EvaluateFn](./puppeteer.evaluatefn.md) \| string | the function to be evaluated in the page context. Will be passed the result of <code>Array.from(document.querySelectorAll(selector))</code> as its first argument. |
|
||||
| pageFunction | (elements: Element\[\], ...args: unknown\[\]) => ReturnType \| Promise<ReturnType> | the function to be evaluated in the page context. Will be passed the result of <code>Array.from(document.querySelectorAll(selector))</code> as its first argument. |
|
||||
| args | [SerializableOrJSHandle](./puppeteer.serializableorjshandle.md)<!-- -->\[\] | any additional arguments to pass through to <code>pageFunction</code>. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
Promise<ReturnType>
|
||||
Promise<[WrapElementHandle](./puppeteer.wrapelementhandle.md)<!-- --><ReturnType>>
|
||||
|
||||
The result of calling `pageFunction`<!-- -->.
|
||||
The result of calling `pageFunction`<!-- -->. If it returns an element it is wrapped in an [ElementHandle](./puppeteer.elementhandle.md)<!-- -->, else the raw value itself is returned.
|
||||
|
||||
## Remarks
|
||||
|
||||
@ -33,17 +33,40 @@ If `pageFunction` returns a promise `$$eval` will wait for the promise to resolv
|
||||
## Example 1
|
||||
|
||||
|
||||
```js
|
||||
```
|
||||
// get the amount of divs on the page
|
||||
const divCount = await page.$$eval('div', divs => divs.length);
|
||||
|
||||
// get the text content of all the `.options` elements:
|
||||
const options = await page.$$eval('div > span.options', options => {
|
||||
return options.map(option => option.textContent)
|
||||
});
|
||||
|
||||
```
|
||||
If you are using TypeScript, you may have to provide an explicit type to the first argument of the `pageFunction`<!-- -->. By default it is typed as `Element[]`<!-- -->, but you may need to provide a more specific sub-type:
|
||||
|
||||
## Example 2
|
||||
|
||||
|
||||
```js
|
||||
const options = await page.$$eval(
|
||||
'div > span.options', options => options.map(option => option.textContent));
|
||||
```
|
||||
// if you don't provide HTMLInputElement here, TS will error
|
||||
// as `value` is not on `Element`
|
||||
await page.$$eval('input', (elements: HTMLInputElement[]) => {
|
||||
return elements.map(e => e.value);
|
||||
});
|
||||
|
||||
```
|
||||
The compiler should be able to infer the return type from the `pageFunction` you provide. If it is unable to, you can use the generic type to tell the compiler what return type you expect from `$$eval`<!-- -->:
|
||||
|
||||
## Example 3
|
||||
|
||||
|
||||
```
|
||||
// The compiler can infer the return type in this case, but if it can't
|
||||
// or if you want to be more explicit, provide it as the generic type.
|
||||
const allInputValues = await page.$$eval<string[]>(
|
||||
'input', (elements: HTMLInputElement[]) => elements.map(e => e.textContent)
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
|
@ -25,7 +25,6 @@ import { MouseButton } from './Input';
|
||||
import { FrameManager, Frame } from './FrameManager';
|
||||
import { getQueryHandlerAndSelector, QueryHandler } from './QueryHandler';
|
||||
import {
|
||||
EvaluateFn,
|
||||
SerializableOrJSHandle,
|
||||
EvaluateHandleFn,
|
||||
WrapElementHandle,
|
||||
@ -172,11 +171,14 @@ export class DOMWorld {
|
||||
return document.$eval<ReturnType>(selector, pageFunction, ...args);
|
||||
}
|
||||
|
||||
async $$eval<ReturnType extends any>(
|
||||
async $$eval<ReturnType>(
|
||||
selector: string,
|
||||
pageFunction: EvaluateFn | string,
|
||||
pageFunction: (
|
||||
elements: Element[],
|
||||
...args: unknown[]
|
||||
) => ReturnType | Promise<ReturnType>,
|
||||
...args: SerializableOrJSHandle[]
|
||||
): Promise<ReturnType> {
|
||||
): Promise<WrapElementHandle<ReturnType>> {
|
||||
const document = await this._document();
|
||||
const value = await document.$$eval<ReturnType>(
|
||||
selector,
|
||||
|
@ -30,7 +30,6 @@ import { Page } from './Page';
|
||||
import { HTTPResponse } from './HTTPResponse';
|
||||
import Protocol from '../protocol';
|
||||
import {
|
||||
EvaluateFn,
|
||||
SerializableOrJSHandle,
|
||||
EvaluateHandleFn,
|
||||
WrapElementHandle,
|
||||
@ -496,11 +495,14 @@ export class Frame {
|
||||
return this._mainWorld.$eval<ReturnType>(selector, pageFunction, ...args);
|
||||
}
|
||||
|
||||
async $$eval<ReturnType extends any>(
|
||||
async $$eval<ReturnType>(
|
||||
selector: string,
|
||||
pageFunction: EvaluateFn | string,
|
||||
pageFunction: (
|
||||
elements: Element[],
|
||||
...args: unknown[]
|
||||
) => ReturnType | Promise<ReturnType>,
|
||||
...args: SerializableOrJSHandle[]
|
||||
): Promise<ReturnType> {
|
||||
): Promise<WrapElementHandle<ReturnType>> {
|
||||
return this._mainWorld.$$eval<ReturnType>(selector, pageFunction, ...args);
|
||||
}
|
||||
|
||||
|
@ -882,11 +882,14 @@ export class ElementHandle<
|
||||
* .toEqual(['Hello!', 'Hi!']);
|
||||
* ```
|
||||
*/
|
||||
async $$eval<ReturnType extends any>(
|
||||
async $$eval<ReturnType>(
|
||||
selector: string,
|
||||
pageFunction: EvaluateFn | string,
|
||||
pageFunction: (
|
||||
elements: Element[],
|
||||
...args: unknown[]
|
||||
) => ReturnType | Promise<ReturnType>,
|
||||
...args: SerializableOrJSHandle[]
|
||||
): Promise<ReturnType> {
|
||||
): Promise<WrapElementHandle<ReturnType>> {
|
||||
const defaultHandler = (element: Element, selector: string) =>
|
||||
Array.from(element.querySelectorAll(selector));
|
||||
const { updatedSelector, queryHandler } = getQueryHandlerAndSelector(
|
||||
@ -898,12 +901,17 @@ export class ElementHandle<
|
||||
queryHandler,
|
||||
updatedSelector
|
||||
);
|
||||
const result = await arrayHandle.evaluate<(...args: any[]) => ReturnType>(
|
||||
pageFunction,
|
||||
...args
|
||||
);
|
||||
const result = await arrayHandle.evaluate<
|
||||
(
|
||||
elements: Element[],
|
||||
...args: unknown[]
|
||||
) => ReturnType | Promise<ReturnType>
|
||||
>(pageFunction, ...args);
|
||||
await arrayHandle.dispose();
|
||||
return result;
|
||||
/* This as exists for the same reason as the `as` in $eval above.
|
||||
* See the comment there for a ful explanation.
|
||||
*/
|
||||
return result as WrapElementHandle<ReturnType>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -43,7 +43,6 @@ import { ConsoleMessage, ConsoleMessageType } from './ConsoleMessage';
|
||||
import { PuppeteerLifeCycleEvent } from './LifecycleWatcher';
|
||||
import Protocol from '../protocol';
|
||||
import {
|
||||
EvaluateFn,
|
||||
SerializableOrJSHandle,
|
||||
EvaluateHandleFn,
|
||||
WrapElementHandle,
|
||||
@ -795,31 +794,70 @@ export class Page extends EventEmitter {
|
||||
* resolve and then return its value.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* const divCount = await page.$$eval('div', divs => divs.length);
|
||||
*
|
||||
* ```
|
||||
* // get the amount of divs on the page
|
||||
* const divCount = await page.$$eval('div', divs => divs.length);
|
||||
*
|
||||
* // get the text content of all the `.options` elements:
|
||||
* const options = await page.$$eval('div > span.options', options => {
|
||||
* return options.map(option => option.textContent)
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* If you are using TypeScript, you may have to provide an explicit type to the
|
||||
* first argument of the `pageFunction`.
|
||||
* By default it is typed as `Element[]`, but you may need to provide a more
|
||||
* specific sub-type:
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* const options = await page.$$eval(
|
||||
* 'div > span.options', options => options.map(option => option.textContent));
|
||||
*
|
||||
* ```
|
||||
* // if you don't provide HTMLInputElement here, TS will error
|
||||
* // as `value` is not on `Element`
|
||||
* await page.$$eval('input', (elements: HTMLInputElement[]) => {
|
||||
* return elements.map(e => e.value);
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @param selector - the
|
||||
* The compiler should be able to infer the return type
|
||||
* from the `pageFunction` you provide. If it is unable to, you can use the generic
|
||||
* type to tell the compiler what return type you expect from `$$eval`:
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```
|
||||
* // The compiler can infer the return type in this case, but if it can't
|
||||
* // or if you want to be more explicit, provide it as the generic type.
|
||||
* const allInputValues = await page.$$eval<string[]>(
|
||||
* 'input', (elements: HTMLInputElement[]) => elements.map(e => e.textContent)
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* @param selector the
|
||||
* {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors | selector}
|
||||
* to query for
|
||||
* @param pageFunction - the function to be evaluated in the page context.
|
||||
* Will be passed the result of
|
||||
* `Array.from(document.querySelectorAll(selector))` as its first argument.
|
||||
* @param args - any additional arguments to pass through to `pageFunction`.
|
||||
* @param pageFunction the function to be evaluated in the page context. Will
|
||||
* be passed the result of `Array.from(document.querySelectorAll(selector))`
|
||||
* as its first argument.
|
||||
* @param args any additional arguments to pass through to `pageFunction`.
|
||||
*
|
||||
* @returns The result of calling `pageFunction`.
|
||||
* @returns The result of calling `pageFunction`. If it returns an element it
|
||||
* is wrapped in an {@link ElementHandle}, else the raw value itself is
|
||||
* returned.
|
||||
*/
|
||||
async $$eval<ReturnType extends any>(
|
||||
async $$eval<ReturnType>(
|
||||
selector: string,
|
||||
pageFunction: EvaluateFn | string,
|
||||
pageFunction: (
|
||||
elements: Element[],
|
||||
/* These have to be typed as unknown[] for the same reason as the $eval
|
||||
* definition above, please see that comment for more details and the TODO
|
||||
* that will improve things.
|
||||
*/
|
||||
...args: unknown[]
|
||||
) => ReturnType | Promise<ReturnType>,
|
||||
...args: SerializableOrJSHandle[]
|
||||
): Promise<ReturnType> {
|
||||
): Promise<WrapElementHandle<ReturnType>> {
|
||||
return this.mainFrame().$$eval<ReturnType>(selector, pageFunction, ...args);
|
||||
}
|
||||
|
||||
|
@ -218,7 +218,7 @@ describe('querySelector', function () {
|
||||
'<html><body><div class="tweet"><div class="like">100</div><div class="like">10</div></div></body></html>'
|
||||
);
|
||||
const tweet = await page.$('.tweet');
|
||||
const content = await tweet.$$eval('.like', (nodes) =>
|
||||
const content = await tweet.$$eval('.like', (nodes: HTMLElement[]) =>
|
||||
nodes.map((n) => n.innerText)
|
||||
);
|
||||
expect(content).toEqual(['100', '10']);
|
||||
@ -231,7 +231,7 @@ describe('querySelector', function () {
|
||||
'<div class="a">not-a-child-div</div><div id="myId"><div class="a">a1-child-div</div><div class="a">a2-child-div</div></div>';
|
||||
await page.setContent(htmlContent);
|
||||
const elementHandle = await page.$('#myId');
|
||||
const content = await elementHandle.$$eval('.a', (nodes) =>
|
||||
const content = await elementHandle.$$eval('.a', (nodes: HTMLElement[]) =>
|
||||
nodes.map((n) => n.innerText)
|
||||
);
|
||||
expect(content).toEqual(['a1-child-div', 'a2-child-div']);
|
||||
|
Loading…
Reference in New Issue
Block a user