fix: extends ElementHandle to Nodes (#8552)

* fix: extends `ElementHandle` to `Node`s (#8552)
This commit is contained in:
jrandolf 2022-07-06 09:05:37 +02:00 committed by GitHub
parent b49d530d73
commit 5ff205dc8b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
93 changed files with 597 additions and 1095 deletions

View File

@ -1,6 +1,39 @@
assets/
## [START] Keep in sync with .gitignore
# Dependencies
node_modules
# Production
build/
coverage/
lib
lib/
# Generated files
tsconfig.tsbuildinfo
puppeteer.api.json
puppeteer*.tgz
yarn.lock
.docusaurus/
.cache-loader
.local-chromium/
.local-firefox/
test/output-*/
.dev_profile*
coverage/
# IDE Artifacts
.vscode
# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
## [END] Keep in sync with .gitignore
# ESLint ignores.
assets/
vendor/

View File

@ -140,6 +140,8 @@ module.exports = {
'arrow-body-style': ['error', 'always'],
// Error if comments do not adhere to `tsdoc`.
'tsdoc/syntax': 2,
// Keeps array types simple only when they are simple for readability.
'@typescript-eslint/array-type': ['error', {default: 'array-simple'}],
'no-unused-vars': 0,
'@typescript-eslint/no-unused-vars': [
'error',

1
.gitignore vendored
View File

@ -16,6 +16,7 @@ yarn.lock
.local-firefox/
test/output-*/
.dev_profile*
coverage/
# IDE Artifacts
.vscode

View File

@ -1,5 +1,4 @@
# Keep in sync with .gitignore
## [START] Keep in sync with .gitignore
# Dependencies
node_modules
@ -18,6 +17,7 @@ yarn.lock
.local-firefox/
test/output-*/
.dev_profile*
coverage/
# IDE Artifacts
.vscode
@ -32,6 +32,7 @@ test/output-*/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
## [END] Keep in sync with .gitignore
# Prettier-only ignores.
assets/

View File

@ -155,6 +155,7 @@ sidebar_label: API
| [KeyInput](./puppeteer.keyinput.md) | All the valid keys that can be passed to functions that take user input, such as [keyboard.press](./puppeteer.keyboard.press.md) |
| [LowerCasePaperFormat](./puppeteer.lowercasepaperformat.md) | |
| [MouseButton](./puppeteer.mousebutton.md) | |
| [NodeFor](./puppeteer.nodefor.md) | |
| [PaperFormat](./puppeteer.paperformat.md) | All the valid paper format types when printing a PDF. |
| [Permission](./puppeteer.permission.md) | |
| [Platform](./puppeteer.platform.md) | Supported platforms. |

View File

@ -15,6 +15,6 @@ export interface CustomQueryHandler
## Properties
| Property | Modifiers | Type | Description |
| ------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------- | ----------------- |
| [queryAll?](./puppeteer.customqueryhandler.queryall.md) | | (element: Element \| Document, selector: string) =&gt; Element\[\] \| NodeListOf&lt;Element&gt; | <i>(Optional)</i> |
| [queryOne?](./puppeteer.customqueryhandler.queryone.md) | | (element: Element \| Document, selector: string) =&gt; Element \| null | <i>(Optional)</i> |
| ------------------------------------------------------- | --------- | ---------------------------------------------------- | ----------------- |
| [queryAll?](./puppeteer.customqueryhandler.queryall.md) | | (element: Node, selector: string) =&gt; Node\[\] | <i>(Optional)</i> |
| [queryOne?](./puppeteer.customqueryhandler.queryone.md) | | (element: Node, selector: string) =&gt; Node \| null | <i>(Optional)</i> |

View File

@ -8,9 +8,6 @@ sidebar_label: CustomQueryHandler.queryAll
```typescript
interface CustomQueryHandler {
queryAll?: (
element: Element | Document,
selector: string
) => Element[] | NodeListOf<Element>;
queryAll?: (element: Node, selector: string) => Node[];
}
```

View File

@ -8,6 +8,6 @@ sidebar_label: CustomQueryHandler.queryOne
```typescript
interface CustomQueryHandler {
queryOne?: (element: Element | Document, selector: string) => Element | null;
queryOne?: (element: Node, selector: string) => Node | null;
}
```

View File

@ -10,9 +10,9 @@ Runs `element.querySelector` within the page.
```typescript
class ElementHandle {
$<Selector extends keyof HTMLElementTagNameMap>(
$<Selector extends string>(
selector: Selector
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]> | null>;
): Promise<ElementHandle<NodeFor<Selector>> | null>;
}
```
@ -24,7 +24,7 @@ class ElementHandle {
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;HTMLElementTagNameMap\[Selector\]&gt; \| null&gt;
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;[NodeFor](./puppeteer.nodefor.md)&lt;Selector&gt;&gt; \| null&gt;
`null` if no element matches the selector.

View File

@ -10,9 +10,9 @@ Runs `element.querySelectorAll` within the page.
```typescript
class ElementHandle {
$$<Selector extends keyof HTMLElementTagNameMap>(
$$<Selector extends string>(
selector: Selector
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]>[]>;
): Promise<Array<ElementHandle<NodeFor<Selector>>>>;
}
```
@ -24,7 +24,7 @@ class ElementHandle {
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;HTMLElementTagNameMap\[Selector\]&gt;\[\]&gt;
Promise&lt;Array&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;[NodeFor](./puppeteer.nodefor.md)&lt;Selector&gt;&gt;&gt;&gt;
`[]` if no element matches the selector.

View File

@ -1,23 +0,0 @@
---
sidebar_label: ElementHandle.$_1
---
# ElementHandle.$() method
**Signature:**
```typescript
class ElementHandle {
$(selector: string): Promise<ElementHandle | null>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ------ | ----------- |
| selector | string | |
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md) \| null&gt;

View File

@ -1,23 +0,0 @@
---
sidebar_label: ElementHandle.$$_1
---
# ElementHandle.$$() method
**Signature:**
```typescript
class ElementHandle {
$$(selector: string): Promise<ElementHandle[]>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ------ | ----------- |
| selector | string | |
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)\[\]&gt;

View File

@ -13,11 +13,11 @@ If `pageFunction` returns a Promise, then `frame.$$eval` would wait for the prom
```typescript
class ElementHandle {
$$eval<
Selector extends keyof HTMLElementTagNameMap,
Selector extends string,
Params extends unknown[],
Func extends EvaluateFunc<
[HTMLElementTagNameMap[Selector][], ...Params]
> = EvaluateFunc<[HTMLElementTagNameMap[Selector][], ...Params]>
[Array<NodeFor<Selector>>, ...Params]
> = EvaluateFunc<[Array<NodeFor<Selector>>, ...Params]>
>(
selector: Selector,
pageFunction: Func | string,

View File

@ -1,34 +0,0 @@
---
sidebar_label: ElementHandle.$$eval_1
---
# ElementHandle.$$eval() method
**Signature:**
```typescript
class ElementHandle {
$$eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element[], ...Params]> = EvaluateFunc<
[Element[], ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
}
```
## Parameters
| Parameter | Type | Description |
| ------------ | -------------- | ----------- |
| selector | string | |
| pageFunction | Func \| string | |
| args | Params | |
**Returns:**
Promise&lt;Awaited&lt;ReturnType&lt;Func&gt;&gt;&gt;

View File

@ -13,11 +13,11 @@ If `pageFunction` returns a Promise, then `frame.$eval` would wait for the promi
```typescript
class ElementHandle {
$eval<
Selector extends keyof HTMLElementTagNameMap,
Selector extends string,
Params extends unknown[],
Func extends EvaluateFunc<
[HTMLElementTagNameMap[Selector], ...Params]
> = EvaluateFunc<[HTMLElementTagNameMap[Selector], ...Params]>
[ElementHandle<NodeFor<Selector>>, ...Params]
> = EvaluateFunc<[ElementHandle<NodeFor<Selector>>, ...Params]>
>(
selector: Selector,
pageFunction: Func | string,

View File

@ -1,34 +0,0 @@
---
sidebar_label: ElementHandle.$eval_1
---
# ElementHandle.$eval() method
**Signature:**
```typescript
class ElementHandle {
$eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element, ...Params]> = EvaluateFunc<
[Element, ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
}
```
## Parameters
| Parameter | Type | Description |
| ------------ | -------------- | ----------- |
| selector | string | |
| pageFunction | Func \| string | |
| args | Params | |
**Returns:**
Promise&lt;Awaited&lt;ReturnType&lt;Func&gt;&gt;&gt;

View File

@ -10,7 +10,7 @@ The method evaluates the XPath expression relative to the elementHandle. If ther
```typescript
class ElementHandle {
$x(expression: string): Promise<ElementHandle[]>;
$x(expression: string): Promise<Array<ElementHandle<Node>>>;
}
```
@ -22,4 +22,4 @@ class ElementHandle {
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)\[\]&gt;
Promise&lt;Array&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;Node&gt;&gt;&gt;

View File

@ -10,14 +10,15 @@ This method scrolls element into view if needed, and then uses [Page.mouse](./pu
```typescript
class ElementHandle {
click(options?: ClickOptions): Promise<void>;
click(this: ElementHandle<Element>, options?: ClickOptions): Promise<void>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ------------------------------------------- | ----------------- |
| --------- | ------------------------------------------------------------ | ----------------- |
| this | [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | |
| options | [ClickOptions](./puppeteer.clickoptions.md) | <i>(Optional)</i> |
**Returns:**

View File

@ -10,14 +10,18 @@ This method creates and captures a dragevent from the element.
```typescript
class ElementHandle {
drag(target: Point): Promise<Protocol.Input.DragData>;
drag(
this: ElementHandle<Element>,
target: Point
): Promise<Protocol.Input.DragData>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ----------------------------- | ----------- |
| --------- | ------------------------------------------------------------ | ----------- |
| this | [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | |
| target | [Point](./puppeteer.point.md) | |
**Returns:**

View File

@ -11,7 +11,8 @@ This method triggers a dragenter, dragover, and drop on the element.
```typescript
class ElementHandle {
dragAndDrop(
target: ElementHandle,
this: ElementHandle<Element>,
target: ElementHandle<Node>,
options?: {
delay: number;
}
@ -22,8 +23,9 @@ class ElementHandle {
## Parameters
| Parameter | Type | Description |
| --------- | --------------------------------------------- | ----------------- |
| target | [ElementHandle](./puppeteer.elementhandle.md) | |
| --------- | ------------------------------------------------------------ | ----------------- |
| this | [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | |
| target | [ElementHandle](./puppeteer.elementhandle.md)&lt;Node&gt; | |
| options | { delay: number; } | <i>(Optional)</i> |
**Returns:**

View File

@ -10,14 +10,18 @@ This method creates a `dragenter` event on the element.
```typescript
class ElementHandle {
dragEnter(data?: Protocol.Input.DragData): Promise<void>;
dragEnter(
this: ElementHandle<Element>,
data?: Protocol.Input.DragData
): Promise<void>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ----------------------- | ----------------- |
| --------- | ------------------------------------------------------------ | ----------------- |
| this | [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | |
| data | Protocol.Input.DragData | <i>(Optional)</i> |
**Returns:**

View File

@ -10,14 +10,18 @@ This method creates a `dragover` event on the element.
```typescript
class ElementHandle {
dragOver(data?: Protocol.Input.DragData): Promise<void>;
dragOver(
this: ElementHandle<Element>,
data?: Protocol.Input.DragData
): Promise<void>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ----------------------- | ----------------- |
| --------- | ------------------------------------------------------------ | ----------------- |
| this | [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | |
| data | Protocol.Input.DragData | <i>(Optional)</i> |
**Returns:**

View File

@ -10,14 +10,18 @@ This method triggers a drop on the element.
```typescript
class ElementHandle {
drop(data?: Protocol.Input.DragData): Promise<void>;
drop(
this: ElementHandle<Element>,
data?: Protocol.Input.DragData
): Promise<void>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ----------------------- | ----------------- |
| --------- | ------------------------------------------------------------ | ----------------- |
| this | [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | |
| data | Protocol.Input.DragData | <i>(Optional)</i> |
**Returns:**

View File

@ -10,10 +10,16 @@ This method scrolls element into view if needed, and then uses [Page.mouse](./pu
```typescript
class ElementHandle {
hover(): Promise<void>;
hover(this: ElementHandle<Element>): Promise<void>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ------------------------------------------------------------ | ----------- |
| this | [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | |
**Returns:**
Promise&lt;void&gt;

View File

@ -10,14 +10,20 @@ Resolves to true if the element is visible in the current viewport.
```typescript
class ElementHandle {
isIntersectingViewport(options?: {threshold?: number}): Promise<boolean>;
isIntersectingViewport(
this: ElementHandle<Element>,
options?: {
threshold?: number;
}
): Promise<boolean>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ----------------------- | ----------------- |
| --------- | ------------------------------------------------------------ | ----------------- |
| this | [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | |
| options | { threshold?: number; } | <i>(Optional)</i> |
**Returns:**

View File

@ -9,14 +9,14 @@ ElementHandle represents an in-page DOM element.
**Signature:**
```typescript
export declare class ElementHandle<ElementType extends Element = Element> extends JSHandle<ElementType>
export declare class ElementHandle<ElementType extends Node = Element> extends JSHandle<ElementType>
```
**Extends:** [JSHandle](./puppeteer.jshandle.md)
## Remarks
ElementHandles can be created with the method.
ElementHandles can be created with the [Page.$()](./puppeteer.page._.md) method.
```ts
const puppeteer = require('puppeteer');
@ -33,7 +33,7 @@ const puppeteer = require('puppeteer');
ElementHandle prevents the DOM element from being garbage-collected unless the handle is [disposed](./puppeteer.jshandle.dispose.md). ElementHandles are auto-disposed when their origin frame gets navigated.
ElementHandle instances can be used as arguments in and [Page.evaluate()](./puppeteer.page.evaluate.md) methods.
ElementHandle instances can be used as arguments in [Page.$eval()](./puppeteer.page._eval.md) and [Page.evaluate()](./puppeteer.page.evaluate.md) methods.
If you're using TypeScript, ElementHandle takes a generic argument that denotes the type of element the handle is holding within. For example, if you have a handle to a `<select>` element, you can type it as `ElementHandle<HTMLSelectElement>` and you get some nicer type checks.
@ -42,38 +42,33 @@ The constructor for this class is marked as internal. Third-party code should no
## Methods
| Method | Modifiers | Description |
| -------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| -------------------------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [$(selector)](./puppeteer.elementhandle._.md) | | Runs <code>element.querySelector</code> within the page. |
| [$(selector)](./puppeteer.elementhandle.__1.md) | | |
| [$$(selector)](./puppeteer.elementhandle.__.md) | | Runs <code>element.querySelectorAll</code> within the page. |
| [$$(selector)](./puppeteer.elementhandle.___1.md) | | |
| [$$eval(selector, pageFunction, args)](./puppeteer.elementhandle.__eval.md) | | <p>This method runs <code>document.querySelectorAll</code> within the element and passes it as the first argument to <code>pageFunction</code>. If there's no element matching <code>selector</code>, the method throws an error.</p><p>If <code>pageFunction</code> returns a Promise, then <code>frame.$$eval</code> would wait for the promise to resolve and return its value.</p> |
| [$$eval(selector, pageFunction, args)](./puppeteer.elementhandle.__eval_1.md) | | |
| [$eval(selector, pageFunction, args)](./puppeteer.elementhandle._eval.md) | | <p>This method runs <code>document.querySelector</code> within the element and passes it as the first argument to <code>pageFunction</code>. If there's no element matching <code>selector</code>, the method throws an error.</p><p>If <code>pageFunction</code> returns a Promise, then <code>frame.$eval</code> would wait for the promise to resolve and return its value.</p> |
| [$eval(selector, pageFunction, args)](./puppeteer.elementhandle._eval_1.md) | | |
| [$x(expression)](./puppeteer.elementhandle._x.md) | | The method evaluates the XPath expression relative to the elementHandle. If there are no such elements, the method will resolve to an empty array. |
| [asElement()](./puppeteer.elementhandle.aselement.md) | | |
| [boundingBox()](./puppeteer.elementhandle.boundingbox.md) | | This method returns the bounding box of the element (relative to the main frame), or <code>null</code> if the element is not visible. |
| [boxModel()](./puppeteer.elementhandle.boxmodel.md) | | This method returns boxes of the element, or <code>null</code> if the element is not visible. |
| [click(options)](./puppeteer.elementhandle.click.md) | | This method scrolls element into view if needed, and then uses [Page.mouse](./puppeteer.page.mouse.md) to click in the center of the element. If the element is detached from DOM, the method throws an error. |
| [click(this, options)](./puppeteer.elementhandle.click.md) | | This method scrolls element into view if needed, and then uses [Page.mouse](./puppeteer.page.mouse.md) to click in the center of the element. If the element is detached from DOM, the method throws an error. |
| [clickablePoint(offset)](./puppeteer.elementhandle.clickablepoint.md) | | Returns the middle point within an element unless a specific offset is provided. |
| [contentFrame()](./puppeteer.elementhandle.contentframe.md) | | Resolves to the content frame for element handles referencing iframe nodes, or null otherwise |
| [drag(target)](./puppeteer.elementhandle.drag.md) | | This method creates and captures a dragevent from the element. |
| [dragAndDrop(target, options)](./puppeteer.elementhandle.draganddrop.md) | | This method triggers a dragenter, dragover, and drop on the element. |
| [dragEnter(data)](./puppeteer.elementhandle.dragenter.md) | | This method creates a <code>dragenter</code> event on the element. |
| [dragOver(data)](./puppeteer.elementhandle.dragover.md) | | This method creates a <code>dragover</code> event on the element. |
| [drop(data)](./puppeteer.elementhandle.drop.md) | | This method triggers a drop on the element. |
| [drag(this, target)](./puppeteer.elementhandle.drag.md) | | This method creates and captures a dragevent from the element. |
| [dragAndDrop(this, target, options)](./puppeteer.elementhandle.draganddrop.md) | | This method triggers a dragenter, dragover, and drop on the element. |
| [dragEnter(this, data)](./puppeteer.elementhandle.dragenter.md) | | This method creates a <code>dragenter</code> event on the element. |
| [dragOver(this, data)](./puppeteer.elementhandle.dragover.md) | | This method creates a <code>dragover</code> event on the element. |
| [drop(this, data)](./puppeteer.elementhandle.drop.md) | | This method triggers a drop on the element. |
| [focus()](./puppeteer.elementhandle.focus.md) | | Calls [focus](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus) on the element. |
| [hover()](./puppeteer.elementhandle.hover.md) | | This method scrolls element into view if needed, and then uses [Page.mouse](./puppeteer.page.mouse.md) to hover over the center of the element. If the element is detached from DOM, the method throws an error. |
| [isIntersectingViewport(options)](./puppeteer.elementhandle.isintersectingviewport.md) | | Resolves to true if the element is visible in the current viewport. |
| [hover(this)](./puppeteer.elementhandle.hover.md) | | This method scrolls element into view if needed, and then uses [Page.mouse](./puppeteer.page.mouse.md) to hover over the center of the element. If the element is detached from DOM, the method throws an error. |
| [isIntersectingViewport(this, options)](./puppeteer.elementhandle.isintersectingviewport.md) | | Resolves to true if the element is visible in the current viewport. |
| [press(key, options)](./puppeteer.elementhandle.press.md) | | Focuses the element, and then uses [Keyboard.down()](./puppeteer.keyboard.down.md) and [Keyboard.up()](./puppeteer.keyboard.up.md). |
| [screenshot(options)](./puppeteer.elementhandle.screenshot.md) | | This method scrolls element into view if needed, and then uses [Page.screenshot()](./puppeteer.page.screenshot.md) to take a screenshot of the element. If the element is detached from DOM, the method throws an error. |
| [screenshot(this, options)](./puppeteer.elementhandle.screenshot.md) | | This method scrolls element into view if needed, and then uses [Page.screenshot()](./puppeteer.page.screenshot.md) to take a screenshot of the element. If the element is detached from DOM, the method throws an error. |
| [select(values)](./puppeteer.elementhandle.select.md) | | Triggers a <code>change</code> and <code>input</code> event once all the provided options have been selected. If there's no <code>&lt;select&gt;</code> element matching <code>selector</code>, the method throws an error. |
| [tap()](./puppeteer.elementhandle.tap.md) | | This method scrolls element into view if needed, and then uses [Touchscreen.tap()](./puppeteer.touchscreen.tap.md) to tap in the center of the element. If the element is detached from DOM, the method throws an error. |
| [tap(this)](./puppeteer.elementhandle.tap.md) | | This method scrolls element into view if needed, and then uses [Touchscreen.tap()](./puppeteer.touchscreen.tap.md) to tap in the center of the element. If the element is detached from DOM, the method throws an error. |
| [type(text, options)](./puppeteer.elementhandle.type.md) | | <p>Focuses the element, and then sends a <code>keydown</code>, <code>keypress</code>/<code>input</code>, and <code>keyup</code> event for each character in the text.</p><p>To press a special key, like <code>Control</code> or <code>ArrowDown</code>, use [ElementHandle.press()](./puppeteer.elementhandle.press.md).</p> |
| [uploadFile(this, filePaths)](./puppeteer.elementhandle.uploadfile.md) | | This method expects <code>elementHandle</code> to point to an [input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). |
| [waitForSelector(selector, options)](./puppeteer.elementhandle.waitforselector.md) | | <p>Wait for the <code>selector</code> to appear within the element. If at the moment of calling the method the <code>selector</code> already exists, the method will return immediately. If the <code>selector</code> doesn't appear after the <code>timeout</code> milliseconds of waiting, the function will throw.</p><p>This method does not work across navigations or if the element is detached from DOM.</p> |
| [waitForSelector(selector, options)](./puppeteer.elementhandle.waitforselector_1.md) | | |
| [waitForXPath(xpath, options)](./puppeteer.elementhandle.waitforxpath.md) | | <p>Wait for the <code>xpath</code> within the element. If at the moment of calling the method the <code>xpath</code> already exists, the method will return immediately. If the <code>xpath</code> doesn't appear after the <code>timeout</code> milliseconds of waiting, the function will throw.</p><p>If <code>xpath</code> starts with <code>//</code> instead of <code>.//</code>, the dot will be appended automatically.</p><p>This method works across navigation</p> |
```ts

View File

@ -10,14 +10,18 @@ This method scrolls element into view if needed, and then uses [Page.screenshot(
```typescript
class ElementHandle {
screenshot(options?: ScreenshotOptions): Promise<string | Buffer>;
screenshot(
this: ElementHandle<Element>,
options?: ScreenshotOptions
): Promise<string | Buffer>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ----------------------------------------------------- | ----------------- |
| --------- | ------------------------------------------------------------ | ----------------- |
| this | [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | |
| options | [ScreenshotOptions](./puppeteer.screenshotoptions.md) | <i>(Optional)</i> |
**Returns:**

View File

@ -10,10 +10,16 @@ This method scrolls element into view if needed, and then uses [Touchscreen.tap(
```typescript
class ElementHandle {
tap(): Promise<void>;
tap(this: ElementHandle<Element>): Promise<void>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ------------------------------------------------------------ | ----------- |
| this | [ElementHandle](./puppeteer.elementhandle.md)&lt;Element&gt; | |
**Returns:**
Promise&lt;void&gt;

View File

@ -12,10 +12,10 @@ This method does not work across navigations or if the element is detached from
```typescript
class ElementHandle {
waitForSelector<Selector extends keyof HTMLElementTagNameMap>(
waitForSelector<Selector extends string>(
selector: Selector,
options?: Exclude<WaitForSelectorOptions, 'root'>
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]> | null>;
): Promise<ElementHandle<NodeFor<Selector>> | null>;
}
```
@ -28,7 +28,7 @@ class ElementHandle {
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;HTMLElementTagNameMap\[Selector\]&gt; \| null&gt;
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;[NodeFor](./puppeteer.nodefor.md)&lt;Selector&gt;&gt; \| null&gt;
Promise which resolves when element specified by selector string is added to DOM. Resolves to `null` if waiting for hidden: `true` and selector is not found in DOM.

View File

@ -1,27 +0,0 @@
---
sidebar_label: ElementHandle.waitForSelector_1
---
# ElementHandle.waitForSelector() method
**Signature:**
```typescript
class ElementHandle {
waitForSelector(
selector: string,
options?: Exclude<WaitForSelectorOptions, 'root'>
): Promise<ElementHandle | null>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | -------------------------------------------------------------------------------------- | ----------------- |
| selector | string | |
| options | Exclude&lt;[WaitForSelectorOptions](./puppeteer.waitforselectoroptions.md), 'root'&gt; | <i>(Optional)</i> |
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md) \| null&gt;

View File

@ -41,7 +41,7 @@ class ElementHandle {
hidden?: boolean;
timeout?: number;
}
): Promise<ElementHandle | null>;
): Promise<ElementHandle<Node> | null>;
}
```
@ -54,7 +54,7 @@ class ElementHandle {
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md) \| null&gt;
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;Node&gt; \| null&gt;
Promise which resolves when element specified by xpath string is added to DOM. Resolves to `null` if waiting for `hidden: true` and xpath is not found in DOM.

View File

@ -10,9 +10,9 @@ This method queries the frame for the given selector.
```typescript
class Frame {
$<Selector extends keyof HTMLElementTagNameMap>(
$<Selector extends string>(
selector: Selector
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]> | null>;
): Promise<ElementHandle<NodeFor<Selector>> | null>;
}
```
@ -24,6 +24,6 @@ class Frame {
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;HTMLElementTagNameMap\[Selector\]&gt; \| null&gt;
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;[NodeFor](./puppeteer.nodefor.md)&lt;Selector&gt;&gt; \| null&gt;
A promise which resolves to an `ElementHandle` pointing at the element, or `null` if it was not found.

View File

@ -10,9 +10,9 @@ This runs `document.querySelectorAll` in the frame and returns the result.
```typescript
class Frame {
$$<Selector extends keyof HTMLElementTagNameMap>(
$$<Selector extends string>(
selector: Selector
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]>[]>;
): Promise<Array<ElementHandle<NodeFor<Selector>>>>;
}
```
@ -24,6 +24,6 @@ class Frame {
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;HTMLElementTagNameMap\[Selector\]&gt;\[\]&gt;
Promise&lt;Array&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;[NodeFor](./puppeteer.nodefor.md)&lt;Selector&gt;&gt;&gt;&gt;
An array of element handles pointing to the found frame elements.

View File

@ -1,23 +0,0 @@
---
sidebar_label: Frame.$_1
---
# Frame.$() method
**Signature:**
```typescript
class Frame {
$(selector: string): Promise<ElementHandle | null>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ------ | ----------- |
| selector | string | |
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md) \| null&gt;

View File

@ -1,23 +0,0 @@
---
sidebar_label: Frame.$$_1
---
# Frame.$$() method
**Signature:**
```typescript
class Frame {
$$(selector: string): Promise<ElementHandle[]>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ------ | ----------- |
| selector | string | |
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)\[\]&gt;

View File

@ -9,11 +9,11 @@ sidebar_label: Frame.$$eval
```typescript
class Frame {
$$eval<
Selector extends keyof HTMLElementTagNameMap,
Selector extends string,
Params extends unknown[],
Func extends EvaluateFunc<
[HTMLElementTagNameMap[Selector][], ...Params]
> = EvaluateFunc<[HTMLElementTagNameMap[Selector][], ...Params]>
[Array<NodeFor<Selector>>, ...Params]
> = EvaluateFunc<[Array<NodeFor<Selector>>, ...Params]>
>(
selector: Selector,
pageFunction: Func | string,

View File

@ -1,34 +0,0 @@
---
sidebar_label: Frame.$$eval_1
---
# Frame.$$eval() method
**Signature:**
```typescript
class Frame {
$$eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element[], ...Params]> = EvaluateFunc<
[Element[], ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
}
```
## Parameters
| Parameter | Type | Description |
| ------------ | -------------- | ----------- |
| selector | string | |
| pageFunction | Func \| string | |
| args | Params | |
**Returns:**
Promise&lt;Awaited&lt;ReturnType&lt;Func&gt;&gt;&gt;

View File

@ -9,11 +9,11 @@ sidebar_label: Frame.$eval
```typescript
class Frame {
$eval<
Selector extends keyof HTMLElementTagNameMap,
Selector extends string,
Params extends unknown[],
Func extends EvaluateFunc<
[HTMLElementTagNameMap[Selector], ...Params]
> = EvaluateFunc<[HTMLElementTagNameMap[Selector], ...Params]>
[ElementHandle<NodeFor<Selector>>, ...Params]
> = EvaluateFunc<[ElementHandle<NodeFor<Selector>>, ...Params]>
>(
selector: Selector,
pageFunction: Func | string,

View File

@ -1,34 +0,0 @@
---
sidebar_label: Frame.$eval_1
---
# Frame.$eval() method
**Signature:**
```typescript
class Frame {
$eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element, ...Params]> = EvaluateFunc<
[Element, ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
}
```
## Parameters
| Parameter | Type | Description |
| ------------ | -------------- | ----------- |
| selector | string | |
| pageFunction | Func \| string | |
| args | Params | |
**Returns:**
Promise&lt;Awaited&lt;ReturnType&lt;Func&gt;&gt;&gt;

View File

@ -10,7 +10,7 @@ This method evaluates the given XPath expression and returns the results.
```typescript
class Frame {
$x(expression: string): Promise<ElementHandle[]>;
$x(expression: string): Promise<Array<ElementHandle<Node>>>;
}
```
@ -22,4 +22,4 @@ class Frame {
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)\[\]&gt;
Promise&lt;Array&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;Node&gt;&gt;&gt;

View File

@ -10,7 +10,9 @@ Adds a `<script>` tag into the page with the desired url or content.
```typescript
class Frame {
addScriptTag(options: FrameAddScriptTagOptions): Promise<ElementHandle>;
addScriptTag(
options: FrameAddScriptTagOptions
): Promise<ElementHandle<HTMLScriptElement>>;
}
```
@ -22,6 +24,6 @@ class Frame {
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&gt;
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;HTMLScriptElement&gt;&gt;
a promise that resolves to the added tag when the script's `onload` event fires or when the script content was injected into the frame.

View File

@ -10,7 +10,7 @@ Adds a `<link rel="stylesheet">` tag into the page with the desired url or a `<s
```typescript
class Frame {
addStyleTag(options: FrameAddStyleTagOptions): Promise<ElementHandle>;
addStyleTag(options: FrameAddStyleTagOptions): Promise<ElementHandle<Node>>;
}
```
@ -22,6 +22,6 @@ class Frame {
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&gt;
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;Node&gt;&gt;
a promise that resolves to the added tag when the stylesheets's `onload` event fires or when the CSS content was injected into the frame.

View File

@ -62,13 +62,9 @@ console.log(text);
| Method | Modifiers | Description |
| ------------------------------------------------------------------------------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [$(selector)](./puppeteer.frame._.md) | | This method queries the frame for the given selector. |
| [$(selector)](./puppeteer.frame.__1.md) | | |
| [$$(selector)](./puppeteer.frame.__.md) | | This runs <code>document.querySelectorAll</code> in the frame and returns the result. |
| [$$(selector)](./puppeteer.frame.___1.md) | | |
| [$$eval(selector, pageFunction, args)](./puppeteer.frame.__eval.md) | | |
| [$$eval(selector, pageFunction, args)](./puppeteer.frame.__eval_1.md) | | |
| [$eval(selector, pageFunction, args)](./puppeteer.frame._eval.md) | | |
| [$eval(selector, pageFunction, args)](./puppeteer.frame._eval_1.md) | | |
| [$x(expression)](./puppeteer.frame._x.md) | | This method evaluates the given XPath expression and returns the results. |
| [addScriptTag(options)](./puppeteer.frame.addscripttag.md) | | Adds a <code>&lt;script&gt;</code> tag into the page with the desired url or content. |
| [addStyleTag(options)](./puppeteer.frame.addstyletag.md) | | Adds a <code>&lt;link rel=&quot;stylesheet&quot;&gt;</code> tag into the page with the desired url or a <code>&lt;style type=&quot;text/css&quot;&gt;</code> tag with the content. |
@ -94,6 +90,5 @@ console.log(text);
| [waitForFunction(pageFunction, options, args)](./puppeteer.frame.waitforfunction.md) | | |
| [waitForNavigation(options)](./puppeteer.frame.waitfornavigation.md) | | |
| [waitForSelector(selector, options)](./puppeteer.frame.waitforselector.md) | | |
| [waitForSelector(selector, options)](./puppeteer.frame.waitforselector_1.md) | | |
| [waitForTimeout(milliseconds)](./puppeteer.frame.waitfortimeout.md) | | Causes your script to wait for the given number of milliseconds. |
| [waitForXPath(xpath, options)](./puppeteer.frame.waitforxpath.md) | | |

View File

@ -8,10 +8,10 @@ sidebar_label: Frame.waitForSelector
```typescript
class Frame {
waitForSelector<Selector extends keyof HTMLElementTagNameMap>(
waitForSelector<Selector extends string>(
selector: Selector,
options?: WaitForSelectorOptions
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]> | null>;
): Promise<ElementHandle<NodeFor<Selector>> | null>;
}
```
@ -24,7 +24,7 @@ class Frame {
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;HTMLElementTagNameMap\[Selector\]&gt; \| null&gt;
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;[NodeFor](./puppeteer.nodefor.md)&lt;Selector&gt;&gt; \| null&gt;
a promise which resolves when an element matching the selector string is added to the DOM.

View File

@ -1,27 +0,0 @@
---
sidebar_label: Frame.waitForSelector_1
---
# Frame.waitForSelector() method
**Signature:**
```typescript
class Frame {
waitForSelector(
selector: string,
options?: WaitForSelectorOptions
): Promise<ElementHandle | null>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | --------------------------------------------------------------- | ----------------- |
| selector | string | |
| options | [WaitForSelectorOptions](./puppeteer.waitforselectoroptions.md) | <i>(Optional)</i> |
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md) \| null&gt;

View File

@ -26,7 +26,7 @@ Promise&lt;void&gt;
## Remarks
It's generally recommended to not wait for a number of seconds, but instead use , [Frame.waitForXPath()](./puppeteer.frame.waitforxpath.md) or [Frame.waitForFunction()](./puppeteer.frame.waitforfunction.md) to wait for exactly the conditions you want.
It's generally recommended to not wait for a number of seconds, but instead use [Frame.waitForSelector()](./puppeteer.frame.waitforselector.md), [Frame.waitForXPath()](./puppeteer.frame.waitforxpath.md) or [Frame.waitForFunction()](./puppeteer.frame.waitforfunction.md) to wait for exactly the conditions you want.
## Example

View File

@ -11,7 +11,7 @@ class Frame {
waitForXPath(
xpath: string,
options?: WaitForSelectorOptions
): Promise<ElementHandle | null>;
): Promise<ElementHandle<Node> | null>;
}
```
@ -24,10 +24,10 @@ class Frame {
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md) \| null&gt;
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;Node&gt; \| null&gt;
## Remarks
Wait for the `xpath` to appear in page. If at the moment of calling the method the `xpath` already exists, the method will return immediately. If the xpath doesn't appear after the `timeout` milliseconds of waiting, the function will throw.
For a code example, see the example for . That function behaves identically other than taking a CSS selector rather than an XPath.
For a code example, see the example for [Frame.waitForSelector()](./puppeteer.frame.waitforselector.md). That function behaves identically other than taking a CSS selector rather than an XPath.

View File

@ -7,7 +7,7 @@ sidebar_label: HandleFor
**Signature:**
```typescript
export declare type HandleFor<T> = T extends Element
export declare type HandleFor<T> = T extends Node
? ElementHandle<T>
: JSHandle<T>;
```

View File

@ -0,0 +1,15 @@
---
sidebar_label: JSHandle.[__JSHandleSymbol]
---
# JSHandle.\[\_\_JSHandleSymbol\] property
Used for nominally typing [JSHandle](./puppeteer.jshandle.md).
**Signature:**
```typescript
class JSHandle {
[__JSHandleSymbol]?: T;
}
```

View File

@ -8,12 +8,12 @@ sidebar_label: JSHandle.asElement
```typescript
class JSHandle {
asElement(): ElementHandle | null;
asElement(): ElementHandle<Node> | null;
}
```
**Returns:**
[ElementHandle](./puppeteer.elementhandle.md) \| null
[ElementHandle](./puppeteer.elementhandle.md)&lt;Node&gt; \| null
Either `null` or the object handle itself, if the object handle is an instance of [ElementHandle](./puppeteer.elementhandle.md).

View File

@ -24,7 +24,13 @@ const windowHandle = await page.evaluateHandle(() => window);
JSHandle prevents the referenced JavaScript object from being garbage-collected unless the handle is [disposed](./puppeteer.jshandle.dispose.md). JSHandles are auto- disposed when their origin frame gets navigated or the parent context gets destroyed.
JSHandle instances can be used as arguments for , [Page.evaluate()](./puppeteer.page.evaluate.md), and [Page.evaluateHandle()](./puppeteer.page.evaluatehandle.md).
JSHandle instances can be used as arguments for [Page.$eval()](./puppeteer.page._eval.md), [Page.evaluate()](./puppeteer.page.evaluate.md), and [Page.evaluateHandle()](./puppeteer.page.evaluatehandle.md).
## Properties
| Property | Modifiers | Type | Description |
| --------------------------------------------------------------------- | --------- | ---- | -------------------------------------------------------------------------------- |
| [\[\_\_JSHandleSymbol\]?](./puppeteer.jshandle.___jshandlesymbol_.md) | | T | <i>(Optional)</i> Used for nominally typing [JSHandle](./puppeteer.jshandle.md). |
## Methods

View File

@ -0,0 +1,16 @@
---
sidebar_label: NodeFor
---
# NodeFor type
**Signature:**
```typescript
export declare type NodeFor<Selector extends string> =
Selector extends keyof HTMLElementTagNameMap
? HTMLElementTagNameMap[Selector]
: Selector extends keyof SVGElementTagNameMap
? SVGElementTagNameMap[Selector]
: Element;
```

View File

@ -10,9 +10,9 @@ Runs `document.querySelector` within the page. If no element matches the selecto
```typescript
class Page {
$<Selector extends keyof HTMLElementTagNameMap>(
$<Selector extends string>(
selector: Selector
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]> | null>;
): Promise<ElementHandle<NodeFor<Selector>> | null>;
}
```
@ -24,4 +24,4 @@ class Page {
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;HTMLElementTagNameMap\[Selector\]&gt; \| null&gt;
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;[NodeFor](./puppeteer.nodefor.md)&lt;Selector&gt;&gt; \| null&gt;

View File

@ -10,9 +10,9 @@ The method runs `document.querySelectorAll` within the page. If no elements matc
```typescript
class Page {
$$<Selector extends keyof HTMLElementTagNameMap>(
$$<Selector extends string>(
selector: Selector
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]>[]>;
): Promise<Array<ElementHandle<NodeFor<Selector>>>>;
}
```
@ -24,8 +24,8 @@ class Page {
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;HTMLElementTagNameMap\[Selector\]&gt;\[\]&gt;
Promise&lt;Array&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;[NodeFor](./puppeteer.nodefor.md)&lt;Selector&gt;&gt;&gt;&gt;
## Remarks
Shortcut for .
Shortcut for [Page.mainFrame().$$(selector)](./puppeteer.frame.__.md).

View File

@ -1,23 +0,0 @@
---
sidebar_label: Page.$_1
---
# Page.$() method
**Signature:**
```typescript
class Page {
$(selector: string): Promise<ElementHandle | null>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ------ | ----------- |
| selector | string | |
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md) \| null&gt;

View File

@ -1,23 +0,0 @@
---
sidebar_label: Page.$$_1
---
# Page.$$() method
**Signature:**
```typescript
class Page {
$$(selector: string): Promise<ElementHandle[]>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | ------ | ----------- |
| selector | string | |
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)\[\]&gt;

View File

@ -11,11 +11,11 @@ This method runs `Array.from(document.querySelectorAll(selector))` within the pa
```typescript
class Page {
$$eval<
Selector extends keyof HTMLElementTagNameMap,
Selector extends string,
Params extends unknown[],
Func extends EvaluateFunc<
[HTMLElementTagNameMap[Selector][], ...Params]
> = EvaluateFunc<[HTMLElementTagNameMap[Selector][], ...Params]>
[Array<NodeFor<Selector>>, ...Params]
> = EvaluateFunc<[Array<NodeFor<Selector>>, ...Params]>
>(
selector: Selector,
pageFunction: Func | string,

View File

@ -1,34 +0,0 @@
---
sidebar_label: Page.$$eval_1
---
# Page.$$eval() method
**Signature:**
```typescript
class Page {
$$eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element[], ...Params]> = EvaluateFunc<
[Element[], ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
}
```
## Parameters
| Parameter | Type | Description |
| ------------ | -------------- | ----------- |
| selector | string | |
| pageFunction | Func \| string | |
| args | Params | |
**Returns:**
Promise&lt;Awaited&lt;ReturnType&lt;Func&gt;&gt;&gt;

View File

@ -11,11 +11,11 @@ This method runs `document.querySelector` within the page and passes the result
```typescript
class Page {
$eval<
Selector extends keyof HTMLElementTagNameMap,
Selector extends string,
Params extends unknown[],
Func extends EvaluateFunc<
[HTMLElementTagNameMap[Selector], ...Params]
> = EvaluateFunc<[HTMLElementTagNameMap[Selector], ...Params]>
[ElementHandle<NodeFor<Selector>>, ...Params]
> = EvaluateFunc<[ElementHandle<NodeFor<Selector>>, ...Params]>
>(
selector: Selector,
pageFunction: Func | string,

View File

@ -1,34 +0,0 @@
---
sidebar_label: Page.$eval_1
---
# Page.$eval() method
**Signature:**
```typescript
class Page {
$eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element, ...Params]> = EvaluateFunc<
[Element, ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
}
```
## Parameters
| Parameter | Type | Description |
| ------------ | -------------- | ----------- |
| selector | string | |
| pageFunction | Func \| string | |
| args | Params | |
**Returns:**
Promise&lt;Awaited&lt;ReturnType&lt;Func&gt;&gt;&gt;

View File

@ -10,7 +10,7 @@ The method evaluates the XPath expression relative to the page document as its c
```typescript
class Page {
$x(expression: string): Promise<ElementHandle[]>;
$x(expression: string): Promise<Array<ElementHandle<Node>>>;
}
```
@ -22,7 +22,7 @@ class Page {
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)\[\]&gt;
Promise&lt;Array&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;Node&gt;&gt;&gt;
## Remarks

View File

@ -16,7 +16,7 @@ class Page {
content?: string;
type?: string;
id?: string;
}): Promise<ElementHandle>;
}): Promise<ElementHandle<HTMLScriptElement>>;
}
```
@ -28,7 +28,7 @@ class Page {
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&gt;
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;HTMLScriptElement&gt;&gt;
Promise which resolves to the added tag when the script's onload fires or when the script content was injected into frame.

View File

@ -14,7 +14,7 @@ class Page {
url?: string;
path?: string;
content?: string;
}): Promise<ElementHandle>;
}): Promise<ElementHandle<Node>>;
}
```
@ -26,6 +26,6 @@ class Page {
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&gt;
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;Node&gt;&gt;
Promise which resolves to the added tag when the stylesheet's onload fires or when the CSS content was injected into frame.

View File

@ -77,13 +77,9 @@ page.off('request', logRequest);
| Method | Modifiers | Description |
| ------------------------------------------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [$(selector)](./puppeteer.page._.md) | | Runs <code>document.querySelector</code> within the page. If no element matches the selector, the return value resolves to <code>null</code>. |
| [$(selector)](./puppeteer.page.__1.md) | | |
| [$$(selector)](./puppeteer.page.__.md) | | The method runs <code>document.querySelectorAll</code> within the page. If no elements match the selector, the return value resolves to <code>[]</code>. |
| [$$(selector)](./puppeteer.page.___1.md) | | |
| [$$eval(selector, pageFunction, args)](./puppeteer.page.__eval.md) | | This method runs <code>Array.from(document.querySelectorAll(selector))</code> within the page and passes the result as the first argument to the <code>pageFunction</code>. |
| [$$eval(selector, pageFunction, args)](./puppeteer.page.__eval_1.md) | | |
| [$eval(selector, pageFunction, args)](./puppeteer.page._eval.md) | | This method runs <code>document.querySelector</code> within the page and passes the result as the first argument to the <code>pageFunction</code>. |
| [$eval(selector, pageFunction, args)](./puppeteer.page._eval_1.md) | | |
| [$x(expression)](./puppeteer.page._x.md) | | The method evaluates the XPath expression relative to the page document as its context node. If there are no such elements, the method resolves to an empty array. |
| [addScriptTag(options)](./puppeteer.page.addscripttag.md) | | Adds a <code>&lt;script&gt;</code> tag into the page with the desired URL or content. |
| [addStyleTag(options)](./puppeteer.page.addstyletag.md) | | Adds a <code>&lt;link rel=&quot;stylesheet&quot;&gt;</code> tag into the page with the desired URL or a <code>&lt;style type=&quot;text/css&quot;&gt;</code> tag with the content. |
@ -178,7 +174,6 @@ const puppeteer = require('puppeteer');
```
|
| [waitForSelector(selector, options)](./puppeteer.page.waitforselector_1.md) | | |
| [waitForTimeout(milliseconds)](./puppeteer.page.waitfortimeout.md) | | Causes your script to wait for the given number of milliseconds. |
| [waitForXPath(xpath, options)](./puppeteer.page.waitforxpath.md) | | <p>Wait for the <code>xpath</code> to appear in page. If at the moment of calling the method the <code>xpath</code> already exists, the method will return immediately. If the <code>xpath</code> doesn't appear after the <code>timeout</code> milliseconds of waiting, the function will throw.</p><p>This method works across navigation</p>

View File

@ -32,10 +32,10 @@ const puppeteer = require('puppeteer');
```typescript
class Page {
waitForSelector<Selector extends keyof HTMLElementTagNameMap>(
waitForSelector<Selector extends string>(
selector: Selector,
options?: Exclude<WaitForSelectorOptions, 'root'>
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]> | null>;
): Promise<ElementHandle<NodeFor<Selector>> | null>;
}
```
@ -48,7 +48,7 @@ class Page {
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;HTMLElementTagNameMap\[Selector\]&gt; \| null&gt;
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;[NodeFor](./puppeteer.nodefor.md)&lt;Selector&gt;&gt; \| null&gt;
Promise which resolves when element specified by selector string is added to DOM. Resolves to `null` if waiting for hidden: `true` and selector is not found in DOM.

View File

@ -1,27 +0,0 @@
---
sidebar_label: Page.waitForSelector_1
---
# Page.waitForSelector() method
**Signature:**
```typescript
class Page {
waitForSelector(
selector: string,
options?: Exclude<WaitForSelectorOptions, 'root'>
): Promise<ElementHandle | null>;
}
```
## Parameters
| Parameter | Type | Description |
| --------- | -------------------------------------------------------------------------------------- | ----------------- |
| selector | string | |
| options | Exclude&lt;[WaitForSelectorOptions](./puppeteer.waitforselectoroptions.md), 'root'&gt; | <i>(Optional)</i> |
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md) \| null&gt;

View File

@ -26,7 +26,7 @@ Promise&lt;void&gt;
## Remarks
It's generally recommended to not wait for a number of seconds, but instead use , [Page.waitForXPath()](./puppeteer.page.waitforxpath.md) or [Page.waitForFunction()](./puppeteer.page.waitforfunction.md) to wait for exactly the conditions you want.
It's generally recommended to not wait for a number of seconds, but instead use [Page.waitForSelector()](./puppeteer.page.waitforselector.md), [Page.waitForXPath()](./puppeteer.page.waitforxpath.md) or [Page.waitForFunction()](./puppeteer.page.waitforfunction.md) to wait for exactly the conditions you want.
## Example

View File

@ -39,7 +39,7 @@ class Page {
hidden?: boolean;
timeout?: number;
}
): Promise<ElementHandle | null>;
): Promise<ElementHandle<Node> | null>;
}
```
@ -52,7 +52,7 @@ class Page {
**Returns:**
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md) \| null&gt;
Promise&lt;[ElementHandle](./puppeteer.elementhandle.md)&lt;Node&gt; \| null&gt;
Promise which resolves when element specified by xpath string is added to DOM. Resolves to `null` if waiting for `hidden: true` and xpath is not found in DOM.

View File

@ -13,6 +13,6 @@ export interface SnapshotOptions
## Properties
| Property | Modifiers | Type | Description |
| ------------------------------------------------------------------ | --------- | --------------------------------------------- | ------------------------------------------------------------- |
| ------------------------------------------------------------------ | --------- | --------------------------------------------------------- | ------------------------------------------------------------- |
| [interestingOnly?](./puppeteer.snapshotoptions.interestingonly.md) | | boolean | <i>(Optional)</i> Prune uninteresting nodes from the tree. |
| [root?](./puppeteer.snapshotoptions.root.md) | | [ElementHandle](./puppeteer.elementhandle.md) | <i>(Optional)</i> Root node to get the accessibility tree for |
| [root?](./puppeteer.snapshotoptions.root.md) | | [ElementHandle](./puppeteer.elementhandle.md)&lt;Node&gt; | <i>(Optional)</i> Root node to get the accessibility tree for |

View File

@ -10,6 +10,6 @@ Root node to get the accessibility tree for
```typescript
interface SnapshotOptions {
root?: ElementHandle;
root?: ElementHandle<Node>;
}
```

View File

@ -16,4 +16,4 @@ export declare class TimeoutError extends CustomError
## Remarks
Example operations are or [puppeteer.launch](./puppeteer.puppeteernode.launch.md).
Example operations are [page.waitForSelector](./puppeteer.page.waitforselector.md) or [puppeteer.launch](./puppeteer.puppeteernode.launch.md).

View File

@ -13,8 +13,8 @@ export interface WaitForSelectorOptions
## Properties
| Property | Modifiers | Type | Description |
| --------------------------------------------------------- | --------- | --------------------------------------------- | ----------------- |
| --------------------------------------------------------- | --------- | --------------------------------------------------------- | ----------------- |
| [hidden?](./puppeteer.waitforselectoroptions.hidden.md) | | boolean | <i>(Optional)</i> |
| [root?](./puppeteer.waitforselectoroptions.root.md) | | [ElementHandle](./puppeteer.elementhandle.md) | <i>(Optional)</i> |
| [root?](./puppeteer.waitforselectoroptions.root.md) | | [ElementHandle](./puppeteer.elementhandle.md)&lt;Node&gt; | <i>(Optional)</i> |
| [timeout?](./puppeteer.waitforselectoroptions.timeout.md) | | number | <i>(Optional)</i> |
| [visible?](./puppeteer.waitforselectoroptions.visible.md) | | boolean | <i>(Optional)</i> |

View File

@ -8,6 +8,6 @@ sidebar_label: WaitForSelectorOptions.root
```typescript
interface WaitForSelectorOptions {
root?: ElementHandle;
root?: ElementHandle<Node>;
}
```

View File

@ -28,7 +28,7 @@
},
"scripts": {
"test": "c8 --check-coverage --lines 94 run-s test:chrome test:chrome:* test:firefox",
"test:types": "tsc -b test-d",
"test:types": "tsd",
"test:install": "scripts/test-install.sh",
"test:firefox": "cross-env PUPPETEER_PRODUCT=firefox MOZ_WEBRENDER=0 mocha",
"test:chrome": "mocha",

View File

@ -104,7 +104,7 @@ export interface SnapshotOptions {
* Root node to get the accessibility tree for
* @defaultValue The root node of the entire page.
*/
root?: ElementHandle;
root?: ElementHandle<Node>;
}
/**

View File

@ -24,7 +24,7 @@ import {InternalQueryHandler} from './QueryHandler.js';
async function queryAXTree(
client: CDPSession,
element: ElementHandle,
element: ElementHandle<Node>,
accessibleName?: string,
role?: string
): Promise<Protocol.Accessibility.AXNode[]> {
@ -86,9 +86,9 @@ function parseAriaSelector(selector: string): ARIAQueryOption {
}
const queryOne = async (
element: ElementHandle,
element: ElementHandle<Node>,
selector: string
): Promise<ElementHandle | null> => {
): Promise<ElementHandle<Node> | null> => {
const exeCtx = element.executionContext();
const {name, role} = parseAriaSelector(selector);
const res = await queryAXTree(exeCtx._client, element, name, role);
@ -111,7 +111,7 @@ const waitFor = async (
return element;
},
};
return domWorld._waitForSelectorInPage(
return (await domWorld._waitForSelectorInPage(
(_: Element, selector: string) => {
return (
globalThis as any as unknown as {
@ -122,13 +122,13 @@ const waitFor = async (
selector,
options,
binding
);
)) as ElementHandle<Element> | null;
};
const queryAll = async (
element: ElementHandle,
element: ElementHandle<Node>,
selector: string
): Promise<ElementHandle[]> => {
): Promise<Array<ElementHandle<Node>>> => {
const exeCtx = element.executionContext();
const {name, role} = parseAriaSelector(selector);
const res = await queryAXTree(exeCtx._client, element, name, role);
@ -140,9 +140,9 @@ const queryAll = async (
};
const queryAllArray = async (
element: ElementHandle,
element: ElementHandle<Node>,
selector: string
): Promise<JSHandle<Element[]>> => {
): Promise<JSHandle<Node[]>> => {
const elementHandles = await queryAll(element, selector);
const exeCtx = element.executionContext();
const jsHandle = exeCtx.evaluateHandle((...elements) => {

View File

@ -26,7 +26,7 @@ import {JSHandle} from './JSHandle.js';
import {LifecycleWatcher, PuppeteerLifeCycleEvent} from './LifecycleWatcher.js';
import {getQueryHandlerAndSelector} from './QueryHandler.js';
import {TimeoutSettings} from './TimeoutSettings.js';
import {EvaluateFunc, HandleFor} from './types.js';
import {EvaluateFunc, HandleFor, NodeFor} from './types.js';
import {
debugError,
isNumber,
@ -54,7 +54,7 @@ export interface WaitForSelectorOptions {
visible?: boolean;
hidden?: boolean;
timeout?: number;
root?: ElementHandle;
root?: ElementHandle<Node>;
}
/**
@ -73,7 +73,7 @@ export class DOMWorld {
#client: CDPSession;
#frame: Frame;
#timeoutSettings: TimeoutSettings;
#documentPromise: Promise<ElementHandle> | null = null;
#documentPromise: Promise<ElementHandle<Document>> | null = null;
#contextPromise: Promise<ExecutionContext> | null = null;
#contextResolveCallback: ((x: ExecutionContext) => void) | null = null;
#detached = false;
@ -85,16 +85,10 @@ export class DOMWorld {
#boundFunctions = new Map<string, Function>();
#waitTasks = new Set<WaitTask>();
/**
* @internal
*/
get _waitTasks(): Set<WaitTask> {
return this.#waitTasks;
}
/**
* @internal
*/
get _boundFunctions(): Map<string, Function> {
return this.#boundFunctions;
}
@ -123,9 +117,6 @@ export class DOMWorld {
return this.#frame;
}
/**
* @internal
*/
async _setContext(context: ExecutionContext | null): Promise<void> {
if (context) {
assert(
@ -146,16 +137,10 @@ export class DOMWorld {
}
}
/**
* @internal
*/
_hasContext(): boolean {
return !this.#contextResolveCallback;
}
/**
* @internal
*/
_detach(): void {
this.#detached = true;
this.#client.off('Runtime.bindingCalled', this.#onBindingCalled);
@ -200,115 +185,64 @@ export class DOMWorld {
return context.evaluate(pageFunction, ...args);
}
async $<Selector extends keyof HTMLElementTagNameMap>(
async $<Selector extends string>(
selector: Selector
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]> | null>;
async $(selector: string): Promise<ElementHandle | null>;
async $(selector: string): Promise<ElementHandle | null> {
): Promise<ElementHandle<NodeFor<Selector>> | null> {
const document = await this._document();
const value = await document.$(selector);
return value;
}
async $$<Selector extends keyof HTMLElementTagNameMap>(
async $$<Selector extends string>(
selector: Selector
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]>[]>;
async $$(selector: string): Promise<ElementHandle[]>;
async $$(selector: string): Promise<ElementHandle[]> {
): Promise<Array<ElementHandle<NodeFor<Selector>>>> {
const document = await this._document();
const value = await document.$$(selector);
return value;
return document.$$(selector);
}
/**
* @internal
*/
async _document(): Promise<ElementHandle> {
async _document(): Promise<ElementHandle<Document>> {
if (this.#documentPromise) {
return this.#documentPromise;
}
this.#documentPromise = this.executionContext().then(async context => {
const document = await context.evaluateHandle('document');
const element = document.asElement();
if (element === null) {
throw new Error('Document is null');
}
return element;
return await context.evaluateHandle(() => {
return document;
});
});
return this.#documentPromise;
}
async $x(expression: string): Promise<ElementHandle[]> {
async $x(expression: string): Promise<Array<ElementHandle<Node>>> {
const document = await this._document();
const value = await document.$x(expression);
return value;
}
async $eval<
Selector extends keyof HTMLElementTagNameMap,
Selector extends string,
Params extends unknown[],
Func extends EvaluateFunc<
[HTMLElementTagNameMap[Selector], ...Params]
> = EvaluateFunc<[HTMLElementTagNameMap[Selector], ...Params]>
[ElementHandle<NodeFor<Selector>>, ...Params]
> = EvaluateFunc<[ElementHandle<NodeFor<Selector>>, ...Params]>
>(
selector: Selector,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
async $eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element, ...Params]> = EvaluateFunc<
[Element, ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
async $eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element, ...Params]> = EvaluateFunc<
[Element, ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>> {
const document = await this._document();
return document.$eval(selector, pageFunction, ...args);
}
async $$eval<
Selector extends keyof HTMLElementTagNameMap,
Selector extends string,
Params extends unknown[],
Func extends EvaluateFunc<
[HTMLElementTagNameMap[Selector][], ...Params]
> = EvaluateFunc<[HTMLElementTagNameMap[Selector][], ...Params]>
[Array<NodeFor<Selector>>, ...Params]
> = EvaluateFunc<[Array<NodeFor<Selector>>, ...Params]>
>(
selector: Selector,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
async $$eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element[], ...Params]> = EvaluateFunc<
[Element[], ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
async $$eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element[], ...Params]> = EvaluateFunc<
[Element[], ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>> {
const document = await this._document();
const value = await document.$$eval(selector, pageFunction, ...args);
@ -377,7 +311,7 @@ export class DOMWorld {
content?: string;
id?: string;
type?: string;
}): Promise<ElementHandle> {
}): Promise<ElementHandle<HTMLScriptElement>> {
const {
url = null,
path = null,
@ -388,17 +322,7 @@ export class DOMWorld {
if (url !== null) {
try {
const context = await this.executionContext();
const handle = await context.evaluateHandle(
addScriptUrl,
url,
id,
type
);
const elementHandle = handle.asElement();
if (elementHandle === null) {
throw new Error('Script element is not found');
}
return elementHandle;
return await context.evaluateHandle(addScriptUrl, url, id, type);
} catch (error) {
throw new Error(`Loading script from ${url} failed`);
}
@ -419,43 +343,19 @@ export class DOMWorld {
let contents = await fs.readFile(path, 'utf8');
contents += '//# sourceURL=' + path.replace(/\n/g, '');
const context = await this.executionContext();
const handle = await context.evaluateHandle(
addScriptContent,
contents,
id,
type
);
const elementHandle = handle.asElement();
if (elementHandle === null) {
throw new Error('Script element is not found');
}
return elementHandle;
return await context.evaluateHandle(addScriptContent, contents, id, type);
}
if (content !== null) {
const context = await this.executionContext();
const handle = await context.evaluateHandle(
addScriptContent,
content,
id,
type
);
const elementHandle = handle.asElement();
if (elementHandle === null) {
throw new Error('Script element is not found');
}
return elementHandle;
return await context.evaluateHandle(addScriptContent, content, id, type);
}
throw new Error(
'Provide an object with a `url`, `path` or `content` property'
);
async function addScriptUrl(
url: string,
id: string,
type: string
): Promise<HTMLElement> {
async function addScriptUrl(url: string, id: string, type: string) {
const script = document.createElement('script');
script.src = url;
if (id) {
@ -477,7 +377,7 @@ export class DOMWorld {
content: string,
id: string,
type = 'text/javascript'
): HTMLElement {
) {
const script = document.createElement('script');
script.type = type;
script.text = content;
@ -510,7 +410,7 @@ export class DOMWorld {
url?: string;
path?: string;
content?: string;
}): Promise<ElementHandle> {
}): Promise<ElementHandle<Node>> {
const {url = null, path = null, content = null} = options;
if (url !== null) {
try {
@ -640,31 +540,24 @@ export class DOMWorld {
await handle.dispose();
}
async waitForSelector<Selector extends keyof HTMLElementTagNameMap>(
async waitForSelector<Selector extends string>(
selector: Selector,
options: WaitForSelectorOptions
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]> | null>;
async waitForSelector(
selector: string,
options: WaitForSelectorOptions
): Promise<ElementHandle | null>;
async waitForSelector(
selector: string,
options: WaitForSelectorOptions
): Promise<ElementHandle | null> {
): Promise<ElementHandle<NodeFor<Selector>> | null> {
const {updatedSelector, queryHandler} =
getQueryHandlerAndSelector(selector);
assert(queryHandler.waitFor, 'Query handler does not support waiting');
return queryHandler.waitFor(this, updatedSelector, options);
return (await queryHandler.waitFor(
this,
updatedSelector,
options
)) as ElementHandle<NodeFor<Selector>> | null;
}
// If multiple waitFor are set up asynchronously, we need to wait for the
// first one to set up the binding in the page before running the others.
#settingUpBinding: Promise<void> | null = null;
/**
* @internal
*/
async _addBindingToContext(
context: ExecutionContext,
name: string
@ -776,15 +669,12 @@ export class DOMWorld {
}
};
/**
* @internal
*/
async _waitForSelectorInPage(
queryOne: Function,
selector: string,
options: WaitForSelectorOptions,
binding?: PageBinding
): Promise<ElementHandle | null> {
): Promise<ElementHandle<Node> | null> {
const {
visible: waitForVisible = false,
hidden: waitForHidden = false,
@ -829,7 +719,7 @@ export class DOMWorld {
async waitForXPath(
xpath: string,
options: WaitForSelectorOptions
): Promise<ElementHandle | null> {
): Promise<ElementHandle<Node> | null> {
const {
visible: waitForVisible = false,
hidden: waitForHidden = false,
@ -911,7 +801,7 @@ export interface WaitTaskOptions {
timeout: number;
binding?: PageBinding;
args: unknown[];
root?: ElementHandle;
root?: ElementHandle<Node>;
}
const noop = (): void => {};
@ -932,7 +822,7 @@ export class WaitTask {
#reject: (x: Error) => void = noop;
#timeoutTimer?: NodeJS.Timeout;
#terminated = false;
#root: ElementHandle | null = null;
#root: ElementHandle<Node> | null = null;
promise: Promise<JSHandle>;
@ -1099,7 +989,7 @@ export class WaitTask {
}
async function waitForPredicatePageFunction(
root: Element | Document | null,
root: Node | null,
predicateBody: string,
predicateAcceptsContextElement: boolean,
polling: 'raf' | 'mutation' | number,

View File

@ -15,7 +15,7 @@ import {
} from './JSHandle.js';
import {Page, ScreenshotOptions} from './Page.js';
import {getQueryHandlerAndSelector} from './QueryHandler.js';
import {EvaluateFunc} from './types.js';
import {EvaluateFunc, NodeFor} from './types.js';
import {KeyInput} from './USKeyboardLayout.js';
import {debugError, isString} from './util.js';
@ -64,7 +64,7 @@ const applyOffsetsToQuad = (
*/
export class ElementHandle<
ElementType extends Element = Element
ElementType extends Node = Element
> extends JSHandle<ElementType> {
#frame: Frame;
#page: Page;
@ -117,18 +117,10 @@ export class ElementHandle<
* (30 seconds). Pass `0` to disable timeout. The default value can be changed
* by using the {@link Page.setDefaultTimeout} method.
*/
async waitForSelector<Selector extends keyof HTMLElementTagNameMap>(
async waitForSelector<Selector extends string>(
selector: Selector,
options?: Exclude<WaitForSelectorOptions, 'root'>
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]> | null>;
async waitForSelector(
selector: string,
options?: Exclude<WaitForSelectorOptions, 'root'>
): Promise<ElementHandle | null>;
async waitForSelector(
selector: string,
options: Exclude<WaitForSelectorOptions, 'root'> = {}
): Promise<ElementHandle | null> {
): Promise<ElementHandle<NodeFor<Selector>> | null> {
const frame = this._context.frame();
assert(frame);
const secondaryContext = await frame._secondaryWorld.executionContext();
@ -204,7 +196,7 @@ export class ElementHandle<
hidden?: boolean;
timeout?: number;
} = {}
): Promise<ElementHandle | null> {
): Promise<ElementHandle<Node> | null> {
const frame = this._context.frame();
assert(frame);
const secondaryContext = await frame._secondaryWorld.executionContext();
@ -246,7 +238,7 @@ export class ElementHandle<
return this.#frameManager.frame(nodeInfo.node.frameId);
}
async #scrollIntoViewIfNeeded(): Promise<void> {
async #scrollIntoViewIfNeeded(this: ElementHandle<Element>): Promise<void> {
const error = await this.evaluate(
async (element, pageJavascriptEnabled): Promise<string | false> => {
if (!element.isConnected) {
@ -432,7 +424,7 @@ export class ElementHandle<
* uses {@link Page.mouse} to hover over the center of the element.
* If the element is detached from DOM, the method throws an error.
*/
async hover(): Promise<void> {
async hover(this: ElementHandle<Element>): Promise<void> {
await this.#scrollIntoViewIfNeeded();
const {x, y} = await this.clickablePoint();
await this.#page.mouse.move(x, y);
@ -443,7 +435,10 @@ export class ElementHandle<
* uses {@link Page.mouse} to click in the center of the element.
* If the element is detached from DOM, the method throws an error.
*/
async click(options: ClickOptions = {}): Promise<void> {
async click(
this: ElementHandle<Element>,
options: ClickOptions = {}
): Promise<void> {
await this.#scrollIntoViewIfNeeded();
const {x, y} = await this.clickablePoint(options.offset);
await this.#page.mouse.click(x, y, options);
@ -452,7 +447,10 @@ export class ElementHandle<
/**
* This method creates and captures a dragevent from the element.
*/
async drag(target: Point): Promise<Protocol.Input.DragData> {
async drag(
this: ElementHandle<Element>,
target: Point
): Promise<Protocol.Input.DragData> {
assert(
this.#page.isDragInterceptionEnabled(),
'Drag Interception is not enabled!'
@ -466,6 +464,7 @@ export class ElementHandle<
* This method creates a `dragenter` event on the element.
*/
async dragEnter(
this: ElementHandle<Element>,
data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
): Promise<void> {
await this.#scrollIntoViewIfNeeded();
@ -477,6 +476,7 @@ export class ElementHandle<
* This method creates a `dragover` event on the element.
*/
async dragOver(
this: ElementHandle<Element>,
data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
): Promise<void> {
await this.#scrollIntoViewIfNeeded();
@ -488,6 +488,7 @@ export class ElementHandle<
* This method triggers a drop on the element.
*/
async drop(
this: ElementHandle<Element>,
data: Protocol.Input.DragData = {items: [], dragOperationsMask: 1}
): Promise<void> {
await this.#scrollIntoViewIfNeeded();
@ -499,7 +500,8 @@ export class ElementHandle<
* This method triggers a dragenter, dragover, and drop on the element.
*/
async dragAndDrop(
target: ElementHandle,
this: ElementHandle<Element>,
target: ElementHandle<Node>,
options?: {delay: number}
): Promise<void> {
await this.#scrollIntoViewIfNeeded();
@ -637,7 +639,7 @@ export class ElementHandle<
* {@link Touchscreen.tap} to tap in the center of the element.
* If the element is detached from DOM, the method throws an error.
*/
async tap(): Promise<void> {
async tap(this: ElementHandle<Element>): Promise<void> {
await this.#scrollIntoViewIfNeeded();
const {x, y} = await this.clickablePoint();
await this.#page.touchscreen.tap(x, y);
@ -771,7 +773,10 @@ export class ElementHandle<
* {@link Page.screenshot} to take a screenshot of the element.
* If the element is detached from DOM, the method throws an error.
*/
async screenshot(options: ScreenshotOptions = {}): Promise<string | Buffer> {
async screenshot(
this: ElementHandle<Element>,
options: ScreenshotOptions = {}
): Promise<string | Buffer> {
let needsViewportReset = false;
let boundingBox = await this.boundingBox();
@ -833,18 +838,19 @@ export class ElementHandle<
* @returns `null` if no element matches the selector.
* @throws `Error` if the selector has no associated query handler.
*/
async $<Selector extends keyof HTMLElementTagNameMap>(
async $<Selector extends string>(
selector: Selector
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]> | null>;
async $(selector: string): Promise<ElementHandle | null>;
async $(selector: string): Promise<ElementHandle | null> {
): Promise<ElementHandle<NodeFor<Selector>> | null> {
const {updatedSelector, queryHandler} =
getQueryHandlerAndSelector(selector);
assert(
queryHandler.queryOne,
'Cannot handle queries for a single element with the given selector'
);
return queryHandler.queryOne(this, updatedSelector);
return (await queryHandler.queryOne(
this,
updatedSelector
)) as ElementHandle<NodeFor<Selector>> | null;
}
/**
@ -858,18 +864,18 @@ export class ElementHandle<
* @returns `[]` if no element matches the selector.
* @throws `Error` if the selector has no associated query handler.
*/
async $$<Selector extends keyof HTMLElementTagNameMap>(
async $$<Selector extends string>(
selector: Selector
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]>[]>;
async $$(selector: string): Promise<ElementHandle[]>;
async $$(selector: string): Promise<ElementHandle[]> {
): Promise<Array<ElementHandle<NodeFor<Selector>>>> {
const {updatedSelector, queryHandler} =
getQueryHandlerAndSelector(selector);
assert(
queryHandler.queryAll,
'Cannot handle queries for a multiple element with the given selector'
);
return queryHandler.queryAll(this, updatedSelector);
return (await queryHandler.queryAll(this, updatedSelector)) as Array<
ElementHandle<NodeFor<Selector>>
>;
}
/**
@ -888,35 +894,15 @@ export class ElementHandle<
* ```
*/
async $eval<
Selector extends keyof HTMLElementTagNameMap,
Selector extends string,
Params extends unknown[],
Func extends EvaluateFunc<
[HTMLElementTagNameMap[Selector], ...Params]
> = EvaluateFunc<[HTMLElementTagNameMap[Selector], ...Params]>
[ElementHandle<NodeFor<Selector>>, ...Params]
> = EvaluateFunc<[ElementHandle<NodeFor<Selector>>, ...Params]>
>(
selector: Selector,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
async $eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element, ...Params]> = EvaluateFunc<
[Element, ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
async $eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element, ...Params]> = EvaluateFunc<
[Element, ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>> {
const elementHandle = await this.$(selector);
if (!elementHandle) {
@ -953,40 +939,23 @@ export class ElementHandle<
* ```
*/
async $$eval<
Selector extends keyof HTMLElementTagNameMap,
Selector extends string,
Params extends unknown[],
Func extends EvaluateFunc<
[HTMLElementTagNameMap[Selector][], ...Params]
> = EvaluateFunc<[HTMLElementTagNameMap[Selector][], ...Params]>
[Array<NodeFor<Selector>>, ...Params]
> = EvaluateFunc<[Array<NodeFor<Selector>>, ...Params]>
>(
selector: Selector,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
async $$eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element[], ...Params]> = EvaluateFunc<
[Element[], ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
async $$eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element[], ...Params]> = EvaluateFunc<
[Element[], ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>> {
const {updatedSelector, queryHandler} =
getQueryHandlerAndSelector(selector);
assert(queryHandler.queryAllArray);
const arrayHandle = await queryHandler.queryAllArray(this, updatedSelector);
const arrayHandle = (await queryHandler.queryAllArray(
this,
updatedSelector
)) as JSHandle<Array<NodeFor<Selector>>>;
const result = await arrayHandle.evaluate(pageFunction, ...args);
await arrayHandle.dispose();
return result;
@ -997,10 +966,10 @@ export class ElementHandle<
* If there are no such elements, the method will resolve to an empty array.
* @param expression - Expression to {@link https://developer.mozilla.org/en-US/docs/Web/API/Document/evaluate | evaluate}
*/
async $x(expression: string): Promise<ElementHandle[]> {
async $x(expression: string): Promise<Array<ElementHandle<Node>>> {
const arrayHandle = await this.evaluateHandle((element, expression) => {
const document = element.ownerDocument || element;
const iterator = document.evaluate(
const doc = element.ownerDocument || document;
const iterator = doc.evaluate(
expression,
element,
null,
@ -1028,9 +997,12 @@ export class ElementHandle<
/**
* Resolves to true if the element is visible in the current viewport.
*/
async isIntersectingViewport(options?: {
async isIntersectingViewport(
this: ElementHandle<Element>,
options?: {
threshold?: number;
}): Promise<boolean> {
}
): Promise<boolean> {
const {threshold = 0} = options ?? {};
return await this.evaluate(async (element, threshold) => {
const visibleRatio = await new Promise<number>(resolve => {

View File

@ -415,20 +415,20 @@ export class ExecutionContext {
*/
async _adoptBackendNodeId(
backendNodeId?: Protocol.DOM.BackendNodeId
): Promise<ElementHandle> {
): Promise<ElementHandle<Node>> {
const {object} = await this._client.send('DOM.resolveNode', {
backendNodeId: backendNodeId,
executionContextId: this._contextId,
});
return createJSHandle(this, object) as ElementHandle;
return createJSHandle(this, object) as ElementHandle<Node>;
}
/**
* @internal
*/
async _adoptElementHandle(
elementHandle: ElementHandle
): Promise<ElementHandle> {
async _adoptElementHandle<T extends ElementHandle<Node>>(
elementHandle: T
): Promise<T> {
assert(
elementHandle.executionContext() !== this,
'Cannot adopt handle that already belongs to this execution context'
@ -437,6 +437,6 @@ export class ExecutionContext {
const nodeInfo = await this._client.send('DOM.describeNode', {
objectId: elementHandle._remoteObject.objectId,
});
return this._adoptBackendNodeId(nodeInfo.node.backendNodeId);
return (await this._adoptBackendNodeId(nodeInfo.node.backendNodeId)) as T;
}
}

View File

@ -18,16 +18,16 @@ import {Protocol} from 'devtools-protocol';
import {assert} from './assert.js';
import {CDPSession, Connection} from './Connection.js';
import {DOMWorld, WaitForSelectorOptions} from './DOMWorld.js';
import {ElementHandle} from './ElementHandle.js';
import {EventEmitter} from './EventEmitter.js';
import {EVALUATION_SCRIPT_URL, ExecutionContext} from './ExecutionContext.js';
import {HTTPResponse} from './HTTPResponse.js';
import {MouseButton} from './Input.js';
import {ElementHandle} from './ElementHandle.js';
import {LifecycleWatcher, PuppeteerLifeCycleEvent} from './LifecycleWatcher.js';
import {NetworkManager} from './NetworkManager.js';
import {Page} from './Page.js';
import {TimeoutSettings} from './TimeoutSettings.js';
import {EvaluateFunc, HandleFor} from './types.js';
import {EvaluateFunc, HandleFor, NodeFor} from './types.js';
import {debugError, isErrorLike} from './util.js';
const UTILITY_WORLD_NAME = '__puppeteer_utility_world__';
@ -920,11 +920,9 @@ export class Frame {
* @returns A promise which resolves to an `ElementHandle` pointing at the
* element, or `null` if it was not found.
*/
async $<Selector extends keyof HTMLElementTagNameMap>(
async $<Selector extends string>(
selector: Selector
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]> | null>;
async $(selector: string): Promise<ElementHandle | null>;
async $(selector: string): Promise<ElementHandle | null> {
): Promise<ElementHandle<NodeFor<Selector>> | null> {
return this._mainWorld.$(selector);
}
@ -934,11 +932,9 @@ export class Frame {
* @param selector - a selector to search for
* @returns An array of element handles pointing to the found frame elements.
*/
async $$<Selector extends keyof HTMLElementTagNameMap>(
async $$<Selector extends string>(
selector: Selector
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]>[]>;
async $$(selector: string): Promise<ElementHandle[]>;
async $$(selector: string): Promise<ElementHandle[]> {
): Promise<Array<ElementHandle<NodeFor<Selector>>>> {
return this._mainWorld.$$(selector);
}
@ -947,7 +943,7 @@ export class Frame {
*
* @param expression - the XPath expression to evaluate.
*/
async $x(expression: string): Promise<ElementHandle[]> {
async $x(expression: string): Promise<Array<ElementHandle<Node>>> {
return this._mainWorld.$x(expression);
}
@ -971,35 +967,15 @@ export class Frame {
* @param args - additional arguments to pass to `pageFunction`
*/
async $eval<
Selector extends keyof HTMLElementTagNameMap,
Selector extends string,
Params extends unknown[],
Func extends EvaluateFunc<
[HTMLElementTagNameMap[Selector], ...Params]
> = EvaluateFunc<[HTMLElementTagNameMap[Selector], ...Params]>
[ElementHandle<NodeFor<Selector>>, ...Params]
> = EvaluateFunc<[ElementHandle<NodeFor<Selector>>, ...Params]>
>(
selector: Selector,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
async $eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element, ...Params]> = EvaluateFunc<
[Element, ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
async $eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element, ...Params]> = EvaluateFunc<
[Element, ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>> {
return this._mainWorld.$eval(selector, pageFunction, ...args);
}
@ -1024,35 +1000,15 @@ export class Frame {
* @param args - additional arguments to pass to `pageFunction`
*/
async $$eval<
Selector extends keyof HTMLElementTagNameMap,
Selector extends string,
Params extends unknown[],
Func extends EvaluateFunc<
[HTMLElementTagNameMap[Selector][], ...Params]
> = EvaluateFunc<[HTMLElementTagNameMap[Selector][], ...Params]>
[Array<NodeFor<Selector>>, ...Params]
> = EvaluateFunc<[Array<NodeFor<Selector>>, ...Params]>
>(
selector: Selector,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
async $$eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element[], ...Params]> = EvaluateFunc<
[Element[], ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
async $$eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element[], ...Params]> = EvaluateFunc<
[Element[], ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>> {
return this._mainWorld.$$eval(selector, pageFunction, ...args);
}
@ -1134,7 +1090,7 @@ export class Frame {
*/
async addScriptTag(
options: FrameAddScriptTagOptions
): Promise<ElementHandle> {
): Promise<ElementHandle<HTMLScriptElement>> {
return this._mainWorld.addScriptTag(options);
}
@ -1148,7 +1104,9 @@ export class Frame {
* `onload` event fires or when the CSS content was injected into the
* frame.
*/
async addStyleTag(options: FrameAddStyleTagOptions): Promise<ElementHandle> {
async addStyleTag(
options: FrameAddStyleTagOptions
): Promise<ElementHandle<Node>> {
return this._mainWorld.addStyleTag(options);
}
@ -1345,18 +1303,10 @@ export class Frame {
* @returns a promise which resolves when an element matching the selector
* string is added to the DOM.
*/
async waitForSelector<Selector extends keyof HTMLElementTagNameMap>(
async waitForSelector<Selector extends string>(
selector: Selector,
options?: WaitForSelectorOptions
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]> | null>;
async waitForSelector(
selector: string,
options?: WaitForSelectorOptions
): Promise<ElementHandle | null>;
async waitForSelector(
selector: string,
options: WaitForSelectorOptions = {}
): Promise<ElementHandle | null> {
): Promise<ElementHandle<NodeFor<Selector>> | null> {
const handle = await this._secondaryWorld.waitForSelector(
selector,
options
@ -1388,7 +1338,7 @@ export class Frame {
async waitForXPath(
xpath: string,
options: WaitForSelectorOptions = {}
): Promise<ElementHandle | null> {
): Promise<ElementHandle<Node> | null> {
const handle = await this._secondaryWorld.waitForXPath(xpath, options);
if (!handle) {
return null;

View File

@ -23,6 +23,8 @@ import {MouseButton} from './Input.js';
import {releaseObject, valueFromRemoteObject, createJSHandle} from './util.js';
import type {ElementHandle} from './ElementHandle.js';
declare const __JSHandleSymbol: unique symbol;
/**
* @public
*/
@ -68,6 +70,11 @@ export interface BoundingBox extends Point {
* @public
*/
export class JSHandle<T = unknown> {
/**
* Used for nominally typing {@link JSHandle}.
*/
[__JSHandleSymbol]?: T;
#client: CDPSession;
#disposed = false;
#context: ExecutionContext;
@ -253,7 +260,7 @@ export class JSHandle<T = unknown> {
* @returns Either `null` or the object handle itself, if the object
* handle is an instance of {@link ElementHandle}.
*/
asElement(): ElementHandle | null {
asElement(): ElementHandle<Node> | null {
/* This always returns null, but subclasses can override this and return an
ElementHandle.
*/

View File

@ -49,7 +49,7 @@ import {Target} from './Target.js';
import {TaskQueue} from './TaskQueue.js';
import {TimeoutSettings} from './TimeoutSettings.js';
import {Tracing} from './Tracing.js';
import {EvaluateFunc, HandleFor} from './types.js';
import {EvaluateFunc, HandleFor, NodeFor} from './types.js';
import {
createJSHandle,
debugError,
@ -1025,11 +1025,9 @@ export class Page extends EventEmitter {
* {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors | selector}
* to query page for.
*/
async $<Selector extends keyof HTMLElementTagNameMap>(
async $<Selector extends string>(
selector: Selector
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]> | null>;
async $(selector: string): Promise<ElementHandle | null>;
async $(selector: string): Promise<ElementHandle | null> {
): Promise<ElementHandle<NodeFor<Selector>> | null> {
return this.mainFrame().$(selector);
}
@ -1040,11 +1038,9 @@ export class Page extends EventEmitter {
* Shortcut for {@link Frame.$$ | Page.mainFrame().$$(selector) }.
* @param selector - A `selector` to query page for
*/
async $$<Selector extends keyof HTMLElementTagNameMap>(
async $$<Selector extends string>(
selector: Selector
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]>[]>;
async $$(selector: string): Promise<ElementHandle[]>;
async $$(selector: string): Promise<ElementHandle[]> {
): Promise<Array<ElementHandle<NodeFor<Selector>>>> {
return this.mainFrame().$$(selector);
}
@ -1201,35 +1197,15 @@ export class Page extends EventEmitter {
* returned.
*/
async $eval<
Selector extends keyof HTMLElementTagNameMap,
Selector extends string,
Params extends unknown[],
Func extends EvaluateFunc<
[HTMLElementTagNameMap[Selector], ...Params]
> = EvaluateFunc<[HTMLElementTagNameMap[Selector], ...Params]>
[ElementHandle<NodeFor<Selector>>, ...Params]
> = EvaluateFunc<[ElementHandle<NodeFor<Selector>>, ...Params]>
>(
selector: Selector,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
async $eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element, ...Params]> = EvaluateFunc<
[Element, ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
async $eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element, ...Params]> = EvaluateFunc<
[Element, ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>> {
return this.mainFrame().$eval(selector, pageFunction, ...args);
}
@ -1297,35 +1273,15 @@ export class Page extends EventEmitter {
* returned.
*/
async $$eval<
Selector extends keyof HTMLElementTagNameMap,
Selector extends string,
Params extends unknown[],
Func extends EvaluateFunc<
[HTMLElementTagNameMap[Selector][], ...Params]
> = EvaluateFunc<[HTMLElementTagNameMap[Selector][], ...Params]>
[Array<NodeFor<Selector>>, ...Params]
> = EvaluateFunc<[Array<NodeFor<Selector>>, ...Params]>
>(
selector: Selector,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
async $$eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element[], ...Params]> = EvaluateFunc<
[Element[], ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>>;
async $$eval<
Params extends unknown[],
Func extends EvaluateFunc<[Element[], ...Params]> = EvaluateFunc<
[Element[], ...Params]
>
>(
selector: string,
pageFunction: Func | string,
...args: Params
): Promise<Awaited<ReturnType<Func>>> {
return this.mainFrame().$$eval(selector, pageFunction, ...args);
}
@ -1338,7 +1294,7 @@ export class Page extends EventEmitter {
* Shortcut for {@link Frame.$x | Page.mainFrame().$x(expression) }.
* @param expression - Expression to evaluate
*/
async $x(expression: string): Promise<ElementHandle[]> {
async $x(expression: string): Promise<Array<ElementHandle<Node>>> {
return this.mainFrame().$x(expression);
}
@ -1421,7 +1377,7 @@ export class Page extends EventEmitter {
content?: string;
type?: string;
id?: string;
}): Promise<ElementHandle> {
}): Promise<ElementHandle<HTMLScriptElement>> {
return this.mainFrame().addScriptTag(options);
}
@ -1435,7 +1391,7 @@ export class Page extends EventEmitter {
url?: string;
path?: string;
content?: string;
}): Promise<ElementHandle> {
}): Promise<ElementHandle<Node>> {
return this.mainFrame().addStyleTag(options);
}
@ -3339,18 +3295,10 @@ export class Page extends EventEmitter {
* (30 seconds). Pass `0` to disable timeout. The default value can be changed
* by using the {@link Page.setDefaultTimeout} method.
*/
async waitForSelector<Selector extends keyof HTMLElementTagNameMap>(
async waitForSelector<Selector extends string>(
selector: Selector,
options?: Exclude<WaitForSelectorOptions, 'root'>
): Promise<ElementHandle<HTMLElementTagNameMap[Selector]> | null>;
async waitForSelector(
selector: string,
options?: Exclude<WaitForSelectorOptions, 'root'>
): Promise<ElementHandle | null>;
async waitForSelector(
selector: string,
options: Exclude<WaitForSelectorOptions, 'root'> = {}
): Promise<ElementHandle | null> {
): Promise<ElementHandle<NodeFor<Selector>> | null> {
return await this.mainFrame().waitForSelector(selector, options);
}
@ -3409,7 +3357,7 @@ export class Page extends EventEmitter {
hidden?: boolean;
timeout?: number;
} = {}
): Promise<ElementHandle | null> {
): Promise<ElementHandle<Node> | null> {
return this.mainFrame().waitForXPath(xpath, options);
}

View File

@ -14,32 +14,33 @@
* limitations under the License.
*/
import {WaitForSelectorOptions, DOMWorld} from './DOMWorld.js';
import {JSHandle} from './JSHandle.js';
import {ariaHandler} from './AriaQueryHandler.js';
import {DOMWorld, WaitForSelectorOptions} from './DOMWorld.js';
import {ElementHandle} from './ElementHandle.js';
import {JSHandle} from './JSHandle.js';
/**
* @internal
*/
export interface InternalQueryHandler {
queryOne?: (
element: ElementHandle,
element: ElementHandle<Node>,
selector: string
) => Promise<ElementHandle | null>;
) => Promise<ElementHandle<Node> | null>;
queryAll?: (
element: ElementHandle<Node>,
selector: string
) => Promise<Array<ElementHandle<Node>>>;
waitFor?: (
domWorld: DOMWorld,
selector: string,
options: WaitForSelectorOptions
) => Promise<ElementHandle | null>;
queryAll?: (
element: ElementHandle,
selector: string
) => Promise<ElementHandle[]>;
) => Promise<ElementHandle<Node> | null>;
queryAllArray?: (
element: ElementHandle,
element: ElementHandle<Node>,
selector: string
) => Promise<JSHandle<Element[]>>;
) => Promise<JSHandle<Node[]>>;
}
/**
@ -54,14 +55,13 @@ export interface InternalQueryHandler {
* @public
*/
export interface CustomQueryHandler {
queryOne?: (element: Element | Document, selector: string) => Element | null;
queryAll?: (
element: Element | Document,
selector: string
) => Element[] | NodeListOf<Element>;
queryOne?: (element: Node, selector: string) => Node | null;
queryAll?: (element: Node, selector: string) => Node[];
}
function makeQueryHandler(handler: CustomQueryHandler): InternalQueryHandler {
function createInternalQueryHandler(
handler: CustomQueryHandler
): InternalQueryHandler {
const internalHandler: InternalQueryHandler = {};
if (handler.queryOne) {
@ -114,19 +114,37 @@ function makeQueryHandler(handler: CustomQueryHandler): InternalQueryHandler {
return internalHandler;
}
const defaultHandler = makeQueryHandler({
queryOne: (element: Element | Document, selector: string) => {
return element.querySelector(selector);
const defaultHandler = createInternalQueryHandler({
queryOne: (element, selector) => {
if (!('querySelector' in element)) {
throw new Error(
`Could not invoke \`querySelector\` on node of type ${element.nodeName}.`
);
}
return (
element as unknown as {querySelector(selector: string): Element}
).querySelector(selector);
},
queryAll: (element: Element | Document, selector: string) => {
return element.querySelectorAll(selector);
queryAll: (element, selector) => {
if (!('querySelectorAll' in element)) {
throw new Error(
`Could not invoke \`querySelectorAll\` on node of type ${element.nodeName}.`
);
}
return [
...(
element as unknown as {
querySelectorAll(selector: string): NodeList;
}
).querySelectorAll(selector),
];
},
});
const pierceHandler = makeQueryHandler({
const pierceHandler = createInternalQueryHandler({
queryOne: (element, selector) => {
let found: Element | null = null;
const search = (root: Element | ShadowRoot) => {
let found: Node | null = null;
const search = (root: Node) => {
const iter = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
do {
const currentNode = iter.currentNode as HTMLElement;
@ -149,8 +167,8 @@ const pierceHandler = makeQueryHandler({
},
queryAll: (element, selector) => {
const result: Element[] = [];
const collect = (root: Element | ShadowRoot) => {
const result: Node[] = [];
const collect = (root: Node) => {
const iter = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
do {
const currentNode = iter.currentNode as HTMLElement;
@ -213,7 +231,7 @@ export function registerCustomQueryHandler(
throw new Error(`Custom query handler names may only contain [a-zA-Z]`);
}
const internalHandler = makeQueryHandler(handler);
const internalHandler = createInternalQueryHandler(handler);
queryHandlers.set(name, internalHandler);
}

View File

@ -25,7 +25,8 @@ export type Awaitable<T> = T | PromiseLike<T>;
/**
* @public
*/
export type HandleFor<T> = T extends Element ? ElementHandle<T> : JSHandle<T>;
export type HandleFor<T> = T extends Node ? ElementHandle<T> : JSHandle<T>;
/**
* @public
*/
@ -48,3 +49,13 @@ export type InnerParams<T extends unknown[]> = {
export type EvaluateFunc<T extends unknown[]> = (
...params: InnerParams<T>
) => Awaitable<unknown>;
/**
* @public
*/
export type NodeFor<Selector extends string> =
Selector extends keyof HTMLElementTagNameMap
? HTMLElementTagNameMap[Selector]
: Selector extends keyof SVGElementTagNameMap
? SVGElementTagNameMap[Selector]
: Element;

View File

@ -215,7 +215,7 @@ export async function waitForEvent<T>(
export function createJSHandle(
context: ExecutionContext,
remoteObject: Protocol.Runtime.RemoteObject
): JSHandle | ElementHandle {
): JSHandle | ElementHandle<Node> {
const frame = context.frame();
if (remoteObject.subtype === 'node' && frame) {
const frameManager = frame._frameManager;

View File

@ -19,15 +19,15 @@ declare const handle: ElementHandle;
{
{
expectType<ElementHandle<HTMLAnchorElement>[]>(await handle.$$('a'));
expectNotType<ElementHandle<Element>[]>(await handle.$$('a'));
expectType<Array<ElementHandle<HTMLAnchorElement>>>(await handle.$$('a'));
expectNotType<Array<ElementHandle<Element>>>(await handle.$$('a'));
}
{
expectType<ElementHandle<HTMLDivElement>[]>(await handle.$$('div'));
expectNotType<ElementHandle<Element>[]>(await handle.$$('div'));
expectType<Array<ElementHandle<HTMLDivElement>>>(await handle.$$('div'));
expectNotType<Array<ElementHandle<Element>>>(await handle.$$('div'));
}
{
expectType<ElementHandle<Element>[]>(await handle.$$('some-custom'));
expectType<Array<ElementHandle<Element>>>(await handle.$$('some-custom'));
}
}

View File

@ -1,4 +1,4 @@
import {expectAssignable, expectNotAssignable, expectType} from 'tsd';
import {expectNotAssignable, expectNotType, expectType} from 'tsd';
import {ElementHandle} from '../lib/esm/puppeteer/common/ElementHandle.js';
import {JSHandle} from '../lib/esm/puppeteer/common/JSHandle.js';
@ -61,16 +61,16 @@ declare const handle2: JSHandle<{test: number}>;
{
{
expectType<JSHandle<number>>(await handle2.getProperty('test'));
expectNotAssignable<JSHandle<string>>(await handle2.getProperty('test'));
expectNotType<JSHandle<unknown>>(await handle2.getProperty('test'));
}
{
expectType<JSHandle<unknown>>(
await handle2.getProperty('key-doesnt-exist')
);
expectAssignable<JSHandle<string>>(
expectNotType<JSHandle<string>>(
await handle2.getProperty('key-doesnt-exist')
);
expectAssignable<JSHandle<number>>(
expectNotType<JSHandle<number>>(
await handle2.getProperty('key-doesnt-exist')
);
}

View File

@ -98,8 +98,10 @@ describeChromeOnly('AriaQueryHandler', () => {
await page.setContent(
'<div id="div"><button id="btn" role="button">Submit</button></div>'
);
const button = (await page.$('aria/[role="button"]'))!;
const id = await button!.evaluate((button: Element) => {
const button = (await page.$(
'aria/[role="button"]'
)) as ElementHandle<HTMLButtonElement>;
const id = await button!.evaluate(button => {
return button.id;
});
expect(id).toBe('btn');
@ -110,8 +112,10 @@ describeChromeOnly('AriaQueryHandler', () => {
await page.setContent(
'<div id="div"><button id="btn" role="button">Submit</button></div>'
);
const button = (await page.$('aria/Submit[role="button"]'))!;
const id = await button!.evaluate((button: Element) => {
const button = (await page.$(
'aria/Submit[role="button"]'
)) as ElementHandle<HTMLButtonElement>;
const id = await button!.evaluate(button => {
return button.id;
});
expect(id).toBe('btn');
@ -125,8 +129,10 @@ describeChromeOnly('AriaQueryHandler', () => {
<div role="menu" id="mnu2" aria-label="menu div"></div>
`
);
const div = (await page.$('aria/menu div'))!;
const id = await div!.evaluate((div: Element) => {
const div = (await page.$(
'aria/menu div'
)) as ElementHandle<HTMLDivElement>;
const id = await div!.evaluate(div => {
return div.id;
});
expect(id).toBe('mnu1');
@ -140,8 +146,10 @@ describeChromeOnly('AriaQueryHandler', () => {
<div role="menu" id="mnu2" aria-label="menu-label2">menu div</div>
`
);
const menu = (await page.$('aria/menu-label1'))!;
const id = await menu!.evaluate((div: Element) => {
const menu = (await page.$(
'aria/menu-label1'
)) as ElementHandle<HTMLDivElement>;
const id = await menu!.evaluate(div => {
return div.id;
});
expect(id).toBe('mnu1');
@ -155,8 +163,10 @@ describeChromeOnly('AriaQueryHandler', () => {
<div role="menu" id="mnu2" aria-label="menu-label2">menu div</div>
`
);
const menu = (await page.$('aria/menu-label2'))!;
const id = await menu!.evaluate((div: Element) => {
const menu = (await page.$(
'aria/menu-label2'
)) as ElementHandle<HTMLDivElement>;
const id = await menu!.evaluate(div => {
return div.id;
});
expect(id).toBe('mnu2');
@ -172,10 +182,12 @@ describeChromeOnly('AriaQueryHandler', () => {
<div role="menu" id="mnu2" aria-label="menu div"></div>
`
);
const divs = await page.$$('aria/menu div');
const divs = (await page.$$('aria/menu div')) as Array<
ElementHandle<HTMLDivElement>
>;
const ids = await Promise.all(
divs.map(n => {
return n.evaluate((div: Element) => {
return n.evaluate(div => {
return div.id;
});
})
@ -652,9 +664,9 @@ describeChromeOnly('AriaQueryHandler', () => {
});
it('should find by role "button"', async () => {
const {page} = getTestState();
const found = (await page.$$(
'aria/[role="button"]'
)) as ElementHandle<HTMLButtonElement>[];
const found = (await page.$$('aria/[role="button"]')) as Array<
ElementHandle<HTMLButtonElement>
>;
const ids = await getIds(found);
expect(ids).toEqual([
'node5',

View File

@ -16,6 +16,7 @@
import expect from 'expect';
import sinon from 'sinon';
import {ElementHandle} from '../../lib/cjs/puppeteer/common/ElementHandle.js';
import {
describeFailsFirefox,
getTestState,
@ -83,7 +84,9 @@ describe('ElementHandle specs', function () {
<rect id="theRect" x="30" y="50" width="200" height="300"></rect>
</svg>
`);
const element = (await page.$('#therect'))!;
const element = (await page.$(
'#therect'
)) as ElementHandle<SVGRectElement>;
const pptrBoundingBox = await element.boundingBox();
const webBoundingBox = await page.evaluate(e => {
const rect = e.getBoundingClientRect();
@ -274,7 +277,9 @@ describe('ElementHandle specs', function () {
describe('Element.waitForSelector', () => {
it('should wait correctly with waitForSelector on an element', async () => {
const {page} = getTestState();
const waitFor = page.waitForSelector('.foo');
const waitFor = page.waitForSelector('.foo') as Promise<
ElementHandle<HTMLDivElement>
>;
// Set the page content after the waitFor has been started.
await page.setContent(
'<div id="not-foo"></div><div class="bar">bar2</div><div class="foo">Foo1</div>'
@ -282,7 +287,9 @@ describe('ElementHandle specs', function () {
let element = (await waitFor)!;
expect(element).toBeDefined();
const innerWaitFor = element.waitForSelector('.bar');
const innerWaitFor = element.waitForSelector('.bar') as Promise<
ElementHandle<HTMLDivElement>
>;
await element.evaluate(el => {
el.innerHTML = '<div class="bar">bar1</div>';
});
@ -312,19 +319,20 @@ describe('ElementHandle specs', function () {
</div>`
);
const el2 = (await page.waitForSelector('#el1'))!;
const el2 = (await page.waitForSelector(
'#el1'
)) as ElementHandle<HTMLDivElement>;
for (const path of ['//div', './/div']) {
const e = (await el2.waitForXPath(
path
)) as ElementHandle<HTMLDivElement>;
expect(
await (await el2.waitForXPath('//div'))!.evaluate(el => {
return el.id;
})
).toStrictEqual('el2');
expect(
await (await el2.waitForXPath('.//div'))!.evaluate(el => {
await e.evaluate(el => {
return el.id;
})
).toStrictEqual('el2');
}
});
});
@ -398,7 +406,9 @@ describe('ElementHandle specs', function () {
return document.querySelector(`[id="${selector}"]`);
},
});
const element = (await page.$('getById/foo'))!;
const element = (await page.$(
'getById/foo'
)) as ElementHandle<HTMLDivElement>;
expect(
await page.evaluate(element => {
return element.id;
@ -447,10 +457,12 @@ describe('ElementHandle specs', function () {
);
puppeteer.registerCustomQueryHandler('getByClass', {
queryAll: (_element, selector) => {
return document.querySelectorAll(`.${selector}`);
return [...document.querySelectorAll(`.${selector}`)];
},
});
const elements = await page.$$('getByClass/foo');
const elements = (await page.$$('getByClass/foo')) as Array<
ElementHandle<HTMLDivElement>
>;
const classNames = await Promise.all(
elements.map(async element => {
return await page.evaluate(element => {
@ -468,7 +480,7 @@ describe('ElementHandle specs', function () {
);
puppeteer.registerCustomQueryHandler('getByClass', {
queryAll: (_element, selector) => {
return document.querySelectorAll(`.${selector}`);
return [...document.querySelectorAll(`.${selector}`)];
},
});
const elements = await page.$$eval('getByClass/foo', divs => {
@ -481,7 +493,7 @@ describe('ElementHandle specs', function () {
const {page, puppeteer} = getTestState();
puppeteer.registerCustomQueryHandler('getByClass', {
queryOne: (element, selector) => {
return element.querySelector(`.${selector}`);
return (element as Element).querySelector(`.${selector}`);
},
});
const waitFor = page.waitForSelector('getByClass/foo');
@ -499,10 +511,12 @@ describe('ElementHandle specs', function () {
const {page, puppeteer} = getTestState();
puppeteer.registerCustomQueryHandler('getByClass', {
queryOne: (element, selector) => {
return element.querySelector(`.${selector}`);
return (element as Element).querySelector(`.${selector}`);
},
});
const waitFor = page.waitForSelector('getByClass/foo');
const waitFor = page.waitForSelector('getByClass/foo') as Promise<
ElementHandle<HTMLElement>
>;
// Set the page content after the waitFor has been started.
await page.setContent(
@ -511,7 +525,9 @@ describe('ElementHandle specs', function () {
let element = (await waitFor)!;
expect(element).toBeDefined();
const innerWaitFor = element.waitForSelector('getByClass/bar');
const innerWaitFor = element.waitForSelector('getByClass/bar') as Promise<
ElementHandle<HTMLElement>
>;
await element.evaluate(el => {
el.innerHTML = '<div class="bar">bar1</div>';
@ -521,7 +537,7 @@ describe('ElementHandle specs', function () {
expect(element).toBeDefined();
expect(
await element.evaluate(el => {
return (el as HTMLElement).innerText;
return el.innerText;
})
).toStrictEqual('bar1');
});
@ -532,7 +548,7 @@ describe('ElementHandle specs', function () {
const {page, puppeteer} = getTestState();
puppeteer.registerCustomQueryHandler('getByClass', {
queryOne: (element, selector) => {
return element.querySelector(`.${selector}`);
return (element as Element).querySelector(`.${selector}`);
},
});
const waitFor = page.waitForSelector('getByClass/foo');
@ -552,10 +568,10 @@ describe('ElementHandle specs', function () {
);
puppeteer.registerCustomQueryHandler('getByClass', {
queryOne: (element, selector) => {
return element.querySelector(`.${selector}`);
return (element as Element).querySelector(`.${selector}`);
},
queryAll: (element, selector) => {
return element.querySelectorAll(`.${selector}`);
return [...(element as Element).querySelectorAll(`.${selector}`)];
},
});
@ -572,10 +588,10 @@ describe('ElementHandle specs', function () {
);
puppeteer.registerCustomQueryHandler('getByClass', {
queryOne: (element, selector) => {
return element.querySelector(`.${selector}`);
return (element as Element).querySelector(`.${selector}`);
},
queryAll: (element, selector) => {
return element.querySelectorAll(`.${selector}`);
return [...(element as Element).querySelectorAll(`.${selector}`)];
},
});

View File

@ -399,7 +399,7 @@ describe('JSHandle', function () {
itFailsFirefox('should work', async () => {
const {page} = getTestState();
const clicks: [x: number, y: number][] = [];
const clicks: Array<[x: number, y: number]> = [];
await page.exposeFunction('reportClick', (x: number, y: number): void => {
clicks.push([x, y]);

View File

@ -20,6 +20,7 @@ import {
setupTestPageAndContextHooks,
} from './mocha-utils.js';
import {CustomQueryHandler} from '../../lib/cjs/puppeteer/common/QueryHandler.js';
import {ElementHandle} from '../../lib/cjs/puppeteer/common/ElementHandle.js';
describe('querySelector', function () {
setupTestBrowserHooks();
@ -99,18 +100,20 @@ describe('querySelector', function () {
});
it('should find first element in shadow', async () => {
const {page} = getTestState();
const div = (await page.$('pierce/.foo'))!;
const text = await div.evaluate((element: Element) => {
const div = (await page.$('pierce/.foo')) as ElementHandle<HTMLElement>;
const text = await div.evaluate(element => {
return element.textContent;
});
expect(text).toBe('Hello');
});
it('should find all elements in shadow', async () => {
const {page} = getTestState();
const divs = await page.$$('pierce/.foo');
const divs = (await page.$$('pierce/.foo')) as Array<
ElementHandle<HTMLElement>
>;
const text = await Promise.all(
divs.map(div => {
return div.evaluate((element: Element) => {
return div.evaluate(element => {
return element.textContent;
});
})
@ -120,8 +123,10 @@ describe('querySelector', function () {
it('should find first child element', async () => {
const {page} = getTestState();
const parentElement = (await page.$('html > div'))!;
const childElement = (await parentElement.$('pierce/div'))!;
const text = await childElement.evaluate((element: Element) => {
const childElement = (await parentElement.$(
'pierce/div'
)) as ElementHandle<HTMLElement>;
const text = await childElement.evaluate(element => {
return element.textContent;
});
expect(text).toBe('Hello');
@ -129,10 +134,12 @@ describe('querySelector', function () {
it('should find all child elements', async () => {
const {page} = getTestState();
const parentElement = (await page.$('html > div'))!;
const childElements = await parentElement.$$('pierce/div');
const childElements = (await parentElement.$$('pierce/div')) as Array<
ElementHandle<HTMLElement>
>;
const text = await Promise.all(
childElements.map(div => {
return div.evaluate((element: Element) => {
return div.evaluate(element => {
return element.textContent;
});
})
@ -456,10 +463,7 @@ describe('querySelector', function () {
describe('QueryAll', function () {
const handler: CustomQueryHandler = {
queryAll: (element, selector) => {
if (element instanceof Document || element instanceof Element) {
return element.querySelectorAll(selector);
}
return [];
return [...(element as Element).querySelectorAll(selector)];
},
};
before(() => {

View File

@ -111,10 +111,7 @@ export async function navigateFrame(
}
}
export const dumpFrames = (
frame: Frame,
indentation?: string
): Array<string> => {
export const dumpFrames = (frame: Frame, indentation?: string): string[] => {
indentation = indentation || '';
let description = frame.url().replace(/:\d{4,5}\//, ':<PORT>/');
if (frame.name()) {

View File

@ -672,7 +672,7 @@ export class MarkdownDocumenter {
headerTitles: ['Type Alias', 'Description'],
});
const apiMembers: ReadonlyArray<ApiItem> =
const apiMembers: readonly ApiItem[] =
apiContainer.kind === ApiItemKind.Package
? (apiContainer as ApiPackage).entryPoints[0]!.members
: (apiContainer as ApiNamespace).members;