diff --git a/new-docs/puppeteer.executioncontext._adoptbackendnodeid.md b/new-docs/puppeteer.executioncontext._adoptbackendnodeid.md deleted file mode 100644 index 1bdf1e05bf9eb..0000000000000 --- a/new-docs/puppeteer.executioncontext._adoptbackendnodeid.md +++ /dev/null @@ -1,22 +0,0 @@ - - -[Home](./index.md) > [puppeteer](./puppeteer.md) > [ExecutionContext](./puppeteer.executioncontext.md) > [\_adoptBackendNodeId](./puppeteer.executioncontext._adoptbackendnodeid.md) - -## ExecutionContext.\_adoptBackendNodeId() method - -Signature: - -```typescript -_adoptBackendNodeId(backendNodeId: Protocol.DOM.BackendNodeId): Promise; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| backendNodeId | Protocol.DOM.BackendNodeId | | - -Returns: - -Promise<[ElementHandle](./puppeteer.elementhandle.md)> - diff --git a/new-docs/puppeteer.executioncontext._adoptelementhandle.md b/new-docs/puppeteer.executioncontext._adoptelementhandle.md deleted file mode 100644 index a211a82592e1c..0000000000000 --- a/new-docs/puppeteer.executioncontext._adoptelementhandle.md +++ /dev/null @@ -1,22 +0,0 @@ - - -[Home](./index.md) > [puppeteer](./puppeteer.md) > [ExecutionContext](./puppeteer.executioncontext.md) > [\_adoptElementHandle](./puppeteer.executioncontext._adoptelementhandle.md) - -## ExecutionContext.\_adoptElementHandle() method - -Signature: - -```typescript -_adoptElementHandle(elementHandle: ElementHandle): Promise; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| elementHandle | [ElementHandle](./puppeteer.elementhandle.md) | | - -Returns: - -Promise<[ElementHandle](./puppeteer.elementhandle.md)> - diff --git a/new-docs/puppeteer.executioncontext._client.md b/new-docs/puppeteer.executioncontext._client.md deleted file mode 100644 index b3ad759f69844..0000000000000 --- a/new-docs/puppeteer.executioncontext._client.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [puppeteer](./puppeteer.md) > [ExecutionContext](./puppeteer.executioncontext.md) > [\_client](./puppeteer.executioncontext._client.md) - -## ExecutionContext.\_client property - -Signature: - -```typescript -_client: CDPSession; -``` diff --git a/new-docs/puppeteer.executioncontext._constructor_.md b/new-docs/puppeteer.executioncontext._constructor_.md deleted file mode 100644 index 8271648e1566e..0000000000000 --- a/new-docs/puppeteer.executioncontext._constructor_.md +++ /dev/null @@ -1,22 +0,0 @@ - - -[Home](./index.md) > [puppeteer](./puppeteer.md) > [ExecutionContext](./puppeteer.executioncontext.md) > [(constructor)](./puppeteer.executioncontext._constructor_.md) - -## ExecutionContext.(constructor) - -Constructs a new instance of the `ExecutionContext` class - -Signature: - -```typescript -constructor(client: CDPSession, contextPayload: Protocol.Runtime.ExecutionContextDescription, world: DOMWorld); -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| client | [CDPSession](./puppeteer.cdpsession.md) | | -| contextPayload | Protocol.Runtime.ExecutionContextDescription | | -| world | DOMWorld | | - diff --git a/new-docs/puppeteer.executioncontext._contextid.md b/new-docs/puppeteer.executioncontext._contextid.md deleted file mode 100644 index 3a8457c534803..0000000000000 --- a/new-docs/puppeteer.executioncontext._contextid.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [puppeteer](./puppeteer.md) > [ExecutionContext](./puppeteer.executioncontext.md) > [\_contextId](./puppeteer.executioncontext._contextid.md) - -## ExecutionContext.\_contextId property - -Signature: - -```typescript -_contextId: number; -``` diff --git a/new-docs/puppeteer.executioncontext._world.md b/new-docs/puppeteer.executioncontext._world.md deleted file mode 100644 index e01b99a26ef63..0000000000000 --- a/new-docs/puppeteer.executioncontext._world.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [puppeteer](./puppeteer.md) > [ExecutionContext](./puppeteer.executioncontext.md) > [\_world](./puppeteer.executioncontext._world.md) - -## ExecutionContext.\_world property - -Signature: - -```typescript -_world: DOMWorld; -``` diff --git a/new-docs/puppeteer.executioncontext.evaluate.md b/new-docs/puppeteer.executioncontext.evaluate.md index c59be4be33342..7c767e125c15c 100644 --- a/new-docs/puppeteer.executioncontext.evaluate.md +++ b/new-docs/puppeteer.executioncontext.evaluate.md @@ -14,10 +14,51 @@ evaluate(pageFunction: Function | string, ...args: unkno | Parameter | Type | Description | | --- | --- | --- | -| pageFunction | Function \| string | | -| args | unknown\[\] | | +| pageFunction | Function \| string | a function to be evaluated in the executionContext | +| args | unknown\[\] | argument to pass to the page function | Returns: Promise<ReturnType> +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. + +## Example 1 + + +```js +const executionContext = await page.mainFrame().executionContext(); +const result = await executionContext.evaluate(() => Promise.resolve(8 * 7))* ; +console.log(result); // prints "56" + +``` + +## Example 2 + +A string can also be passed in instead of a function. + +```js +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`: + +```js +const oneHandle = await executionContext.evaluateHandle(() => 1); +const twoHandle = await executionContext.evaluateHandle(() => 2); +const result = await executionContext.evaluate( + (a, b) => a + b, oneHandle, * twoHandle +); +await oneHandle.dispose(); +await twoHandle.dispose(); +console.log(result); // prints '3'. + +``` + diff --git a/new-docs/puppeteer.executioncontext.evaluatehandle.md b/new-docs/puppeteer.executioncontext.evaluatehandle.md index 4ddf2d737a682..7730949164dc4 100644 --- a/new-docs/puppeteer.executioncontext.evaluatehandle.md +++ b/new-docs/puppeteer.executioncontext.evaluatehandle.md @@ -14,10 +14,49 @@ evaluateHandle(pageFunction: Function | string, ...args: unknown[]): PromiseexecutionContext | +| args | unknown\[\] | argument to pass to the page function | Returns: Promise<[JSHandle](./puppeteer.jshandle.md)> +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. + +## Example 1 + + +```js +const context = await page.mainFrame().executionContext(); +const aHandle = await context.evaluateHandle(() => Promise.resolve(self)); +aHandle; // Handle for the global object. + +``` + +## Example 2 + +A string can also be passed in instead of a function. + +```js +// Handle for the '3' * object. +const aHandle = await context.evaluateHandle('1 + 2'); + +``` + +## Example 3 + +JSHandle instances can be passed as arguments to the `executionContext.* evaluateHandle`: + +```js +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(); + +``` + diff --git a/new-docs/puppeteer.executioncontext.frame.md b/new-docs/puppeteer.executioncontext.frame.md index 112e4b7f60250..94a9dbab56252 100644 --- a/new-docs/puppeteer.executioncontext.frame.md +++ b/new-docs/puppeteer.executioncontext.frame.md @@ -13,3 +13,9 @@ frame(): Frame | null; [Frame](./puppeteer.frame.md) \| null +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. + diff --git a/new-docs/puppeteer.executioncontext.md b/new-docs/puppeteer.executioncontext.md index c07e290665284..c4902fd6d744c 100644 --- a/new-docs/puppeteer.executioncontext.md +++ b/new-docs/puppeteer.executioncontext.md @@ -4,34 +4,26 @@ ## 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 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). + Signature: ```typescript export declare class ExecutionContext ``` -## Constructors - -| Constructor | Modifiers | Description | -| --- | --- | --- | -| [(constructor)(client, contextPayload, world)](./puppeteer.executioncontext._constructor_.md) | | Constructs a new instance of the ExecutionContext class | - -## Properties +## Remarks -| Property | Modifiers | Type | Description | -| --- | --- | --- | --- | -| [\_client](./puppeteer.executioncontext._client.md) | | [CDPSession](./puppeteer.cdpsession.md) | | -| [\_contextId](./puppeteer.executioncontext._contextid.md) | | number | | -| [\_world](./puppeteer.executioncontext._world.md) | | DOMWorld | | +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. ## Methods | Method | Modifiers | Description | | --- | --- | --- | -| [\_adoptBackendNodeId(backendNodeId)](./puppeteer.executioncontext._adoptbackendnodeid.md) | | | -| [\_adoptElementHandle(elementHandle)](./puppeteer.executioncontext._adoptelementhandle.md) | | | | [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) | | | +| [queryObjects(prototypeHandle)](./puppeteer.executioncontext.queryobjects.md) | | This method iterates the JavaScript heap and finds all the objects with the given prototype. | diff --git a/new-docs/puppeteer.executioncontext.queryobjects.md b/new-docs/puppeteer.executioncontext.queryobjects.md index ae9f7c8e0fa6d..1401d91df4a77 100644 --- a/new-docs/puppeteer.executioncontext.queryobjects.md +++ b/new-docs/puppeteer.executioncontext.queryobjects.md @@ -4,6 +4,8 @@ ## ExecutionContext.queryObjects() method +This method iterates the JavaScript heap and finds all the objects with the given prototype. + Signature: ```typescript @@ -14,9 +16,31 @@ queryObjects(prototypeHandle: JSHandle): Promise; | Parameter | Type | Description | | --- | --- | --- | -| prototypeHandle | [JSHandle](./puppeteer.jshandle.md) | | +| prototypeHandle | [JSHandle](./puppeteer.jshandle.md) | a handle to the object prototype | Returns: Promise<[JSHandle](./puppeteer.jshandle.md)> +A handle to an array of objects with the given prototype. + +## Remarks + + +## Example + + +```js +// Create a Map object +await page.evaluate(() => window.map = new Map()); +// Get a handle to the Map object prototype +const mapPrototype = await page.evaluateHandle(() => Map.prototype); +// Query all map instances into an array +const mapInstances = await page.queryObjects(mapPrototype); +// Count amount of map objects in heap +const count = await page.evaluate(maps => maps.length, mapInstances); +await mapInstances.dispose(); +await mapPrototype.dispose(); + +``` + diff --git a/new-docs/puppeteer.md b/new-docs/puppeteer.md index 38c4bad59be43..e5b543386da5f 100644 --- a/new-docs/puppeteer.md +++ b/new-docs/puppeteer.md @@ -19,7 +19,7 @@ | [Dialog](./puppeteer.dialog.md) | Dialog instances are dispatched by the [Page](./puppeteer.page.md) via the dialog 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) | | +| [ExecutionContext](./puppeteer.executioncontext.md) | 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 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). | | [FileChooser](./puppeteer.filechooser.md) | File choosers let you react to the page requesting for a file. | | [Frame](./puppeteer.frame.md) | | | [FrameManager](./puppeteer.framemanager.md) | | diff --git a/src/common/ExecutionContext.ts b/src/common/ExecutionContext.ts index b653895e4e796..5681e9d0bc0af 100644 --- a/src/common/ExecutionContext.ts +++ b/src/common/ExecutionContext.ts @@ -25,11 +25,37 @@ import Protocol from '../protocol'; export const EVALUATION_SCRIPT_URL = '__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. + * + * Besides pages, execution contexts can be found in + * {@link https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API | + * workers }. + * + * @public + */ export class ExecutionContext { + /** + * @internal + */ _client: CDPSession; + /** + * @internal + */ _world: DOMWorld; - _contextId: number; + private _contextId: number; + /** + * @internal + */ constructor( client: CDPSession, contextPayload: Protocol.Runtime.ExecutionContextDescription, @@ -40,10 +66,62 @@ export class ExecutionContext { this._contextId = contextPayload.id; } + /** + * @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. + */ 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. + * + * + * @example + * ```js + * const executionContext = await page.mainFrame().executionContext(); + * const result = await executionContext.evaluate(() => Promise.resolve(8 * 7))* ; + * console.log(result); // prints "56" + * ``` + * + * @example + * A string can also be passed in instead of a function. + * + * ```js + * console.log(await executionContext.evaluate('1 + 2')); // prints "3" + * ``` + * + * @example + * {@link JSHandle} instances can be passed as arguments to the + * `executionContext.* evaluate`: + * ```js + * const oneHandle = await executionContext.evaluateHandle(() => 1); + * const twoHandle = await executionContext.evaluateHandle(() => 2); + * const result = await executionContext.evaluate( + * (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. + */ async evaluate( pageFunction: Function | string, ...args: unknown[] @@ -55,6 +133,48 @@ 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. + * + * @example + * ```js + * const context = await page.mainFrame().executionContext(); + * const aHandle = await context.evaluateHandle(() => Promise.resolve(self)); + * aHandle; // Handle for the global object. + * ``` + * + * @example + * A string can also be passed in instead of a function. + * + * ```js + * // Handle for the '3' * object. + * const aHandle = await context.evaluateHandle('1 + 2'); + * ``` + * + * @example + * JSHandle instances can be passed as arguments + * to the `executionContext.* evaluateHandle`: + * + * ```js + * 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(); + * ``` + * + * @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}). + */ async evaluateHandle( pageFunction: Function | string, ...args: unknown[] @@ -197,6 +317,28 @@ export class ExecutionContext { } } + /** + * This method iterates the JavaScript heap and finds all the objects with the + * given prototype. + * @remarks + * @example + * ```js + * // Create a Map object + * await page.evaluate(() => window.map = new Map()); + * // Get a handle to the Map object prototype + * const mapPrototype = await page.evaluateHandle(() => Map.prototype); + * // Query all map instances into an array + * const mapInstances = await page.queryObjects(mapPrototype); + * // Count amount of map objects in heap + * const count = await page.evaluate(maps => maps.length, mapInstances); + * await mapInstances.dispose(); + * await mapPrototype.dispose(); + * ``` + * + * @param prototypeHandle a handle to the object prototype + * + * @returns A handle to an array of objects with the given prototype. + */ async queryObjects(prototypeHandle: JSHandle): Promise { assert(!prototypeHandle._disposed, 'Prototype JSHandle is disposed!'); assert( @@ -209,6 +351,9 @@ export class ExecutionContext { return createJSHandle(this, response.objects); } + /** + * @internal + */ async _adoptBackendNodeId( backendNodeId: Protocol.DOM.BackendNodeId ): Promise { @@ -219,6 +364,9 @@ export class ExecutionContext { return createJSHandle(this, object) as ElementHandle; } + /** + * @internal + */ async _adoptElementHandle( elementHandle: ElementHandle ): Promise {