chore: refactor JSHandle and ExecutionContext (#8773)
This commit is contained in:
parent
ee2540baef
commit
a238f5758d
@ -6,40 +6,40 @@ sidebar_label: API
|
|||||||
|
|
||||||
## Classes
|
## Classes
|
||||||
|
|
||||||
| Class | Description |
|
| Class | Description |
|
||||||
| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| [Accessibility](./puppeteer.accessibility.md) | The Accessibility class provides methods for inspecting Chromium's accessibility tree. The accessibility tree is used by assistive technology such as [screen readers](https://en.wikipedia.org/wiki/Screen_reader) or [switches](https://en.wikipedia.org/wiki/Switch_access). |
|
| [Accessibility](./puppeteer.accessibility.md) | The Accessibility class provides methods for inspecting Chromium's accessibility tree. The accessibility tree is used by assistive technology such as [screen readers](https://en.wikipedia.org/wiki/Screen_reader) or [switches](https://en.wikipedia.org/wiki/Switch_access). |
|
||||||
| [Browser](./puppeteer.browser.md) | A Browser is created when Puppeteer connects to a Chromium instance, either through [PuppeteerNode.launch()](./puppeteer.puppeteernode.launch.md) or [Puppeteer.connect()](./puppeteer.puppeteer.connect.md). |
|
| [Browser](./puppeteer.browser.md) | A Browser is created when Puppeteer connects to a Chromium instance, either through [PuppeteerNode.launch()](./puppeteer.puppeteernode.launch.md) or [Puppeteer.connect()](./puppeteer.puppeteer.connect.md). |
|
||||||
| [BrowserContext](./puppeteer.browsercontext.md) | BrowserContexts provide a way to operate multiple independent browser sessions. When a browser is launched, it has a single BrowserContext used by default. The method [Browser.newPage](./puppeteer.browser.newpage.md) creates a page in the default browser context. |
|
| [BrowserContext](./puppeteer.browsercontext.md) | BrowserContexts provide a way to operate multiple independent browser sessions. When a browser is launched, it has a single BrowserContext used by default. The method [Browser.newPage](./puppeteer.browser.newpage.md) creates a page in the default browser context. |
|
||||||
| [BrowserFetcher](./puppeteer.browserfetcher.md) | BrowserFetcher can download and manage different versions of Chromium and Firefox. |
|
| [BrowserFetcher](./puppeteer.browserfetcher.md) | BrowserFetcher can download and manage different versions of Chromium and Firefox. |
|
||||||
| [CDPSession](./puppeteer.cdpsession.md) | The <code>CDPSession</code> instances are used to talk raw Chrome Devtools Protocol. |
|
| [CDPSession](./puppeteer.cdpsession.md) | The <code>CDPSession</code> instances are used to talk raw Chrome Devtools Protocol. |
|
||||||
| [Connection](./puppeteer.connection.md) | |
|
| [Connection](./puppeteer.connection.md) | |
|
||||||
| [ConsoleMessage](./puppeteer.consolemessage.md) | ConsoleMessage objects are dispatched by page via the 'console' event. |
|
| [ConsoleMessage](./puppeteer.consolemessage.md) | ConsoleMessage objects are dispatched by page via the 'console' event. |
|
||||||
| [Coverage](./puppeteer.coverage.md) | The Coverage class provides methods to gathers information about parts of JavaScript and CSS that were used by the page. |
|
| [Coverage](./puppeteer.coverage.md) | The Coverage class provides methods to gathers information about parts of JavaScript and CSS that were used by the page. |
|
||||||
| [CSSCoverage](./puppeteer.csscoverage.md) | |
|
| [CSSCoverage](./puppeteer.csscoverage.md) | |
|
||||||
| [CustomError](./puppeteer.customerror.md) | |
|
| [CustomError](./puppeteer.customerror.md) | |
|
||||||
| [Dialog](./puppeteer.dialog.md) | Dialog instances are dispatched by the [Page](./puppeteer.page.md) via the <code>dialog</code> event. |
|
| [Dialog](./puppeteer.dialog.md) | Dialog instances are dispatched by the [Page](./puppeteer.page.md) via the <code>dialog</code> event. |
|
||||||
| [ElementHandle](./puppeteer.elementhandle.md) | ElementHandle represents an in-page DOM element. |
|
| [ElementHandle](./puppeteer.elementhandle.md) | ElementHandle represents an in-page DOM element. |
|
||||||
| [EventEmitter](./puppeteer.eventemitter.md) | The EventEmitter class that many Puppeteer classes extend. |
|
| [EventEmitter](./puppeteer.eventemitter.md) | The EventEmitter class that many Puppeteer classes extend. |
|
||||||
| [ExecutionContext](./puppeteer.executioncontext.md) | <p>This class represents a context for JavaScript execution. A \[Page\] might have many execution contexts: - each [frame](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe) has "default" execution context that is always created after frame is attached to DOM. This context is returned by the [Frame.executionContext()](./puppeteer.frame.executioncontext.md) method. - [Extension](https://developer.chrome.com/extensions)'s content scripts create additional execution contexts.</p><p>Besides pages, execution contexts can be found in [workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API).</p> |
|
| [ExecutionContext](./puppeteer.executioncontext.md) | Represents a context for JavaScript execution. |
|
||||||
| [FileChooser](./puppeteer.filechooser.md) | File choosers let you react to the page requesting for a file. |
|
| [FileChooser](./puppeteer.filechooser.md) | File choosers let you react to the page requesting for a file. |
|
||||||
| [Frame](./puppeteer.frame.md) | At every point of time, page exposes its current frame tree via the [page.mainFrame](./puppeteer.page.mainframe.md) and [frame.childFrames](./puppeteer.frame.childframes.md) methods. |
|
| [Frame](./puppeteer.frame.md) | At every point of time, page exposes its current frame tree via the [page.mainFrame](./puppeteer.page.mainframe.md) and [frame.childFrames](./puppeteer.frame.childframes.md) methods. |
|
||||||
| [HTTPRequest](./puppeteer.httprequest.md) | Represents an HTTP request sent by a page. |
|
| [HTTPRequest](./puppeteer.httprequest.md) | Represents an HTTP request sent by a page. |
|
||||||
| [HTTPResponse](./puppeteer.httpresponse.md) | The HTTPResponse class represents responses which are received by the [Page](./puppeteer.page.md) class. |
|
| [HTTPResponse](./puppeteer.httpresponse.md) | The HTTPResponse class represents responses which are received by the [Page](./puppeteer.page.md) class. |
|
||||||
| [JSCoverage](./puppeteer.jscoverage.md) | |
|
| [JSCoverage](./puppeteer.jscoverage.md) | |
|
||||||
| [JSHandle](./puppeteer.jshandle.md) | Represents an in-page JavaScript object. JSHandles can be created with the [page.evaluateHandle](./puppeteer.page.evaluatehandle.md) method. |
|
| [JSHandle](./puppeteer.jshandle.md) | <p>Represents a reference to a JavaScript object. Instances can be created using [Page.evaluateHandle()](./puppeteer.page.evaluatehandle.md).</p><p>Handles prevent the referenced JavaScript object from being garbage-collected unless the handle is purposely [disposed](./puppeteer.jshandle.dispose.md). JSHandles are auto-disposed when their associated frame is navigated away or the parent context gets destroyed.</p><p>Handles can be used as arguments for any evaluation function such as [Page.$eval()](./puppeteer.page._eval.md), [Page.evaluate()](./puppeteer.page.evaluate.md), and [Page.evaluateHandle()](./puppeteer.page.evaluatehandle.md). They are resolved to their referenced object.</p> |
|
||||||
| [Keyboard](./puppeteer.keyboard.md) | Keyboard provides an api for managing a virtual keyboard. The high level api is [Keyboard.type()](./puppeteer.keyboard.type.md), which takes raw characters and generates proper keydown, keypress/input, and keyup events on your page. |
|
| [Keyboard](./puppeteer.keyboard.md) | Keyboard provides an api for managing a virtual keyboard. The high level api is [Keyboard.type()](./puppeteer.keyboard.type.md), which takes raw characters and generates proper keydown, keypress/input, and keyup events on your page. |
|
||||||
| [Mouse](./puppeteer.mouse.md) | The Mouse class operates in main-frame CSS pixels relative to the top-left corner of the viewport. |
|
| [Mouse](./puppeteer.mouse.md) | The Mouse class operates in main-frame CSS pixels relative to the top-left corner of the viewport. |
|
||||||
| [Page](./puppeteer.page.md) | <p>Page provides methods to interact with a single tab or [extension background page](https://developer.chrome.com/extensions/background_pages) in Chromium.</p><p>:::note</p><p>One Browser instance might have multiple Page instances.</p><p>:::</p> |
|
| [Page](./puppeteer.page.md) | <p>Page provides methods to interact with a single tab or [extension background page](https://developer.chrome.com/extensions/background_pages) in Chromium.</p><p>:::note</p><p>One Browser instance might have multiple Page instances.</p><p>:::</p> |
|
||||||
| [ProtocolError](./puppeteer.protocolerror.md) | ProtocolError is emitted whenever there is an error from the protocol. |
|
| [ProtocolError](./puppeteer.protocolerror.md) | ProtocolError is emitted whenever there is an error from the protocol. |
|
||||||
| [Puppeteer](./puppeteer.puppeteer.md) | <p>The main Puppeteer class.</p><p>IMPORTANT: if you are using Puppeteer in a Node environment, you will get an instance of [PuppeteerNode](./puppeteer.puppeteernode.md) when you import or require <code>puppeteer</code>. That class extends <code>Puppeteer</code>, so has all the methods documented below as well as all that are defined on [PuppeteerNode](./puppeteer.puppeteernode.md).</p> |
|
| [Puppeteer](./puppeteer.puppeteer.md) | <p>The main Puppeteer class.</p><p>IMPORTANT: if you are using Puppeteer in a Node environment, you will get an instance of [PuppeteerNode](./puppeteer.puppeteernode.md) when you import or require <code>puppeteer</code>. That class extends <code>Puppeteer</code>, so has all the methods documented below as well as all that are defined on [PuppeteerNode](./puppeteer.puppeteernode.md).</p> |
|
||||||
| [PuppeteerNode](./puppeteer.puppeteernode.md) | <p>Extends the main [Puppeteer](./puppeteer.puppeteer.md) class with Node specific behaviour for fetching and downloading browsers.</p><p>If you're using Puppeteer in a Node environment, this is the class you'll get when you run <code>require('puppeteer')</code> (or the equivalent ES <code>import</code>).</p> |
|
| [PuppeteerNode](./puppeteer.puppeteernode.md) | <p>Extends the main [Puppeteer](./puppeteer.puppeteer.md) class with Node specific behaviour for fetching and downloading browsers.</p><p>If you're using Puppeteer in a Node environment, this is the class you'll get when you run <code>require('puppeteer')</code> (or the equivalent ES <code>import</code>).</p> |
|
||||||
| [SecurityDetails](./puppeteer.securitydetails.md) | The SecurityDetails class represents the security details of a response that was received over a secure connection. |
|
| [SecurityDetails](./puppeteer.securitydetails.md) | The SecurityDetails class represents the security details of a response that was received over a secure connection. |
|
||||||
| [Target](./puppeteer.target.md) | |
|
| [Target](./puppeteer.target.md) | |
|
||||||
| [TimeoutError](./puppeteer.timeouterror.md) | TimeoutError is emitted whenever certain operations are terminated due to timeout. |
|
| [TimeoutError](./puppeteer.timeouterror.md) | TimeoutError is emitted whenever certain operations are terminated due to timeout. |
|
||||||
| [Touchscreen](./puppeteer.touchscreen.md) | The Touchscreen class exposes touchscreen events. |
|
| [Touchscreen](./puppeteer.touchscreen.md) | The Touchscreen class exposes touchscreen events. |
|
||||||
| [Tracing](./puppeteer.tracing.md) | The Tracing class exposes the tracing audit interface. |
|
| [Tracing](./puppeteer.tracing.md) | The Tracing class exposes the tracing audit interface. |
|
||||||
| [WebWorker](./puppeteer.webworker.md) | This class represents a [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API). |
|
| [WebWorker](./puppeteer.webworker.md) | This class represents a [WebWorker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API). |
|
||||||
|
|
||||||
## Enumerations
|
## Enumerations
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ sidebar_label: ExecutionContext.evaluate
|
|||||||
|
|
||||||
# ExecutionContext.evaluate() method
|
# ExecutionContext.evaluate() method
|
||||||
|
|
||||||
|
Evaluates the given function.
|
||||||
|
|
||||||
**Signature:**
|
**Signature:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
@ -20,20 +22,16 @@ class ExecutionContext {
|
|||||||
|
|
||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| ------------ | -------------- | --------------------------------------------------------------- |
|
| ------------ | -------------- | ----------------------------------------------- |
|
||||||
| pageFunction | Func \| string | a function to be evaluated in the <code>executionContext</code> |
|
| pageFunction | Func \| string | The function to evaluate. |
|
||||||
| args | Params | argument to pass to the page function |
|
| args | Params | Additional arguments to pass into the function. |
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
Promise<Awaited<ReturnType<Func>>>
|
Promise<Awaited<ReturnType<Func>>>
|
||||||
|
|
||||||
A promise that resolves to the return value of the given function.
|
The result of evaluating the function. If the result is an object, a vanilla object containing the serializable properties of the result is returned.
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
If the function passed to the `executionContext.evaluate` returns a Promise, then `executionContext.evaluate` would wait for the promise to resolve and return its value. If the function passed to the `executionContext.evaluate` returns a non-serializable value, then `executionContext.evaluate` resolves to `undefined`. DevTools Protocol also supports transferring some additional values that are not serializable by `JSON`: `-0`, `NaN`, `Infinity`, `-Infinity`, and bigint literals.
|
|
||||||
|
|
||||||
## Example 1
|
## Example 1
|
||||||
|
|
||||||
@ -45,7 +43,7 @@ console.log(result); // prints "56"
|
|||||||
|
|
||||||
## Example 2
|
## Example 2
|
||||||
|
|
||||||
A string can also be passed in instead of a function.
|
A string can also be passed in instead of a function:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
console.log(await executionContext.evaluate('1 + 2')); // prints "3"
|
console.log(await executionContext.evaluate('1 + 2')); // prints "3"
|
||||||
@ -53,13 +51,15 @@ console.log(await executionContext.evaluate('1 + 2')); // prints "3"
|
|||||||
|
|
||||||
## Example 3
|
## Example 3
|
||||||
|
|
||||||
[JSHandle](./puppeteer.jshandle.md) instances can be passed as arguments to the `executionContext.* evaluate`:
|
Handles can also be passed as `args`. They resolve to their referenced object:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const oneHandle = await executionContext.evaluateHandle(() => 1);
|
const oneHandle = await executionContext.evaluateHandle(() => 1);
|
||||||
const twoHandle = await executionContext.evaluateHandle(() => 2);
|
const twoHandle = await executionContext.evaluateHandle(() => 2);
|
||||||
const result = await executionContext.evaluate(
|
const result = await executionContext.evaluate(
|
||||||
(a, b) => a + b, oneHandle, * twoHandle
|
(a, b) => a + b,
|
||||||
|
oneHandle,
|
||||||
|
twoHandle
|
||||||
);
|
);
|
||||||
await oneHandle.dispose();
|
await oneHandle.dispose();
|
||||||
await twoHandle.dispose();
|
await twoHandle.dispose();
|
||||||
|
@ -4,6 +4,12 @@ sidebar_label: ExecutionContext.evaluateHandle
|
|||||||
|
|
||||||
# ExecutionContext.evaluateHandle() method
|
# ExecutionContext.evaluateHandle() method
|
||||||
|
|
||||||
|
Evaluates the given function.
|
||||||
|
|
||||||
|
Unlike [evaluate](./puppeteer.executioncontext.evaluate.md), this method returns a handle to the result of the function.
|
||||||
|
|
||||||
|
This method may be better suited if the object cannot be serialized (e.g. `Map`) and requires further manipulation.
|
||||||
|
|
||||||
**Signature:**
|
**Signature:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
@ -20,27 +26,24 @@ class ExecutionContext {
|
|||||||
|
|
||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
| Parameter | Type | Description |
|
| Parameter | Type | Description |
|
||||||
| ------------ | -------------- | --------------------------------------------------------------- |
|
| ------------ | -------------- | ----------------------------------------------- |
|
||||||
| pageFunction | Func \| string | a function to be evaluated in the <code>executionContext</code> |
|
| pageFunction | Func \| string | The function to evaluate. |
|
||||||
| args | Params | argument to pass to the page function |
|
| args | Params | Additional arguments to pass into the function. |
|
||||||
|
|
||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
Promise<[HandleFor](./puppeteer.handlefor.md)<Awaited<ReturnType<Func>>>>
|
Promise<[HandleFor](./puppeteer.handlefor.md)<Awaited<ReturnType<Func>>>>
|
||||||
|
|
||||||
A promise that resolves to the return value of the given function as an in-page object (a [JSHandle](./puppeteer.jshandle.md)).
|
A [handle](./puppeteer.jshandle.md) to the result of evaluating the function. If the result is a `Node`, then this will return an [element handle](./puppeteer.elementhandle.md).
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
The only difference between `executionContext.evaluate` and `executionContext.evaluateHandle` is that `executionContext.evaluateHandle` returns an in-page object (a [JSHandle](./puppeteer.jshandle.md)). If the function passed to the `executionContext.evaluateHandle` returns a Promise, then `executionContext.evaluateHandle` would wait for the promise to resolve and return its value.
|
|
||||||
|
|
||||||
## Example 1
|
## Example 1
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const context = await page.mainFrame().executionContext();
|
const context = await page.mainFrame().executionContext();
|
||||||
const aHandle = await context.evaluateHandle(() => Promise.resolve(self));
|
const handle: JSHandle<typeof globalThis> = await context.evaluateHandle(() =>
|
||||||
aHandle; // Handle for the global object.
|
Promise.resolve(self)
|
||||||
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example 2
|
## Example 2
|
||||||
@ -48,18 +51,25 @@ aHandle; // Handle for the global object.
|
|||||||
A string can also be passed in instead of a function.
|
A string can also be passed in instead of a function.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
// Handle for the '3' * object.
|
const handle: JSHandle<number> = await context.evaluateHandle('1 + 2');
|
||||||
const aHandle = await context.evaluateHandle('1 + 2');
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example 3
|
## Example 3
|
||||||
|
|
||||||
JSHandle instances can be passed as arguments to the `executionContext.* evaluateHandle`:
|
Handles can also be passed as `args`. They resolve to their referenced object:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const aHandle = await context.evaluateHandle(() => document.body);
|
const bodyHandle: ElementHandle<HTMLBodyElement> = await context.evaluateHandle(
|
||||||
const resultHandle = await context.evaluateHandle(body => body.innerHTML, * aHandle);
|
() => {
|
||||||
console.log(await resultHandle.jsonValue()); // prints body's innerHTML
|
return document.body;
|
||||||
await aHandle.dispose();
|
}
|
||||||
await resultHandle.dispose();
|
);
|
||||||
|
const stringHandle: JSHandle<string> = await context.evaluateHandle(
|
||||||
|
body => body.innerHTML,
|
||||||
|
body
|
||||||
|
);
|
||||||
|
console.log(await stringHandle.jsonValue()); // prints body's innerHTML
|
||||||
|
// Always dispose your garbage! :)
|
||||||
|
await bodyHandle.dispose();
|
||||||
|
await stringHandle.dispose();
|
||||||
```
|
```
|
||||||
|
@ -20,4 +20,4 @@ The frame associated with this execution context.
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
Not every execution context is associated with a frame. For example, workers and extensions have execution contexts that are not associated with frames.
|
Not every execution context is associated with a frame. For example, [workers](./puppeteer.webworker.md) have execution contexts that are not associated with frames.
|
||||||
|
@ -4,9 +4,7 @@ sidebar_label: ExecutionContext
|
|||||||
|
|
||||||
# ExecutionContext class
|
# ExecutionContext class
|
||||||
|
|
||||||
This class represents a context for JavaScript execution. A \[Page\] might have many execution contexts: - each [frame](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe) has "default" execution context that is always created after frame is attached to DOM. This context is returned by the [Frame.executionContext()](./puppeteer.frame.executioncontext.md) method. - [Extension](https://developer.chrome.com/extensions)'s content scripts create additional execution contexts.
|
Represents a context for JavaScript execution.
|
||||||
|
|
||||||
Besides pages, execution contexts can be found in [workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API).
|
|
||||||
|
|
||||||
**Signature:**
|
**Signature:**
|
||||||
|
|
||||||
@ -16,13 +14,21 @@ export declare class ExecutionContext
|
|||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
|
Besides pages, execution contexts can be found in [workers](./puppeteer.webworker.md).
|
||||||
|
|
||||||
The constructor for this class is marked as internal. Third-party code should not call the constructor directly or create subclasses that extend the `ExecutionContext` class.
|
The constructor for this class is marked as internal. Third-party code should not call the constructor directly or create subclasses that extend the `ExecutionContext` class.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
A [Page](./puppeteer.page.md) can have several execution contexts:
|
||||||
|
|
||||||
|
- Each [Frame](./puppeteer.frame.md) of a [page](./puppeteer.page.md) has a "default" execution context that is always created after frame is attached to DOM. This context is returned by the [Frame.executionContext()](./puppeteer.frame.executioncontext.md) method. - Each [Chrome extensions](https://developer.chrome.com/extensions) creates additional execution contexts to isolate their code.
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
| Method | Modifiers | Description |
|
| Method | Modifiers | Description |
|
||||||
| ------------------------------------------------------------------------------------ | --------- | -------------------------------------------------------------------------------------------- |
|
| ------------------------------------------------------------------------------------ | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| [evaluate(pageFunction, args)](./puppeteer.executioncontext.evaluate.md) | | |
|
| [evaluate(pageFunction, args)](./puppeteer.executioncontext.evaluate.md) | | Evaluates the given function. |
|
||||||
| [evaluateHandle(pageFunction, args)](./puppeteer.executioncontext.evaluatehandle.md) | | |
|
| [evaluateHandle(pageFunction, args)](./puppeteer.executioncontext.evaluatehandle.md) | | <p>Evaluates the given function.</p><p>Unlike [evaluate](./puppeteer.executioncontext.evaluate.md), this method returns a handle to the result of the function.</p><p>This method may be better suited if the object cannot be serialized (e.g. <code>Map</code>) and requires further manipulation.</p> |
|
||||||
| [frame()](./puppeteer.executioncontext.frame.md) | | |
|
| [frame()](./puppeteer.executioncontext.frame.md) | | |
|
||||||
| [queryObjects(prototypeHandle)](./puppeteer.executioncontext.queryobjects.md) | | This method iterates the JavaScript heap and finds all the objects with the given prototype. |
|
| [queryObjects(prototypeHandle)](./puppeteer.executioncontext.queryobjects.md) | | Iterates through the JavaScript heap and finds all the objects with the given prototype. |
|
||||||
|
@ -4,7 +4,7 @@ sidebar_label: ExecutionContext.queryObjects
|
|||||||
|
|
||||||
# ExecutionContext.queryObjects() method
|
# ExecutionContext.queryObjects() method
|
||||||
|
|
||||||
This method iterates the JavaScript heap and finds all the objects with the given prototype.
|
Iterates through the JavaScript heap and finds all the objects with the given prototype.
|
||||||
|
|
||||||
**Signature:**
|
**Signature:**
|
||||||
|
|
||||||
@ -28,8 +28,6 @@ Promise<[HandleFor](./puppeteer.handlefor.md)<Prototype\[\]>>
|
|||||||
|
|
||||||
A handle to an array of objects with the given prototype.
|
A handle to an array of objects with the given prototype.
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
|
@ -16,4 +16,4 @@ class JSHandle {
|
|||||||
|
|
||||||
[ElementHandle](./puppeteer.elementhandle.md)<Node> \| null
|
[ElementHandle](./puppeteer.elementhandle.md)<Node> \| null
|
||||||
|
|
||||||
Either `null` or the object handle itself, if the object handle is an instance of [ElementHandle](./puppeteer.elementhandle.md).
|
Either `null` or the handle itself if the handle is an instance of [ElementHandle](./puppeteer.elementhandle.md).
|
||||||
|
@ -4,7 +4,7 @@ sidebar_label: JSHandle.dispose
|
|||||||
|
|
||||||
# JSHandle.dispose() method
|
# JSHandle.dispose() method
|
||||||
|
|
||||||
Stops referencing the element handle, and resolves when the object handle is successfully disposed of.
|
Releases the object referenced by the handle for garbage collection.
|
||||||
|
|
||||||
**Signature:**
|
**Signature:**
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ sidebar_label: JSHandle.evaluate
|
|||||||
|
|
||||||
# JSHandle.evaluate() method
|
# JSHandle.evaluate() method
|
||||||
|
|
||||||
This method passes this handle as the first argument to `pageFunction`. If `pageFunction` returns a Promise, then `handle.evaluate` would wait for the promise to resolve and return its value.
|
Evaluates the given function with the current handle as its first argument.
|
||||||
|
|
||||||
**Signature:**
|
**Signature:**
|
||||||
|
|
||||||
@ -32,10 +32,3 @@ class JSHandle {
|
|||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
Promise<Awaited<ReturnType<Func>>>
|
Promise<Awaited<ReturnType<Func>>>
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
```ts
|
|
||||||
const tweetHandle = await page.$('.tweet .retweets');
|
|
||||||
expect(await tweetHandle.evaluate(node => node.innerText)).toBe('10');
|
|
||||||
```
|
|
||||||
|
@ -4,7 +4,7 @@ sidebar_label: JSHandle.evaluateHandle
|
|||||||
|
|
||||||
# JSHandle.evaluateHandle() method
|
# JSHandle.evaluateHandle() method
|
||||||
|
|
||||||
This method passes this handle as the first argument to `pageFunction`.
|
Evaluates the given function with the current handle as its first argument.
|
||||||
|
|
||||||
**Signature:**
|
**Signature:**
|
||||||
|
|
||||||
@ -32,11 +32,3 @@ class JSHandle {
|
|||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
Promise<[HandleFor](./puppeteer.handlefor.md)<Awaited<ReturnType<Func>>>>
|
Promise<[HandleFor](./puppeteer.handlefor.md)<Awaited<ReturnType<Func>>>>
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
The only difference between `jsHandle.evaluate` and `jsHandle.evaluateHandle` is that `jsHandle.evaluateHandle` returns an in-page object (JSHandle).
|
|
||||||
|
|
||||||
If the function passed to `jsHandle.evaluateHandle` returns a Promise, then `evaluateHandle.evaluateHandle` waits for the promise to resolve and returns its value.
|
|
||||||
|
|
||||||
See [Page.evaluateHandle()](./puppeteer.page.evaluatehandle.md) for more details.
|
|
||||||
|
@ -4,8 +4,6 @@ sidebar_label: JSHandle.executionContext
|
|||||||
|
|
||||||
# JSHandle.executionContext() method
|
# JSHandle.executionContext() method
|
||||||
|
|
||||||
Returns the execution context the handle belongs to.
|
|
||||||
|
|
||||||
**Signature:**
|
**Signature:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
@ -17,3 +15,5 @@ class JSHandle {
|
|||||||
**Returns:**
|
**Returns:**
|
||||||
|
|
||||||
[ExecutionContext](./puppeteer.executioncontext.md)
|
[ExecutionContext](./puppeteer.executioncontext.md)
|
||||||
|
|
||||||
|
The execution context the handle belongs to.
|
||||||
|
@ -4,7 +4,7 @@ sidebar_label: JSHandle.getProperties
|
|||||||
|
|
||||||
# JSHandle.getProperties() method
|
# JSHandle.getProperties() method
|
||||||
|
|
||||||
The method returns a map with property names as keys and JSHandle instances for the property values.
|
Gets a map of handles representing the properties of the current handle.
|
||||||
|
|
||||||
**Signature:**
|
**Signature:**
|
||||||
|
|
||||||
@ -26,7 +26,9 @@ const properties = await listHandle.getProperties();
|
|||||||
const children = [];
|
const children = [];
|
||||||
for (const property of properties.values()) {
|
for (const property of properties.values()) {
|
||||||
const element = property.asElement();
|
const element = property.asElement();
|
||||||
if (element) children.push(element);
|
if (element) {
|
||||||
|
children.push(element);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
children; // holds elementHandles to all children of document.body
|
children; // holds elementHandles to all children of document.body
|
||||||
```
|
```
|
||||||
|
@ -8,7 +8,7 @@ sidebar_label: JSHandle.jsonValue
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
class JSHandle {
|
class JSHandle {
|
||||||
jsonValue<T = unknown>(): Promise<T>;
|
jsonValue(): Promise<T>;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -16,8 +16,12 @@ class JSHandle {
|
|||||||
|
|
||||||
Promise<T>
|
Promise<T>
|
||||||
|
|
||||||
Returns a JSON representation of the object.If the object has a `toJSON` function, it will not be called.
|
A vanilla object representing the serializable portions of the referenced object.
|
||||||
|
|
||||||
|
## Exceptions
|
||||||
|
|
||||||
|
Throws if the object cannot be serialized due to circularity.
|
||||||
|
|
||||||
## Remarks
|
## Remarks
|
||||||
|
|
||||||
The JSON is generated by running [JSON.stringify](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) on the object in page and consequent [JSON.parse](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse) in puppeteer. \*\*NOTE\*\* The method throws if the referenced object is not stringifiable.
|
If the object has a `toJSON` function, it \*will not\* be called.
|
||||||
|
@ -4,7 +4,11 @@ sidebar_label: JSHandle
|
|||||||
|
|
||||||
# JSHandle class
|
# JSHandle class
|
||||||
|
|
||||||
Represents an in-page JavaScript object. JSHandles can be created with the [page.evaluateHandle](./puppeteer.page.evaluatehandle.md) method.
|
Represents a reference to a JavaScript object. Instances can be created using [Page.evaluateHandle()](./puppeteer.page.evaluatehandle.md).
|
||||||
|
|
||||||
|
Handles prevent the referenced JavaScript object from being garbage-collected unless the handle is purposely [disposed](./puppeteer.jshandle.dispose.md). JSHandles are auto-disposed when their associated frame is navigated away or the parent context gets destroyed.
|
||||||
|
|
||||||
|
Handles can be used as arguments for any evaluation function such as [Page.$eval()](./puppeteer.page._eval.md), [Page.evaluate()](./puppeteer.page.evaluate.md), and [Page.evaluateHandle()](./puppeteer.page.evaluatehandle.md). They are resolved to their referenced object.
|
||||||
|
|
||||||
**Signature:**
|
**Signature:**
|
||||||
|
|
||||||
@ -22,10 +26,6 @@ The constructor for this class is marked as internal. Third-party code should no
|
|||||||
const windowHandle = await page.evaluateHandle(() => window);
|
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.$eval()](./puppeteer.page._eval.md), [Page.evaluate()](./puppeteer.page.evaluate.md), and [Page.evaluateHandle()](./puppeteer.page.evaluatehandle.md).
|
|
||||||
|
|
||||||
## Properties
|
## Properties
|
||||||
|
|
||||||
| Property | Modifiers | Type | Description |
|
| Property | Modifiers | Type | Description |
|
||||||
@ -34,16 +34,16 @@ JSHandle instances can be used as arguments for [Page.$eval()](./puppeteer.page.
|
|||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
| Method | Modifiers | Description |
|
| Method | Modifiers | Description |
|
||||||
| ---------------------------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ---------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| [asElement()](./puppeteer.jshandle.aselement.md) | | |
|
| [asElement()](./puppeteer.jshandle.aselement.md) | | |
|
||||||
| [dispose()](./puppeteer.jshandle.dispose.md) | | Stops referencing the element handle, and resolves when the object handle is successfully disposed of. |
|
| [dispose()](./puppeteer.jshandle.dispose.md) | | Releases the object referenced by the handle for garbage collection. |
|
||||||
| [evaluate(pageFunction, args)](./puppeteer.jshandle.evaluate.md) | | This method passes this handle as the first argument to <code>pageFunction</code>. If <code>pageFunction</code> returns a Promise, then <code>handle.evaluate</code> would wait for the promise to resolve and return its value. |
|
| [evaluate(pageFunction, args)](./puppeteer.jshandle.evaluate.md) | | Evaluates the given function with the current handle as its first argument. |
|
||||||
| [evaluateHandle(pageFunction, args)](./puppeteer.jshandle.evaluatehandle.md) | | This method passes this handle as the first argument to <code>pageFunction</code>. |
|
| [evaluateHandle(pageFunction, args)](./puppeteer.jshandle.evaluatehandle.md) | | Evaluates the given function with the current handle as its first argument. |
|
||||||
| [executionContext()](./puppeteer.jshandle.executioncontext.md) | | Returns the execution context the handle belongs to. |
|
| [executionContext()](./puppeteer.jshandle.executioncontext.md) | | |
|
||||||
| [getProperties()](./puppeteer.jshandle.getproperties.md) | | The method returns a map with property names as keys and JSHandle instances for the property values. |
|
| [getProperties()](./puppeteer.jshandle.getproperties.md) | | Gets a map of handles representing the properties of the current handle. |
|
||||||
| [getProperty(propertyName)](./puppeteer.jshandle.getproperty.md) | | Fetches a single property from the referenced object. |
|
| [getProperty(propertyName)](./puppeteer.jshandle.getproperty.md) | | Fetches a single property from the referenced object. |
|
||||||
| [getProperty(propertyName)](./puppeteer.jshandle.getproperty_1.md) | | |
|
| [getProperty(propertyName)](./puppeteer.jshandle.getproperty_1.md) | | |
|
||||||
| [jsonValue()](./puppeteer.jshandle.jsonvalue.md) | | |
|
| [jsonValue()](./puppeteer.jshandle.jsonvalue.md) | | |
|
||||||
| [remoteObject()](./puppeteer.jshandle.remoteobject.md) | | Provides access to \[Protocol.Runtime.RemoteObject\](https://chromedevtools.github.io/devtools-protocol/tot/Runtime/\#type-RemoteObject) backing this JSHandle. |
|
| [remoteObject()](./puppeteer.jshandle.remoteobject.md) | | Provides access to the \[Protocol.Runtime.RemoteObject\](https://chromedevtools.github.io/devtools-protocol/tot/Runtime/\#type-RemoteObject) backing this handle. |
|
||||||
| [toString()](./puppeteer.jshandle.tostring.md) | | Returns a string representation of the JSHandle. |
|
| [toString()](./puppeteer.jshandle.tostring.md) | | Returns a string representation of the JSHandle. |
|
||||||
|
@ -4,7 +4,7 @@ sidebar_label: JSHandle.remoteObject
|
|||||||
|
|
||||||
# JSHandle.remoteObject() method
|
# JSHandle.remoteObject() method
|
||||||
|
|
||||||
Provides access to \[Protocol.Runtime.RemoteObject\](https://chromedevtools.github.io/devtools-protocol/tot/Runtime/\#type-RemoteObject) backing this JSHandle.
|
Provides access to the \[Protocol.Runtime.RemoteObject\](https://chromedevtools.github.io/devtools-protocol/tot/Runtime/\#type-RemoteObject) backing this handle.
|
||||||
|
|
||||||
**Signature:**
|
**Signature:**
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ export class Accessibility {
|
|||||||
let backendNodeId: number | undefined;
|
let backendNodeId: number | undefined;
|
||||||
if (root) {
|
if (root) {
|
||||||
const {node} = await this.#client.send('DOM.describeNode', {
|
const {node} = await this.#client.send('DOM.describeNode', {
|
||||||
objectId: root._remoteObject.objectId,
|
objectId: root.remoteObject().objectId,
|
||||||
});
|
});
|
||||||
backendNodeId = node.backendNodeId;
|
backendNodeId = node.backendNodeId;
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ async function queryAXTree(
|
|||||||
role?: string
|
role?: string
|
||||||
): Promise<Protocol.Accessibility.AXNode[]> {
|
): Promise<Protocol.Accessibility.AXNode[]> {
|
||||||
const {nodes} = await client.send('Accessibility.queryAXTree', {
|
const {nodes} = await client.send('Accessibility.queryAXTree', {
|
||||||
objectId: element._remoteObject.objectId,
|
objectId: element.remoteObject().objectId,
|
||||||
accessibleName,
|
accessibleName,
|
||||||
role,
|
role,
|
||||||
});
|
});
|
||||||
|
@ -277,7 +277,7 @@ export class ElementHandle<
|
|||||||
selector: Selector,
|
selector: Selector,
|
||||||
options: Exclude<WaitForSelectorOptions, 'root'> = {}
|
options: Exclude<WaitForSelectorOptions, 'root'> = {}
|
||||||
): Promise<ElementHandle<NodeFor<Selector>> | null> {
|
): Promise<ElementHandle<NodeFor<Selector>> | null> {
|
||||||
const frame = this._context.frame();
|
const frame = this.executionContext().frame();
|
||||||
assert(frame);
|
assert(frame);
|
||||||
const adoptedRoot = await frame.worlds[PUPPETEER_WORLD].adoptHandle(this);
|
const adoptedRoot = await frame.worlds[PUPPETEER_WORLD].adoptHandle(this);
|
||||||
const handle = await frame.worlds[PUPPETEER_WORLD].waitForSelector(
|
const handle = await frame.worlds[PUPPETEER_WORLD].waitForSelector(
|
||||||
@ -376,8 +376,8 @@ export class ElementHandle<
|
|||||||
* iframe nodes, or null otherwise
|
* iframe nodes, or null otherwise
|
||||||
*/
|
*/
|
||||||
async contentFrame(): Promise<Frame | null> {
|
async contentFrame(): Promise<Frame | null> {
|
||||||
const nodeInfo = await this._client.send('DOM.describeNode', {
|
const nodeInfo = await this.client.send('DOM.describeNode', {
|
||||||
objectId: this._remoteObject.objectId,
|
objectId: this.remoteObject().objectId,
|
||||||
});
|
});
|
||||||
if (typeof nodeInfo.node.frameId !== 'string') {
|
if (typeof nodeInfo.node.frameId !== 'string') {
|
||||||
return null;
|
return null;
|
||||||
@ -403,8 +403,8 @@ export class ElementHandle<
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this._client.send('DOM.scrollIntoViewIfNeeded', {
|
await this.client.send('DOM.scrollIntoViewIfNeeded', {
|
||||||
objectId: this._remoteObject.objectId,
|
objectId: this.remoteObject().objectId,
|
||||||
});
|
});
|
||||||
} catch (_err) {
|
} catch (_err) {
|
||||||
// Fallback to Element.scrollIntoView if DOM.scrollIntoViewIfNeeded is not supported
|
// Fallback to Element.scrollIntoView if DOM.scrollIntoViewIfNeeded is not supported
|
||||||
@ -470,9 +470,9 @@ export class ElementHandle<
|
|||||||
*/
|
*/
|
||||||
async clickablePoint(offset?: Offset): Promise<Point> {
|
async clickablePoint(offset?: Offset): Promise<Point> {
|
||||||
const [result, layoutMetrics] = await Promise.all([
|
const [result, layoutMetrics] = await Promise.all([
|
||||||
this._client
|
this.client
|
||||||
.send('DOM.getContentQuads', {
|
.send('DOM.getContentQuads', {
|
||||||
objectId: this._remoteObject.objectId,
|
objectId: this.remoteObject().objectId,
|
||||||
})
|
})
|
||||||
.catch(debugError),
|
.catch(debugError),
|
||||||
this.#page._client().send('Page.getLayoutMetrics'),
|
this.#page._client().send('Page.getLayoutMetrics'),
|
||||||
@ -539,9 +539,9 @@ export class ElementHandle<
|
|||||||
|
|
||||||
#getBoxModel(): Promise<void | Protocol.DOM.GetBoxModelResponse> {
|
#getBoxModel(): Promise<void | Protocol.DOM.GetBoxModelResponse> {
|
||||||
const params: Protocol.DOM.GetBoxModelRequest = {
|
const params: Protocol.DOM.GetBoxModelRequest = {
|
||||||
objectId: this._remoteObject.objectId,
|
objectId: this.remoteObject().objectId,
|
||||||
};
|
};
|
||||||
return this._client.send('DOM.getBoxModel', params).catch(error => {
|
return this.client.send('DOM.getBoxModel', params).catch(error => {
|
||||||
return debugError(error);
|
return debugError(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -758,8 +758,8 @@ export class ElementHandle<
|
|||||||
return path.resolve(filePath);
|
return path.resolve(filePath);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const {objectId} = this._remoteObject;
|
const {objectId} = this.remoteObject();
|
||||||
const {node} = await this._client.send('DOM.describeNode', {objectId});
|
const {node} = await this.client.send('DOM.describeNode', {objectId});
|
||||||
const {backendNodeId} = node;
|
const {backendNodeId} = node;
|
||||||
|
|
||||||
/* The zero-length array is a special case, it seems that
|
/* The zero-length array is a special case, it seems that
|
||||||
@ -775,7 +775,7 @@ export class ElementHandle<
|
|||||||
element.dispatchEvent(new Event('change', {bubbles: true}));
|
element.dispatchEvent(new Event('change', {bubbles: true}));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await this._client.send('DOM.setFileInputFiles', {
|
await this.client.send('DOM.setFileInputFiles', {
|
||||||
objectId,
|
objectId,
|
||||||
files,
|
files,
|
||||||
backendNodeId,
|
backendNodeId,
|
||||||
@ -954,7 +954,7 @@ export class ElementHandle<
|
|||||||
assert(boundingBox.width !== 0, 'Node has 0 width.');
|
assert(boundingBox.width !== 0, 'Node has 0 width.');
|
||||||
assert(boundingBox.height !== 0, 'Node has 0 height.');
|
assert(boundingBox.height !== 0, 'Node has 0 height.');
|
||||||
|
|
||||||
const layoutMetrics = await this._client.send('Page.getLayoutMetrics');
|
const layoutMetrics = await this.client.send('Page.getLayoutMetrics');
|
||||||
// Fallback to `layoutViewport` in case of using Firefox.
|
// Fallback to `layoutViewport` in case of using Firefox.
|
||||||
const {pageX, pageY} =
|
const {pageX, pageY} =
|
||||||
layoutMetrics.cssVisualViewport || layoutMetrics.layoutViewport;
|
layoutMetrics.cssVisualViewport || layoutMetrics.layoutViewport;
|
||||||
|
@ -17,16 +17,15 @@
|
|||||||
import {Protocol} from 'devtools-protocol';
|
import {Protocol} from 'devtools-protocol';
|
||||||
import {assert} from './assert.js';
|
import {assert} from './assert.js';
|
||||||
import {CDPSession} from './Connection.js';
|
import {CDPSession} from './Connection.js';
|
||||||
import {IsolatedWorld} from './IsolatedWorld.js';
|
|
||||||
import {ElementHandle} from './ElementHandle.js';
|
|
||||||
import {Frame} from './FrameManager.js';
|
import {Frame} from './FrameManager.js';
|
||||||
|
import {IsolatedWorld} from './IsolatedWorld.js';
|
||||||
import {JSHandle} from './JSHandle.js';
|
import {JSHandle} from './JSHandle.js';
|
||||||
import {EvaluateFunc, HandleFor} from './types.js';
|
import {EvaluateFunc, HandleFor} from './types.js';
|
||||||
import {
|
import {
|
||||||
|
createJSHandle,
|
||||||
getExceptionMessage,
|
getExceptionMessage,
|
||||||
isString,
|
isString,
|
||||||
valueFromRemoteObject,
|
valueFromRemoteObject,
|
||||||
createJSHandle,
|
|
||||||
} from './util.js';
|
} from './util.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -36,18 +35,24 @@ export const EVALUATION_SCRIPT_URL = 'pptr://__puppeteer_evaluation_script__';
|
|||||||
const SOURCE_URL_REGEX = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/m;
|
const SOURCE_URL_REGEX = /^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$/m;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents a context for JavaScript execution. A [Page] might have
|
* Represents a context for JavaScript execution.
|
||||||
* many execution contexts:
|
|
||||||
* - each {@link
|
|
||||||
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe | frame}
|
|
||||||
* has "default" execution context that is always created after frame is
|
|
||||||
* attached to DOM. This context is returned by the
|
|
||||||
* {@link Frame.executionContext} method.
|
|
||||||
* - {@link https://developer.chrome.com/extensions | Extension}'s content
|
|
||||||
* scripts create additional execution contexts.
|
|
||||||
*
|
*
|
||||||
* Besides pages, execution contexts can be found in {@link
|
* @example
|
||||||
* https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API | workers}.
|
* A {@link Page} can have several execution contexts:
|
||||||
|
*
|
||||||
|
* - Each {@link Frame} of a {@link Page | page} has a "default" execution
|
||||||
|
* context that is always created after frame is attached to DOM. This context
|
||||||
|
* is returned by the {@link Frame.executionContext} method.
|
||||||
|
* - Each {@link https://developer.chrome.com/extensions | Chrome extensions}
|
||||||
|
* creates additional execution contexts to isolate their code.
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* By definition, each context is isolated from one another, however they are
|
||||||
|
* all able to manipulate non-JavaScript resources (such as DOM).
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* Besides pages, execution contexts can be found in
|
||||||
|
* {@link WebWorker | workers}.
|
||||||
*/
|
*/
|
||||||
export class ExecutionContext {
|
export class ExecutionContext {
|
||||||
/**
|
/**
|
||||||
@ -82,28 +87,19 @@ export class ExecutionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @remarks
|
|
||||||
*
|
|
||||||
* Not every execution context is associated with a frame. For example,
|
|
||||||
* workers and extensions have execution contexts that are not associated with
|
|
||||||
* frames.
|
|
||||||
*
|
|
||||||
* @returns The frame associated with this execution context.
|
* @returns The frame associated with this execution context.
|
||||||
|
*
|
||||||
|
* @remarks
|
||||||
|
* Not every execution context is associated with a frame. For example,
|
||||||
|
* {@link WebWorker | workers} have execution contexts that are not associated
|
||||||
|
* with frames.
|
||||||
*/
|
*/
|
||||||
frame(): Frame | null {
|
frame(): Frame | null {
|
||||||
return this._world ? this._world.frame() : null;
|
return this._world ? this._world.frame() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @remarks
|
* Evaluates the given function.
|
||||||
* If the function passed to the `executionContext.evaluate` returns a
|
|
||||||
* Promise, then `executionContext.evaluate` would wait for the promise to
|
|
||||||
* resolve and return its value. If the function passed to the
|
|
||||||
* `executionContext.evaluate` returns a non-serializable value, then
|
|
||||||
* `executionContext.evaluate` resolves to `undefined`. DevTools Protocol also
|
|
||||||
* supports transferring some additional values that are not serializable by
|
|
||||||
* `JSON`: `-0`, `NaN`, `Infinity`, `-Infinity`, and bigint literals.
|
|
||||||
*
|
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* ```ts
|
* ```ts
|
||||||
@ -113,29 +109,29 @@ export class ExecutionContext {
|
|||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* A string can also be passed in instead of a function.
|
* A string can also be passed in instead of a function:
|
||||||
*
|
|
||||||
* ```ts
|
* ```ts
|
||||||
* console.log(await executionContext.evaluate('1 + 2')); // prints "3"
|
* console.log(await executionContext.evaluate('1 + 2')); // prints "3"
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* {@link JSHandle} instances can be passed as arguments to the
|
* Handles can also be passed as `args`. They resolve to their referenced object:
|
||||||
* `executionContext.* evaluate`:
|
|
||||||
* ```ts
|
* ```ts
|
||||||
* const oneHandle = await executionContext.evaluateHandle(() => 1);
|
* const oneHandle = await executionContext.evaluateHandle(() => 1);
|
||||||
* const twoHandle = await executionContext.evaluateHandle(() => 2);
|
* const twoHandle = await executionContext.evaluateHandle(() => 2);
|
||||||
* const result = await executionContext.evaluate(
|
* const result = await executionContext.evaluate(
|
||||||
* (a, b) => a + b, oneHandle, * twoHandle
|
* (a, b) => a + b, oneHandle, twoHandle
|
||||||
* );
|
* );
|
||||||
* await oneHandle.dispose();
|
* await oneHandle.dispose();
|
||||||
* await twoHandle.dispose();
|
* await twoHandle.dispose();
|
||||||
* console.log(result); // prints '3'.
|
* console.log(result); // prints '3'.
|
||||||
* ```
|
* ```
|
||||||
* @param pageFunction - a function to be evaluated in the `executionContext`
|
|
||||||
* @param args - argument to pass to the page function
|
|
||||||
*
|
*
|
||||||
* @returns A promise that resolves to the return value of the given function.
|
* @param pageFunction - The function to evaluate.
|
||||||
|
* @param args - Additional arguments to pass into the function.
|
||||||
|
* @returns The result of evaluating the function. If the result is an object,
|
||||||
|
* a vanilla object containing the serializable properties of the result is
|
||||||
|
* returned.
|
||||||
*/
|
*/
|
||||||
async evaluate<
|
async evaluate<
|
||||||
Params extends unknown[],
|
Params extends unknown[],
|
||||||
@ -148,46 +144,51 @@ export class ExecutionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @remarks
|
* Evaluates the given function.
|
||||||
* The only difference between `executionContext.evaluate` and
|
*
|
||||||
* `executionContext.evaluateHandle` is that `executionContext.evaluateHandle`
|
* Unlike {@link ExecutionContext.evaluate | evaluate}, this method returns a
|
||||||
* returns an in-page object (a {@link JSHandle}).
|
* handle to the result of the function.
|
||||||
* If the function passed to the `executionContext.evaluateHandle` returns a
|
*
|
||||||
* Promise, then `executionContext.evaluateHandle` would wait for the
|
* This method may be better suited if the object cannot be serialized (e.g.
|
||||||
* promise to resolve and return its value.
|
* `Map`) and requires further manipulation.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* ```ts
|
* ```ts
|
||||||
* const context = await page.mainFrame().executionContext();
|
* const context = await page.mainFrame().executionContext();
|
||||||
* const aHandle = await context.evaluateHandle(() => Promise.resolve(self));
|
* const handle: JSHandle<typeof globalThis> = await context.evaluateHandle(() =>
|
||||||
* aHandle; // Handle for the global object.
|
* Promise.resolve(self)
|
||||||
|
* );
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* A string can also be passed in instead of a function.
|
* A string can also be passed in instead of a function.
|
||||||
*
|
|
||||||
* ```ts
|
* ```ts
|
||||||
* // Handle for the '3' * object.
|
* const handle: JSHandle<number> = await context.evaluateHandle('1 + 2');
|
||||||
* const aHandle = await context.evaluateHandle('1 + 2');
|
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* JSHandle instances can be passed as arguments
|
* Handles can also be passed as `args`. They resolve to their referenced object:
|
||||||
* to the `executionContext.* evaluateHandle`:
|
|
||||||
*
|
|
||||||
* ```ts
|
* ```ts
|
||||||
* const aHandle = await context.evaluateHandle(() => document.body);
|
* const bodyHandle: ElementHandle<HTMLBodyElement> = await context.evaluateHandle(
|
||||||
* const resultHandle = await context.evaluateHandle(body => body.innerHTML, * aHandle);
|
* () => {
|
||||||
* console.log(await resultHandle.jsonValue()); // prints body's innerHTML
|
* return document.body;
|
||||||
* await aHandle.dispose();
|
* }
|
||||||
* await resultHandle.dispose();
|
* );
|
||||||
|
* const stringHandle: JSHandle<string> = await context.evaluateHandle(
|
||||||
|
* body => body.innerHTML,
|
||||||
|
* body
|
||||||
|
* );
|
||||||
|
* console.log(await stringHandle.jsonValue()); // prints body's innerHTML
|
||||||
|
* // Always dispose your garbage! :)
|
||||||
|
* await bodyHandle.dispose();
|
||||||
|
* await stringHandle.dispose();
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @param pageFunction - a function to be evaluated in the `executionContext`
|
* @param pageFunction - The function to evaluate.
|
||||||
* @param args - argument to pass to the page function
|
* @param args - Additional arguments to pass into the function.
|
||||||
*
|
* @returns A {@link JSHandle | handle} to the result of evaluating the
|
||||||
* @returns A promise that resolves to the return value of the given function
|
* function. If the result is a `Node`, then this will return an
|
||||||
* as an in-page object (a {@link JSHandle}).
|
* {@link ElementHandle | element handle}.
|
||||||
*/
|
*/
|
||||||
async evaluateHandle<
|
async evaluateHandle<
|
||||||
Params extends unknown[],
|
Params extends unknown[],
|
||||||
@ -253,12 +254,6 @@ export class ExecutionContext {
|
|||||||
: createJSHandle(this, remoteObject);
|
: createJSHandle(this, remoteObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof pageFunction !== 'function') {
|
|
||||||
throw new Error(
|
|
||||||
`Expected to get |string| or |function| as the first argument, but got "${pageFunction}" instead.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let functionText = pageFunction.toString();
|
let functionText = pageFunction.toString();
|
||||||
try {
|
try {
|
||||||
new Function('(' + functionText + ')');
|
new Function('(' + functionText + ')');
|
||||||
@ -330,23 +325,24 @@ export class ExecutionContext {
|
|||||||
}
|
}
|
||||||
const objectHandle = arg && arg instanceof JSHandle ? arg : null;
|
const objectHandle = arg && arg instanceof JSHandle ? arg : null;
|
||||||
if (objectHandle) {
|
if (objectHandle) {
|
||||||
if (objectHandle._context !== this) {
|
if (objectHandle.executionContext() !== this) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'JSHandles can be evaluated only in the context they were created!'
|
'JSHandles can be evaluated only in the context they were created!'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (objectHandle._disposed) {
|
if (objectHandle.disposed) {
|
||||||
throw new Error('JSHandle is disposed!');
|
throw new Error('JSHandle is disposed!');
|
||||||
}
|
}
|
||||||
if (objectHandle._remoteObject.unserializableValue) {
|
if (objectHandle.remoteObject().unserializableValue) {
|
||||||
return {
|
return {
|
||||||
unserializableValue: objectHandle._remoteObject.unserializableValue,
|
unserializableValue:
|
||||||
|
objectHandle.remoteObject().unserializableValue,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (!objectHandle._remoteObject.objectId) {
|
if (!objectHandle.remoteObject().objectId) {
|
||||||
return {value: objectHandle._remoteObject.value};
|
return {value: objectHandle.remoteObject().value};
|
||||||
}
|
}
|
||||||
return {objectId: objectHandle._remoteObject.objectId};
|
return {objectId: objectHandle.remoteObject().objectId};
|
||||||
}
|
}
|
||||||
return {value: arg};
|
return {value: arg};
|
||||||
}
|
}
|
||||||
@ -372,9 +368,9 @@ export class ExecutionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method iterates the JavaScript heap and finds all the objects with the
|
* Iterates through the JavaScript heap and finds all the objects with the
|
||||||
* given prototype.
|
* given prototype.
|
||||||
* @remarks
|
*
|
||||||
* @example
|
* @example
|
||||||
* ```ts
|
* ```ts
|
||||||
* // Create a Map object
|
* // Create a Map object
|
||||||
@ -390,33 +386,20 @@ export class ExecutionContext {
|
|||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @param prototypeHandle - a handle to the object prototype
|
* @param prototypeHandle - a handle to the object prototype
|
||||||
*
|
|
||||||
* @returns A handle to an array of objects with the given prototype.
|
* @returns A handle to an array of objects with the given prototype.
|
||||||
*/
|
*/
|
||||||
async queryObjects<Prototype>(
|
async queryObjects<Prototype>(
|
||||||
prototypeHandle: JSHandle<Prototype>
|
prototypeHandle: JSHandle<Prototype>
|
||||||
): Promise<HandleFor<Prototype[]>> {
|
): Promise<HandleFor<Prototype[]>> {
|
||||||
assert(!prototypeHandle._disposed, 'Prototype JSHandle is disposed!');
|
assert(!prototypeHandle.disposed, 'Prototype JSHandle is disposed!');
|
||||||
|
const remoteObject = prototypeHandle.remoteObject();
|
||||||
assert(
|
assert(
|
||||||
prototypeHandle._remoteObject.objectId,
|
remoteObject.objectId,
|
||||||
'Prototype JSHandle must not be referencing primitive value'
|
'Prototype JSHandle must not be referencing primitive value'
|
||||||
);
|
);
|
||||||
const response = await this._client.send('Runtime.queryObjects', {
|
const response = await this._client.send('Runtime.queryObjects', {
|
||||||
prototypeObjectId: prototypeHandle._remoteObject.objectId,
|
prototypeObjectId: remoteObject.objectId,
|
||||||
});
|
});
|
||||||
return createJSHandle(this, response.objects) as HandleFor<Prototype[]>;
|
return createJSHandle(this, response.objects) as HandleFor<Prototype[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
async _adoptBackendNodeId(
|
|
||||||
backendNodeId?: Protocol.DOM.BackendNodeId
|
|
||||||
): Promise<ElementHandle<Node>> {
|
|
||||||
const {object} = await this._client.send('DOM.resolveNode', {
|
|
||||||
backendNodeId: backendNodeId,
|
|
||||||
executionContextId: this._contextId,
|
|
||||||
});
|
|
||||||
return createJSHandle(this, object) as ElementHandle<Node>;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -789,7 +789,7 @@ export class IsolatedWorld {
|
|||||||
'Cannot adopt handle that already belongs to this execution context'
|
'Cannot adopt handle that already belongs to this execution context'
|
||||||
);
|
);
|
||||||
const nodeInfo = await this.#client.send('DOM.describeNode', {
|
const nodeInfo = await this.#client.send('DOM.describeNode', {
|
||||||
objectId: handle._remoteObject.objectId,
|
objectId: handle.remoteObject().objectId,
|
||||||
});
|
});
|
||||||
return (await this.adoptBackendNode(nodeInfo.node.backendNodeId)) as T;
|
return (await this.adoptBackendNode(nodeInfo.node.backendNodeId)) as T;
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,11 @@
|
|||||||
import {Protocol} from 'devtools-protocol';
|
import {Protocol} from 'devtools-protocol';
|
||||||
import {assert} from './assert.js';
|
import {assert} from './assert.js';
|
||||||
import {CDPSession} from './Connection.js';
|
import {CDPSession} from './Connection.js';
|
||||||
import {EvaluateFunc, HandleFor, HandleOr} from './types.js';
|
import type {ElementHandle} from './ElementHandle.js';
|
||||||
import {ExecutionContext} from './ExecutionContext.js';
|
import {ExecutionContext} from './ExecutionContext.js';
|
||||||
import {MouseButton} from './Input.js';
|
import {MouseButton} from './Input.js';
|
||||||
import {releaseObject, valueFromRemoteObject, createJSHandle} from './util.js';
|
import {EvaluateFunc, HandleFor, HandleOr} from './types.js';
|
||||||
import type {ElementHandle} from './ElementHandle.js';
|
import {createJSHandle, releaseObject, valueFromRemoteObject} from './util.js';
|
||||||
|
|
||||||
declare const __JSHandleSymbol: unique symbol;
|
declare const __JSHandleSymbol: unique symbol;
|
||||||
|
|
||||||
@ -52,21 +52,23 @@ export interface BoundingBox extends Point {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an in-page JavaScript object. JSHandles can be created with the
|
* Represents a reference to a JavaScript object. Instances can be created using
|
||||||
* {@link Page.evaluateHandle | page.evaluateHandle} method.
|
* {@link Page.evaluateHandle}.
|
||||||
|
*
|
||||||
|
* Handles prevent the referenced JavaScript object from being garbage-collected
|
||||||
|
* unless the handle is purposely {@link JSHandle.dispose | disposed}. JSHandles
|
||||||
|
* are auto-disposed when their associated frame is navigated away or the parent
|
||||||
|
* context gets destroyed.
|
||||||
|
*
|
||||||
|
* Handles can be used as arguments for any evaluation function such as
|
||||||
|
* {@link Page.$eval}, {@link Page.evaluate}, and {@link Page.evaluateHandle}.
|
||||||
|
* They are resolved to their referenced object.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* ```ts
|
* ```ts
|
||||||
* const windowHandle = await page.evaluateHandle(() => window);
|
* const windowHandle = await page.evaluateHandle(() => window);
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* JSHandle prevents the referenced JavaScript object from being garbage-collected
|
|
||||||
* unless the handle is {@link JSHandle.dispose | disposed}. JSHandles are auto-
|
|
||||||
* disposed when their origin frame gets navigated or the parent context gets destroyed.
|
|
||||||
*
|
|
||||||
* JSHandle instances can be used as arguments for {@link Page.$eval},
|
|
||||||
* {@link Page.evaluate}, and {@link Page.evaluateHandle}.
|
|
||||||
*
|
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export class JSHandle<T = unknown> {
|
export class JSHandle<T = unknown> {
|
||||||
@ -83,31 +85,17 @@ export class JSHandle<T = unknown> {
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
get _client(): CDPSession {
|
get client(): CDPSession {
|
||||||
return this.#client;
|
return this.#client;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
get _disposed(): boolean {
|
get disposed(): boolean {
|
||||||
return this.#disposed;
|
return this.#disposed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
get _remoteObject(): Protocol.Runtime.RemoteObject {
|
|
||||||
return this.#remoteObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
get _context(): ExecutionContext {
|
|
||||||
return this.#context;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@ -121,24 +109,18 @@ export class JSHandle<T = unknown> {
|
|||||||
this.#remoteObject = remoteObject;
|
this.#remoteObject = remoteObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the execution context the handle belongs to.
|
/**
|
||||||
|
* @returns The execution context the handle belongs to.
|
||||||
*/
|
*/
|
||||||
executionContext(): ExecutionContext {
|
executionContext(): ExecutionContext {
|
||||||
return this.#context;
|
return this.#context;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method passes this handle as the first argument to `pageFunction`. If
|
* Evaluates the given function with the current handle as its first argument.
|
||||||
* `pageFunction` returns a Promise, then `handle.evaluate` would wait for the
|
|
||||||
* promise to resolve and return its value.
|
|
||||||
*
|
*
|
||||||
* @example
|
* @see {@link ExecutionContext.evaluate} for more details.
|
||||||
* ```ts
|
|
||||||
* const tweetHandle = await page.$('.tweet .retweets');
|
|
||||||
* expect(await tweetHandle.evaluate(node => node.innerText)).toBe('10');
|
|
||||||
* ```
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async evaluate<
|
async evaluate<
|
||||||
Params extends unknown[],
|
Params extends unknown[],
|
||||||
Func extends EvaluateFunc<[this, ...Params]> = EvaluateFunc<
|
Func extends EvaluateFunc<[this, ...Params]> = EvaluateFunc<
|
||||||
@ -154,19 +136,9 @@ export class JSHandle<T = unknown> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method passes this handle as the first argument to `pageFunction`.
|
* Evaluates the given function with the current handle as its first argument.
|
||||||
*
|
*
|
||||||
* @remarks
|
* @see {@link ExecutionContext.evaluateHandle} for more details.
|
||||||
*
|
|
||||||
* The only difference between `jsHandle.evaluate` and
|
|
||||||
* `jsHandle.evaluateHandle` is that `jsHandle.evaluateHandle` returns an
|
|
||||||
* in-page object (JSHandle).
|
|
||||||
*
|
|
||||||
* If the function passed to `jsHandle.evaluateHandle` returns a Promise, then
|
|
||||||
* `evaluateHandle.evaluateHandle` waits for the promise to resolve and
|
|
||||||
* returns its value.
|
|
||||||
*
|
|
||||||
* See {@link Page.evaluateHandle} for more details.
|
|
||||||
*/
|
*/
|
||||||
async evaluateHandle<
|
async evaluateHandle<
|
||||||
Params extends unknown[],
|
Params extends unknown[],
|
||||||
@ -196,14 +168,13 @@ export class JSHandle<T = unknown> {
|
|||||||
async getProperty<K extends keyof T>(
|
async getProperty<K extends keyof T>(
|
||||||
propertyName: HandleOr<K>
|
propertyName: HandleOr<K>
|
||||||
): Promise<HandleFor<T[K]>> {
|
): Promise<HandleFor<T[K]>> {
|
||||||
return await this.evaluateHandle((object, propertyName) => {
|
return this.evaluateHandle((object, propertyName) => {
|
||||||
return object[propertyName];
|
return object[propertyName];
|
||||||
}, propertyName);
|
}, propertyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The method returns a map with property names as keys and JSHandle instances
|
* Gets a map of handles representing the properties of the current handle.
|
||||||
* for the property values.
|
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* ```ts
|
* ```ts
|
||||||
@ -212,14 +183,17 @@ export class JSHandle<T = unknown> {
|
|||||||
* const children = [];
|
* const children = [];
|
||||||
* for (const property of properties.values()) {
|
* for (const property of properties.values()) {
|
||||||
* const element = property.asElement();
|
* const element = property.asElement();
|
||||||
* if (element)
|
* if (element) {
|
||||||
* children.push(element);
|
* children.push(element);
|
||||||
|
* }
|
||||||
* }
|
* }
|
||||||
* children; // holds elementHandles to all children of document.body
|
* children; // holds elementHandles to all children of document.body
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
async getProperties(): Promise<Map<string, JSHandle>> {
|
async getProperties(): Promise<Map<string, JSHandle>> {
|
||||||
assert(this.#remoteObject.objectId);
|
assert(this.#remoteObject.objectId);
|
||||||
|
// We use Runtime.getProperties rather than iterative building because the
|
||||||
|
// iterative approach might create a distorted snapshot.
|
||||||
const response = await this.#client.send('Runtime.getProperties', {
|
const response = await this.#client.send('Runtime.getProperties', {
|
||||||
objectId: this.#remoteObject.objectId,
|
objectId: this.#remoteObject.objectId,
|
||||||
ownProperties: true,
|
ownProperties: true,
|
||||||
@ -235,41 +209,36 @@ export class JSHandle<T = unknown> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns Returns a JSON representation of the object.If the object has a
|
* @returns A vanilla object representing the serializable portions of the
|
||||||
* `toJSON` function, it will not be called.
|
* referenced object.
|
||||||
* @remarks
|
* @throws Throws if the object cannot be serialized due to circularity.
|
||||||
*
|
*
|
||||||
* The JSON is generated by running {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify | JSON.stringify}
|
* @remarks
|
||||||
* on the object in page and consequent {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse | JSON.parse} in puppeteer.
|
* If the object has a `toJSON` function, it *will not* be called.
|
||||||
* **NOTE** The method throws if the referenced object is not stringifiable.
|
|
||||||
*/
|
*/
|
||||||
async jsonValue<T = unknown>(): Promise<T> {
|
async jsonValue(): Promise<T> {
|
||||||
if (this.#remoteObject.objectId) {
|
if (!this.#remoteObject.objectId) {
|
||||||
const response = await this.#client.send('Runtime.callFunctionOn', {
|
return valueFromRemoteObject(this.#remoteObject);
|
||||||
functionDeclaration: 'function() { return this; }',
|
|
||||||
objectId: this.#remoteObject.objectId,
|
|
||||||
returnByValue: true,
|
|
||||||
awaitPromise: true,
|
|
||||||
});
|
|
||||||
return valueFromRemoteObject(response.result) as T;
|
|
||||||
}
|
}
|
||||||
return valueFromRemoteObject(this.#remoteObject) as T;
|
const value = await this.evaluate(object => {
|
||||||
|
return object;
|
||||||
|
});
|
||||||
|
if (value === undefined) {
|
||||||
|
throw new Error('Could not serialize referenced object');
|
||||||
|
}
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns Either `null` or the object handle itself, if the object
|
* @returns Either `null` or the handle itself if the handle is an
|
||||||
* handle is an instance of {@link ElementHandle}.
|
* instance of {@link ElementHandle}.
|
||||||
*/
|
*/
|
||||||
asElement(): ElementHandle<Node> | null {
|
asElement(): ElementHandle<Node> | null {
|
||||||
/* This always returns null, but subclasses can override this and return an
|
|
||||||
ElementHandle.
|
|
||||||
*/
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops referencing the element handle, and resolves when the object handle is
|
* Releases the object referenced by the handle for garbage collection.
|
||||||
* successfully disposed of.
|
|
||||||
*/
|
*/
|
||||||
async dispose(): Promise<void> {
|
async dispose(): Promise<void> {
|
||||||
if (this.#disposed) {
|
if (this.#disposed) {
|
||||||
@ -282,18 +251,21 @@ export class JSHandle<T = unknown> {
|
|||||||
/**
|
/**
|
||||||
* Returns a string representation of the JSHandle.
|
* Returns a string representation of the JSHandle.
|
||||||
*
|
*
|
||||||
* @remarks Useful during debugging.
|
* @remarks
|
||||||
|
* Useful during debugging.
|
||||||
*/
|
*/
|
||||||
toString(): string {
|
toString(): string {
|
||||||
if (this.#remoteObject.objectId) {
|
if (!this.#remoteObject.objectId) {
|
||||||
const type = this.#remoteObject.subtype || this.#remoteObject.type;
|
return 'JSHandle:' + valueFromRemoteObject(this.#remoteObject);
|
||||||
return 'JSHandle@' + type;
|
|
||||||
}
|
}
|
||||||
return 'JSHandle:' + valueFromRemoteObject(this.#remoteObject);
|
const type = this.#remoteObject.subtype || this.#remoteObject.type;
|
||||||
|
return 'JSHandle@' + type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides access to [Protocol.Runtime.RemoteObject](https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-RemoteObject) backing this JSHandle.
|
* Provides access to the
|
||||||
|
* [Protocol.Runtime.RemoteObject](https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-RemoteObject)
|
||||||
|
* backing this handle.
|
||||||
*/
|
*/
|
||||||
remoteObject(): Protocol.Runtime.RemoteObject {
|
remoteObject(): Protocol.Runtime.RemoteObject {
|
||||||
return this.#remoteObject;
|
return this.#remoteObject;
|
||||||
|
@ -1710,7 +1710,7 @@ export class Page extends EventEmitter {
|
|||||||
}
|
}
|
||||||
const textTokens = [];
|
const textTokens = [];
|
||||||
for (const arg of args) {
|
for (const arg of args) {
|
||||||
const remoteObject = arg._remoteObject;
|
const remoteObject = arg.remoteObject();
|
||||||
if (remoteObject.objectId) {
|
if (remoteObject.objectId) {
|
||||||
textTokens.push(arg.toString());
|
textTokens.push(arg.toString());
|
||||||
} else {
|
} else {
|
||||||
|
@ -353,7 +353,7 @@ describe('Evaluation specs', function () {
|
|||||||
const windowHandle = await page.evaluateHandle(() => {
|
const windowHandle = await page.evaluateHandle(() => {
|
||||||
return window;
|
return window;
|
||||||
});
|
});
|
||||||
const errorText = await windowHandle.jsonValue<string>().catch(error_ => {
|
const errorText = await windowHandle.jsonValue().catch(error_ => {
|
||||||
return error_.message;
|
return error_.message;
|
||||||
});
|
});
|
||||||
const error = await page
|
const error = await page
|
||||||
|
@ -73,14 +73,9 @@ describe('JSHandle', function () {
|
|||||||
test.obj = test;
|
test.obj = test;
|
||||||
let error!: Error;
|
let error!: Error;
|
||||||
await page
|
await page
|
||||||
.evaluateHandle(
|
.evaluateHandle(opts => {
|
||||||
opts => {
|
return opts;
|
||||||
// @ts-expect-error we are deliberately passing a bad type here
|
}, test)
|
||||||
// (nested object)
|
|
||||||
return opts.elem;
|
|
||||||
},
|
|
||||||
{test}
|
|
||||||
)
|
|
||||||
.catch(error_ => {
|
.catch(error_ => {
|
||||||
return (error = error_);
|
return (error = error_);
|
||||||
});
|
});
|
||||||
@ -136,7 +131,7 @@ describe('JSHandle', function () {
|
|||||||
const aHandle = await page.evaluateHandle(() => {
|
const aHandle = await page.evaluateHandle(() => {
|
||||||
return {foo: 'bar'};
|
return {foo: 'bar'};
|
||||||
});
|
});
|
||||||
const json = await aHandle.jsonValue<Record<string, string>>();
|
const json = await aHandle.jsonValue();
|
||||||
expect(json).toEqual({foo: 'bar'});
|
expect(json).toEqual({foo: 'bar'});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -146,7 +141,7 @@ describe('JSHandle', function () {
|
|||||||
const aHandle = await page.evaluateHandle(() => {
|
const aHandle = await page.evaluateHandle(() => {
|
||||||
return ['a', 'b'];
|
return ['a', 'b'];
|
||||||
});
|
});
|
||||||
const json = await aHandle.jsonValue<string[]>();
|
const json = await aHandle.jsonValue();
|
||||||
expect(json).toEqual(['a', 'b']);
|
expect(json).toEqual(['a', 'b']);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -156,8 +151,12 @@ describe('JSHandle', function () {
|
|||||||
const aHandle = await page.evaluateHandle(() => {
|
const aHandle = await page.evaluateHandle(() => {
|
||||||
return 'foo';
|
return 'foo';
|
||||||
});
|
});
|
||||||
const json = await aHandle.jsonValue<string>();
|
expect(await aHandle.jsonValue()).toEqual('foo');
|
||||||
expect(json).toEqual('foo');
|
|
||||||
|
const bHandle = await page.evaluateHandle(() => {
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
expect(await bHandle.jsonValue()).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
itFailsFirefox('should not work with dates', async () => {
|
itFailsFirefox('should not work with dates', async () => {
|
||||||
@ -172,13 +171,19 @@ describe('JSHandle', function () {
|
|||||||
it('should throw for circular objects', async () => {
|
it('should throw for circular objects', async () => {
|
||||||
const {page, isChrome} = getTestState();
|
const {page, isChrome} = getTestState();
|
||||||
|
|
||||||
const windowHandle = await page.evaluateHandle('window');
|
const handle = await page.evaluateHandle(() => {
|
||||||
|
const t: {t?: unknown; g: number} = {g: 1};
|
||||||
|
t.t = t;
|
||||||
|
return t;
|
||||||
|
});
|
||||||
let error!: Error;
|
let error!: Error;
|
||||||
await windowHandle.jsonValue().catch(error_ => {
|
await handle.jsonValue().catch(error_ => {
|
||||||
return (error = error_);
|
return (error = error_);
|
||||||
});
|
});
|
||||||
if (isChrome) {
|
if (isChrome) {
|
||||||
expect(error.message).toContain('Object reference chain is too long');
|
expect(error.message).toContain(
|
||||||
|
'Could not serialize referenced object'
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
expect(error.message).toContain('Object is not serializable');
|
expect(error.message).toContain('Object is not serializable');
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user