mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
chore: refactor JSHandle and ExecutionContext (#8773)
This commit is contained in:
parent
ee2540baef
commit
a238f5758d
@ -6,40 +6,40 @@ sidebar_label: API
|
||||
|
||||
## Classes
|
||||
|
||||
| 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). |
|
||||
| [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. |
|
||||
| [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. |
|
||||
| [Connection](./puppeteer.connection.md) | |
|
||||
| [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. |
|
||||
| [CSSCoverage](./puppeteer.csscoverage.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. |
|
||||
| [ElementHandle](./puppeteer.elementhandle.md) | ElementHandle represents an in-page DOM element. |
|
||||
| [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> |
|
||||
| [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. |
|
||||
| [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. |
|
||||
| [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. |
|
||||
| [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. |
|
||||
| [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. |
|
||||
| [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> |
|
||||
| [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) | |
|
||||
| [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. |
|
||||
| [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). |
|
||||
| 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). |
|
||||
| [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. |
|
||||
| [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. |
|
||||
| [Connection](./puppeteer.connection.md) | |
|
||||
| [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. |
|
||||
| [CSSCoverage](./puppeteer.csscoverage.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. |
|
||||
| [ElementHandle](./puppeteer.elementhandle.md) | ElementHandle represents an in-page DOM element. |
|
||||
| [EventEmitter](./puppeteer.eventemitter.md) | The EventEmitter class that many Puppeteer classes extend. |
|
||||
| [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. |
|
||||
| [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. |
|
||||
| [HTTPResponse](./puppeteer.httpresponse.md) | The HTTPResponse class represents responses which are received by the [Page](./puppeteer.page.md) class. |
|
||||
| [JSCoverage](./puppeteer.jscoverage.md) | |
|
||||
| [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. |
|
||||
| [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> |
|
||||
| [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> |
|
||||
| [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. |
|
||||
| [Target](./puppeteer.target.md) | |
|
||||
| [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. |
|
||||
| [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). |
|
||||
|
||||
## Enumerations
|
||||
|
||||
|
@ -4,6 +4,8 @@ sidebar_label: ExecutionContext.evaluate
|
||||
|
||||
# ExecutionContext.evaluate() method
|
||||
|
||||
Evaluates the given function.
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
@ -20,20 +22,16 @@ class ExecutionContext {
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| ------------ | -------------- | --------------------------------------------------------------- |
|
||||
| pageFunction | Func \| string | a function to be evaluated in the <code>executionContext</code> |
|
||||
| args | Params | argument to pass to the page function |
|
||||
| Parameter | Type | Description |
|
||||
| ------------ | -------------- | ----------------------------------------------- |
|
||||
| pageFunction | Func \| string | The function to evaluate. |
|
||||
| args | Params | Additional arguments to pass into the function. |
|
||||
|
||||
**Returns:**
|
||||
|
||||
Promise<Awaited<ReturnType<Func>>>
|
||||
|
||||
A promise that resolves to the return value of the given function.
|
||||
|
||||
## 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.
|
||||
The result of evaluating the function. If the result is an object, a vanilla object containing the serializable properties of the result is returned.
|
||||
|
||||
## Example 1
|
||||
|
||||
@ -45,7 +43,7 @@ console.log(result); // prints "56"
|
||||
|
||||
## 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
|
||||
console.log(await executionContext.evaluate('1 + 2')); // prints "3"
|
||||
@ -53,13 +51,15 @@ console.log(await executionContext.evaluate('1 + 2')); // prints "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
|
||||
const oneHandle = await executionContext.evaluateHandle(() => 1);
|
||||
const twoHandle = await executionContext.evaluateHandle(() => 2);
|
||||
const result = await executionContext.evaluate(
|
||||
(a, b) => a + b, oneHandle, * twoHandle
|
||||
(a, b) => a + b,
|
||||
oneHandle,
|
||||
twoHandle
|
||||
);
|
||||
await oneHandle.dispose();
|
||||
await twoHandle.dispose();
|
||||
|
@ -4,6 +4,12 @@ sidebar_label: ExecutionContext.evaluateHandle
|
||||
|
||||
# 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:**
|
||||
|
||||
```typescript
|
||||
@ -20,27 +26,24 @@ class ExecutionContext {
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| ------------ | -------------- | --------------------------------------------------------------- |
|
||||
| pageFunction | Func \| string | a function to be evaluated in the <code>executionContext</code> |
|
||||
| args | Params | argument to pass to the page function |
|
||||
| Parameter | Type | Description |
|
||||
| ------------ | -------------- | ----------------------------------------------- |
|
||||
| pageFunction | Func \| string | The function to evaluate. |
|
||||
| args | Params | Additional arguments to pass into the function. |
|
||||
|
||||
**Returns:**
|
||||
|
||||
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)).
|
||||
|
||||
## 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.
|
||||
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).
|
||||
|
||||
## Example 1
|
||||
|
||||
```ts
|
||||
const context = await page.mainFrame().executionContext();
|
||||
const aHandle = await context.evaluateHandle(() => Promise.resolve(self));
|
||||
aHandle; // Handle for the global object.
|
||||
const handle: JSHandle<typeof globalThis> = await context.evaluateHandle(() =>
|
||||
Promise.resolve(self)
|
||||
);
|
||||
```
|
||||
|
||||
## Example 2
|
||||
@ -48,18 +51,25 @@ aHandle; // Handle for the global object.
|
||||
A string can also be passed in instead of a function.
|
||||
|
||||
```ts
|
||||
// Handle for the '3' * object.
|
||||
const aHandle = await context.evaluateHandle('1 + 2');
|
||||
const handle: JSHandle<number> = await context.evaluateHandle('1 + 2');
|
||||
```
|
||||
|
||||
## 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
|
||||
const aHandle = await context.evaluateHandle(() => document.body);
|
||||
const resultHandle = await context.evaluateHandle(body => body.innerHTML, * aHandle);
|
||||
console.log(await resultHandle.jsonValue()); // prints body's innerHTML
|
||||
await aHandle.dispose();
|
||||
await resultHandle.dispose();
|
||||
const bodyHandle: ElementHandle<HTMLBodyElement> = await context.evaluateHandle(
|
||||
() => {
|
||||
return document.body;
|
||||
}
|
||||
);
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
Besides pages, execution contexts can be found in [workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API).
|
||||
Represents a context for JavaScript execution.
|
||||
|
||||
**Signature:**
|
||||
|
||||
@ -16,13 +14,21 @@ export declare class ExecutionContext
|
||||
|
||||
## 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.
|
||||
|
||||
## 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
|
||||
|
||||
| Method | Modifiers | Description |
|
||||
| ------------------------------------------------------------------------------------ | --------- | -------------------------------------------------------------------------------------------- |
|
||||
| [evaluate(pageFunction, args)](./puppeteer.executioncontext.evaluate.md) | | |
|
||||
| [evaluateHandle(pageFunction, args)](./puppeteer.executioncontext.evaluatehandle.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. |
|
||||
| Method | Modifiers | Description |
|
||||
| ------------------------------------------------------------------------------------ | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [evaluate(pageFunction, args)](./puppeteer.executioncontext.evaluate.md) | | Evaluates the given function. |
|
||||
| [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) | | |
|
||||
| [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
|
||||
|
||||
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:**
|
||||
|
||||
@ -28,8 +28,6 @@ Promise<[HandleFor](./puppeteer.handlefor.md)<Prototype\[\]>>
|
||||
|
||||
A handle to an array of objects with the given prototype.
|
||||
|
||||
## Remarks
|
||||
|
||||
## Example
|
||||
|
||||
```ts
|
||||
|
@ -16,4 +16,4 @@ class JSHandle {
|
||||
|
||||
[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
|
||||
|
||||
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:**
|
||||
|
||||
|
@ -4,7 +4,7 @@ sidebar_label: JSHandle.evaluate
|
||||
|
||||
# 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:**
|
||||
|
||||
@ -32,10 +32,3 @@ class JSHandle {
|
||||
**Returns:**
|
||||
|
||||
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
|
||||
|
||||
This method passes this handle as the first argument to `pageFunction`.
|
||||
Evaluates the given function with the current handle as its first argument.
|
||||
|
||||
**Signature:**
|
||||
|
||||
@ -32,11 +32,3 @@ class JSHandle {
|
||||
**Returns:**
|
||||
|
||||
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
|
||||
|
||||
Returns the execution context the handle belongs to.
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
@ -17,3 +15,5 @@ class JSHandle {
|
||||
**Returns:**
|
||||
|
||||
[ExecutionContext](./puppeteer.executioncontext.md)
|
||||
|
||||
The execution context the handle belongs to.
|
||||
|
@ -4,7 +4,7 @@ sidebar_label: JSHandle.getProperties
|
||||
|
||||
# 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:**
|
||||
|
||||
@ -26,7 +26,9 @@ const properties = await listHandle.getProperties();
|
||||
const children = [];
|
||||
for (const property of properties.values()) {
|
||||
const element = property.asElement();
|
||||
if (element) children.push(element);
|
||||
if (element) {
|
||||
children.push(element);
|
||||
}
|
||||
}
|
||||
children; // holds elementHandles to all children of document.body
|
||||
```
|
||||
|
@ -8,7 +8,7 @@ sidebar_label: JSHandle.jsonValue
|
||||
|
||||
```typescript
|
||||
class JSHandle {
|
||||
jsonValue<T = unknown>(): Promise<T>;
|
||||
jsonValue(): Promise<T>;
|
||||
}
|
||||
```
|
||||
|
||||
@ -16,8 +16,12 @@ class JSHandle {
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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:**
|
||||
|
||||
@ -22,10 +26,6 @@ The constructor for this class is marked as internal. Third-party code should no
|
||||
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
|
||||
|
||||
| Property | Modifiers | Type | Description |
|
||||
@ -34,16 +34,16 @@ JSHandle instances can be used as arguments for [Page.$eval()](./puppeteer.page.
|
||||
|
||||
## Methods
|
||||
|
||||
| Method | Modifiers | Description |
|
||||
| ---------------------------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [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. |
|
||||
| [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. |
|
||||
| [evaluateHandle(pageFunction, args)](./puppeteer.jshandle.evaluatehandle.md) | | This method passes this handle as the first argument to <code>pageFunction</code>. |
|
||||
| [executionContext()](./puppeteer.jshandle.executioncontext.md) | | Returns the execution context the handle belongs to. |
|
||||
| [getProperties()](./puppeteer.jshandle.getproperties.md) | | The method returns a map with property names as keys and JSHandle instances for the property values. |
|
||||
| [getProperty(propertyName)](./puppeteer.jshandle.getproperty.md) | | Fetches a single property from the referenced object. |
|
||||
| [getProperty(propertyName)](./puppeteer.jshandle.getproperty_1.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. |
|
||||
| [toString()](./puppeteer.jshandle.tostring.md) | | Returns a string representation of the JSHandle. |
|
||||
| Method | Modifiers | Description |
|
||||
| ---------------------------------------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [asElement()](./puppeteer.jshandle.aselement.md) | | |
|
||||
| [dispose()](./puppeteer.jshandle.dispose.md) | | Releases the object referenced by the handle for garbage collection. |
|
||||
| [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) | | Evaluates the given function with the current handle as its first argument. |
|
||||
| [executionContext()](./puppeteer.jshandle.executioncontext.md) | | |
|
||||
| [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_1.md) | | |
|
||||
| [jsonValue()](./puppeteer.jshandle.jsonvalue.md) | | |
|
||||
| [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. |
|
||||
|
@ -4,7 +4,7 @@ sidebar_label: JSHandle.remoteObject
|
||||
|
||||
# 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:**
|
||||
|
||||
|
@ -185,7 +185,7 @@ export class Accessibility {
|
||||
let backendNodeId: number | undefined;
|
||||
if (root) {
|
||||
const {node} = await this.#client.send('DOM.describeNode', {
|
||||
objectId: root._remoteObject.objectId,
|
||||
objectId: root.remoteObject().objectId,
|
||||
});
|
||||
backendNodeId = node.backendNodeId;
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ async function queryAXTree(
|
||||
role?: string
|
||||
): Promise<Protocol.Accessibility.AXNode[]> {
|
||||
const {nodes} = await client.send('Accessibility.queryAXTree', {
|
||||
objectId: element._remoteObject.objectId,
|
||||
objectId: element.remoteObject().objectId,
|
||||
accessibleName,
|
||||
role,
|
||||
});
|
||||
|
@ -277,7 +277,7 @@ export class ElementHandle<
|
||||
selector: Selector,
|
||||
options: Exclude<WaitForSelectorOptions, 'root'> = {}
|
||||
): Promise<ElementHandle<NodeFor<Selector>> | null> {
|
||||
const frame = this._context.frame();
|
||||
const frame = this.executionContext().frame();
|
||||
assert(frame);
|
||||
const adoptedRoot = await frame.worlds[PUPPETEER_WORLD].adoptHandle(this);
|
||||
const handle = await frame.worlds[PUPPETEER_WORLD].waitForSelector(
|
||||
@ -376,8 +376,8 @@ export class ElementHandle<
|
||||
* iframe nodes, or null otherwise
|
||||
*/
|
||||
async contentFrame(): Promise<Frame | null> {
|
||||
const nodeInfo = await this._client.send('DOM.describeNode', {
|
||||
objectId: this._remoteObject.objectId,
|
||||
const nodeInfo = await this.client.send('DOM.describeNode', {
|
||||
objectId: this.remoteObject().objectId,
|
||||
});
|
||||
if (typeof nodeInfo.node.frameId !== 'string') {
|
||||
return null;
|
||||
@ -403,8 +403,8 @@ export class ElementHandle<
|
||||
}
|
||||
|
||||
try {
|
||||
await this._client.send('DOM.scrollIntoViewIfNeeded', {
|
||||
objectId: this._remoteObject.objectId,
|
||||
await this.client.send('DOM.scrollIntoViewIfNeeded', {
|
||||
objectId: this.remoteObject().objectId,
|
||||
});
|
||||
} catch (_err) {
|
||||
// Fallback to Element.scrollIntoView if DOM.scrollIntoViewIfNeeded is not supported
|
||||
@ -470,9 +470,9 @@ export class ElementHandle<
|
||||
*/
|
||||
async clickablePoint(offset?: Offset): Promise<Point> {
|
||||
const [result, layoutMetrics] = await Promise.all([
|
||||
this._client
|
||||
this.client
|
||||
.send('DOM.getContentQuads', {
|
||||
objectId: this._remoteObject.objectId,
|
||||
objectId: this.remoteObject().objectId,
|
||||
})
|
||||
.catch(debugError),
|
||||
this.#page._client().send('Page.getLayoutMetrics'),
|
||||
@ -539,9 +539,9 @@ export class ElementHandle<
|
||||
|
||||
#getBoxModel(): Promise<void | Protocol.DOM.GetBoxModelResponse> {
|
||||
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);
|
||||
});
|
||||
}
|
||||
@ -758,8 +758,8 @@ export class ElementHandle<
|
||||
return path.resolve(filePath);
|
||||
}
|
||||
});
|
||||
const {objectId} = this._remoteObject;
|
||||
const {node} = await this._client.send('DOM.describeNode', {objectId});
|
||||
const {objectId} = this.remoteObject();
|
||||
const {node} = await this.client.send('DOM.describeNode', {objectId});
|
||||
const {backendNodeId} = node;
|
||||
|
||||
/* 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}));
|
||||
});
|
||||
} else {
|
||||
await this._client.send('DOM.setFileInputFiles', {
|
||||
await this.client.send('DOM.setFileInputFiles', {
|
||||
objectId,
|
||||
files,
|
||||
backendNodeId,
|
||||
@ -954,7 +954,7 @@ export class ElementHandle<
|
||||
assert(boundingBox.width !== 0, 'Node has 0 width.');
|
||||
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.
|
||||
const {pageX, pageY} =
|
||||
layoutMetrics.cssVisualViewport || layoutMetrics.layoutViewport;
|
||||
|
@ -17,16 +17,15 @@
|
||||
import {Protocol} from 'devtools-protocol';
|
||||
import {assert} from './assert.js';
|
||||
import {CDPSession} from './Connection.js';
|
||||
import {IsolatedWorld} from './IsolatedWorld.js';
|
||||
import {ElementHandle} from './ElementHandle.js';
|
||||
import {Frame} from './FrameManager.js';
|
||||
import {IsolatedWorld} from './IsolatedWorld.js';
|
||||
import {JSHandle} from './JSHandle.js';
|
||||
import {EvaluateFunc, HandleFor} from './types.js';
|
||||
import {
|
||||
createJSHandle,
|
||||
getExceptionMessage,
|
||||
isString,
|
||||
valueFromRemoteObject,
|
||||
createJSHandle,
|
||||
} 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;
|
||||
|
||||
/**
|
||||
* This class represents a context for JavaScript execution. A [Page] might have
|
||||
* 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.
|
||||
* Represents a context for JavaScript execution.
|
||||
*
|
||||
* Besides pages, execution contexts can be found in {@link
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API | workers}.
|
||||
* @example
|
||||
* 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 {
|
||||
/**
|
||||
@ -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.
|
||||
*
|
||||
* @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 {
|
||||
return this._world ? this._world.frame() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
* Evaluates the given function.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
@ -113,29 +109,29 @@ export class ExecutionContext {
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* A string can also be passed in instead of a function.
|
||||
*
|
||||
* A string can also be passed in instead of a function:
|
||||
* ```ts
|
||||
* console.log(await executionContext.evaluate('1 + 2')); // prints "3"
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* {@link JSHandle} instances can be passed as arguments to the
|
||||
* `executionContext.* evaluate`:
|
||||
* Handles can also be passed as `args`. They resolve to their referenced object:
|
||||
* ```ts
|
||||
* const oneHandle = await executionContext.evaluateHandle(() => 1);
|
||||
* const twoHandle = await executionContext.evaluateHandle(() => 2);
|
||||
* const result = await executionContext.evaluate(
|
||||
* (a, b) => a + b, oneHandle, * twoHandle
|
||||
* (a, b) => a + b, oneHandle, twoHandle
|
||||
* );
|
||||
* await oneHandle.dispose();
|
||||
* await twoHandle.dispose();
|
||||
* 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<
|
||||
Params extends unknown[],
|
||||
@ -148,46 +144,51 @@ export class ExecutionContext {
|
||||
}
|
||||
|
||||
/**
|
||||
* @remarks
|
||||
* The only difference between `executionContext.evaluate` and
|
||||
* `executionContext.evaluateHandle` is that `executionContext.evaluateHandle`
|
||||
* returns an in-page object (a {@link JSHandle}).
|
||||
* 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.
|
||||
* Evaluates the given function.
|
||||
*
|
||||
* Unlike {@link ExecutionContext.evaluate | evaluate}, 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.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const context = await page.mainFrame().executionContext();
|
||||
* const aHandle = await context.evaluateHandle(() => Promise.resolve(self));
|
||||
* aHandle; // Handle for the global object.
|
||||
* const handle: JSHandle<typeof globalThis> = await context.evaluateHandle(() =>
|
||||
* Promise.resolve(self)
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* A string can also be passed in instead of a function.
|
||||
*
|
||||
* ```ts
|
||||
* // Handle for the '3' * object.
|
||||
* const aHandle = await context.evaluateHandle('1 + 2');
|
||||
* const handle: JSHandle<number> = await context.evaluateHandle('1 + 2');
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* 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
|
||||
* const aHandle = await context.evaluateHandle(() => document.body);
|
||||
* const resultHandle = await context.evaluateHandle(body => body.innerHTML, * aHandle);
|
||||
* console.log(await resultHandle.jsonValue()); // prints body's innerHTML
|
||||
* await aHandle.dispose();
|
||||
* await resultHandle.dispose();
|
||||
* const bodyHandle: ElementHandle<HTMLBodyElement> = await context.evaluateHandle(
|
||||
* () => {
|
||||
* return document.body;
|
||||
* }
|
||||
* );
|
||||
* 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 args - argument to pass to the page function
|
||||
*
|
||||
* @returns A promise that resolves to the return value of the given function
|
||||
* as an in-page object (a {@link JSHandle}).
|
||||
* @param pageFunction - The function to evaluate.
|
||||
* @param args - Additional arguments to pass into the function.
|
||||
* @returns A {@link JSHandle | handle} to the result of evaluating the
|
||||
* function. If the result is a `Node`, then this will return an
|
||||
* {@link ElementHandle | element handle}.
|
||||
*/
|
||||
async evaluateHandle<
|
||||
Params extends unknown[],
|
||||
@ -253,12 +254,6 @@ export class ExecutionContext {
|
||||
: 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();
|
||||
try {
|
||||
new Function('(' + functionText + ')');
|
||||
@ -330,23 +325,24 @@ export class ExecutionContext {
|
||||
}
|
||||
const objectHandle = arg && arg instanceof JSHandle ? arg : null;
|
||||
if (objectHandle) {
|
||||
if (objectHandle._context !== this) {
|
||||
if (objectHandle.executionContext() !== this) {
|
||||
throw new Error(
|
||||
'JSHandles can be evaluated only in the context they were created!'
|
||||
);
|
||||
}
|
||||
if (objectHandle._disposed) {
|
||||
if (objectHandle.disposed) {
|
||||
throw new Error('JSHandle is disposed!');
|
||||
}
|
||||
if (objectHandle._remoteObject.unserializableValue) {
|
||||
if (objectHandle.remoteObject().unserializableValue) {
|
||||
return {
|
||||
unserializableValue: objectHandle._remoteObject.unserializableValue,
|
||||
unserializableValue:
|
||||
objectHandle.remoteObject().unserializableValue,
|
||||
};
|
||||
}
|
||||
if (!objectHandle._remoteObject.objectId) {
|
||||
return {value: objectHandle._remoteObject.value};
|
||||
if (!objectHandle.remoteObject().objectId) {
|
||||
return {value: objectHandle.remoteObject().value};
|
||||
}
|
||||
return {objectId: objectHandle._remoteObject.objectId};
|
||||
return {objectId: objectHandle.remoteObject().objectId};
|
||||
}
|
||||
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.
|
||||
* @remarks
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // Create a Map object
|
||||
@ -390,33 +386,20 @@ export class ExecutionContext {
|
||||
* ```
|
||||
*
|
||||
* @param prototypeHandle - a handle to the object prototype
|
||||
*
|
||||
* @returns A handle to an array of objects with the given prototype.
|
||||
*/
|
||||
async queryObjects<Prototype>(
|
||||
prototypeHandle: JSHandle<Prototype>
|
||||
): Promise<HandleFor<Prototype[]>> {
|
||||
assert(!prototypeHandle._disposed, 'Prototype JSHandle is disposed!');
|
||||
assert(!prototypeHandle.disposed, 'Prototype JSHandle is disposed!');
|
||||
const remoteObject = prototypeHandle.remoteObject();
|
||||
assert(
|
||||
prototypeHandle._remoteObject.objectId,
|
||||
remoteObject.objectId,
|
||||
'Prototype JSHandle must not be referencing primitive value'
|
||||
);
|
||||
const response = await this._client.send('Runtime.queryObjects', {
|
||||
prototypeObjectId: prototypeHandle._remoteObject.objectId,
|
||||
prototypeObjectId: remoteObject.objectId,
|
||||
});
|
||||
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'
|
||||
);
|
||||
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;
|
||||
}
|
||||
|
@ -17,11 +17,11 @@
|
||||
import {Protocol} from 'devtools-protocol';
|
||||
import {assert} from './assert.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 {MouseButton} from './Input.js';
|
||||
import {releaseObject, valueFromRemoteObject, createJSHandle} from './util.js';
|
||||
import type {ElementHandle} from './ElementHandle.js';
|
||||
import {EvaluateFunc, HandleFor, HandleOr} from './types.js';
|
||||
import {createJSHandle, releaseObject, valueFromRemoteObject} from './util.js';
|
||||
|
||||
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
|
||||
* {@link Page.evaluateHandle | page.evaluateHandle} method.
|
||||
* Represents a reference to a JavaScript object. Instances can be created using
|
||||
* {@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
|
||||
* ```ts
|
||||
* 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
|
||||
*/
|
||||
export class JSHandle<T = unknown> {
|
||||
@ -83,31 +85,17 @@ export class JSHandle<T = unknown> {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
get _client(): CDPSession {
|
||||
get client(): CDPSession {
|
||||
return this.#client;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
get _disposed(): boolean {
|
||||
get disposed(): boolean {
|
||||
return this.#disposed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
get _remoteObject(): Protocol.Runtime.RemoteObject {
|
||||
return this.#remoteObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
get _context(): ExecutionContext {
|
||||
return this.#context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@ -121,24 +109,18 @@ export class JSHandle<T = unknown> {
|
||||
this.#remoteObject = remoteObject;
|
||||
}
|
||||
|
||||
/** Returns the execution context the handle belongs to.
|
||||
/**
|
||||
* @returns The execution context the handle belongs to.
|
||||
*/
|
||||
executionContext(): ExecutionContext {
|
||||
return this.#context;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const tweetHandle = await page.$('.tweet .retweets');
|
||||
* expect(await tweetHandle.evaluate(node => node.innerText)).toBe('10');
|
||||
* ```
|
||||
* @see {@link ExecutionContext.evaluate} for more details.
|
||||
*/
|
||||
|
||||
async evaluate<
|
||||
Params extends unknown[],
|
||||
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
|
||||
*
|
||||
* 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.
|
||||
* @see {@link ExecutionContext.evaluateHandle} for more details.
|
||||
*/
|
||||
async evaluateHandle<
|
||||
Params extends unknown[],
|
||||
@ -196,14 +168,13 @@ export class JSHandle<T = unknown> {
|
||||
async getProperty<K extends keyof T>(
|
||||
propertyName: HandleOr<K>
|
||||
): Promise<HandleFor<T[K]>> {
|
||||
return await this.evaluateHandle((object, propertyName) => {
|
||||
return this.evaluateHandle((object, propertyName) => {
|
||||
return object[propertyName];
|
||||
}, propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
@ -212,14 +183,17 @@ export class JSHandle<T = unknown> {
|
||||
* const children = [];
|
||||
* for (const property of properties.values()) {
|
||||
* const element = property.asElement();
|
||||
* if (element)
|
||||
* if (element) {
|
||||
* children.push(element);
|
||||
* }
|
||||
* }
|
||||
* children; // holds elementHandles to all children of document.body
|
||||
* ```
|
||||
*/
|
||||
async getProperties(): Promise<Map<string, JSHandle>> {
|
||||
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', {
|
||||
objectId: this.#remoteObject.objectId,
|
||||
ownProperties: true,
|
||||
@ -235,41 +209,36 @@ export class JSHandle<T = unknown> {
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns Returns a JSON representation of the object.If the object has a
|
||||
* `toJSON` function, it will not be called.
|
||||
* @remarks
|
||||
* @returns A vanilla object representing the serializable portions of the
|
||||
* referenced object.
|
||||
* @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}
|
||||
* 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.
|
||||
* **NOTE** The method throws if the referenced object is not stringifiable.
|
||||
* @remarks
|
||||
* If the object has a `toJSON` function, it *will not* be called.
|
||||
*/
|
||||
async jsonValue<T = unknown>(): Promise<T> {
|
||||
if (this.#remoteObject.objectId) {
|
||||
const response = await this.#client.send('Runtime.callFunctionOn', {
|
||||
functionDeclaration: 'function() { return this; }',
|
||||
objectId: this.#remoteObject.objectId,
|
||||
returnByValue: true,
|
||||
awaitPromise: true,
|
||||
});
|
||||
return valueFromRemoteObject(response.result) as T;
|
||||
async jsonValue(): Promise<T> {
|
||||
if (!this.#remoteObject.objectId) {
|
||||
return valueFromRemoteObject(this.#remoteObject);
|
||||
}
|
||||
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
|
||||
* handle is an instance of {@link ElementHandle}.
|
||||
* @returns Either `null` or the handle itself if the handle is an
|
||||
* instance of {@link ElementHandle}.
|
||||
*/
|
||||
asElement(): ElementHandle<Node> | null {
|
||||
/* This always returns null, but subclasses can override this and return an
|
||||
ElementHandle.
|
||||
*/
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
async dispose(): Promise<void> {
|
||||
if (this.#disposed) {
|
||||
@ -282,18 +251,21 @@ export class JSHandle<T = unknown> {
|
||||
/**
|
||||
* Returns a string representation of the JSHandle.
|
||||
*
|
||||
* @remarks Useful during debugging.
|
||||
* @remarks
|
||||
* Useful during debugging.
|
||||
*/
|
||||
toString(): string {
|
||||
if (this.#remoteObject.objectId) {
|
||||
const type = this.#remoteObject.subtype || this.#remoteObject.type;
|
||||
return 'JSHandle@' + type;
|
||||
if (!this.#remoteObject.objectId) {
|
||||
return 'JSHandle:' + valueFromRemoteObject(this.#remoteObject);
|
||||
}
|
||||
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 {
|
||||
return this.#remoteObject;
|
||||
|
@ -1710,7 +1710,7 @@ export class Page extends EventEmitter {
|
||||
}
|
||||
const textTokens = [];
|
||||
for (const arg of args) {
|
||||
const remoteObject = arg._remoteObject;
|
||||
const remoteObject = arg.remoteObject();
|
||||
if (remoteObject.objectId) {
|
||||
textTokens.push(arg.toString());
|
||||
} else {
|
||||
|
@ -353,7 +353,7 @@ describe('Evaluation specs', function () {
|
||||
const windowHandle = await page.evaluateHandle(() => {
|
||||
return window;
|
||||
});
|
||||
const errorText = await windowHandle.jsonValue<string>().catch(error_ => {
|
||||
const errorText = await windowHandle.jsonValue().catch(error_ => {
|
||||
return error_.message;
|
||||
});
|
||||
const error = await page
|
||||
|
@ -73,14 +73,9 @@ describe('JSHandle', function () {
|
||||
test.obj = test;
|
||||
let error!: Error;
|
||||
await page
|
||||
.evaluateHandle(
|
||||
opts => {
|
||||
// @ts-expect-error we are deliberately passing a bad type here
|
||||
// (nested object)
|
||||
return opts.elem;
|
||||
},
|
||||
{test}
|
||||
)
|
||||
.evaluateHandle(opts => {
|
||||
return opts;
|
||||
}, test)
|
||||
.catch(error_ => {
|
||||
return (error = error_);
|
||||
});
|
||||
@ -136,7 +131,7 @@ describe('JSHandle', function () {
|
||||
const aHandle = await page.evaluateHandle(() => {
|
||||
return {foo: 'bar'};
|
||||
});
|
||||
const json = await aHandle.jsonValue<Record<string, string>>();
|
||||
const json = await aHandle.jsonValue();
|
||||
expect(json).toEqual({foo: 'bar'});
|
||||
});
|
||||
|
||||
@ -146,7 +141,7 @@ describe('JSHandle', function () {
|
||||
const aHandle = await page.evaluateHandle(() => {
|
||||
return ['a', 'b'];
|
||||
});
|
||||
const json = await aHandle.jsonValue<string[]>();
|
||||
const json = await aHandle.jsonValue();
|
||||
expect(json).toEqual(['a', 'b']);
|
||||
});
|
||||
|
||||
@ -156,8 +151,12 @@ describe('JSHandle', function () {
|
||||
const aHandle = await page.evaluateHandle(() => {
|
||||
return 'foo';
|
||||
});
|
||||
const json = await aHandle.jsonValue<string>();
|
||||
expect(json).toEqual('foo');
|
||||
expect(await aHandle.jsonValue()).toEqual('foo');
|
||||
|
||||
const bHandle = await page.evaluateHandle(() => {
|
||||
return undefined;
|
||||
});
|
||||
expect(await bHandle.jsonValue()).toEqual(undefined);
|
||||
});
|
||||
|
||||
itFailsFirefox('should not work with dates', async () => {
|
||||
@ -172,13 +171,19 @@ describe('JSHandle', function () {
|
||||
it('should throw for circular objects', async () => {
|
||||
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;
|
||||
await windowHandle.jsonValue().catch(error_ => {
|
||||
await handle.jsonValue().catch(error_ => {
|
||||
return (error = error_);
|
||||
});
|
||||
if (isChrome) {
|
||||
expect(error.message).toContain('Object reference chain is too long');
|
||||
expect(error.message).toContain(
|
||||
'Could not serialize referenced object'
|
||||
);
|
||||
} else {
|
||||
expect(error.message).toContain('Object is not serializable');
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user