feat(Page): introduce Page.queryObjects (#1005)
This patch introduces `Page.queryObjects` and `ExecutionContext.queryObjects` methods to query JavaScript heap for objects with a certain prototype. Fixes #304.
This commit is contained in:
parent
3f9f0f44ff
commit
23c0ba0727
42
docs/api.md
42
docs/api.md
@ -61,6 +61,7 @@
|
|||||||
+ [page.mainFrame()](#pagemainframe)
|
+ [page.mainFrame()](#pagemainframe)
|
||||||
+ [page.mouse](#pagemouse)
|
+ [page.mouse](#pagemouse)
|
||||||
+ [page.pdf(options)](#pagepdfoptions)
|
+ [page.pdf(options)](#pagepdfoptions)
|
||||||
|
+ [page.queryObjects(prototypeHandle)](#pagequeryobjectsprototypehandle)
|
||||||
+ [page.reload(options)](#pagereloadoptions)
|
+ [page.reload(options)](#pagereloadoptions)
|
||||||
+ [page.screenshot([options])](#pagescreenshotoptions)
|
+ [page.screenshot([options])](#pagescreenshotoptions)
|
||||||
+ [page.select(selector, ...values)](#pageselectselector-values)
|
+ [page.select(selector, ...values)](#pageselectselector-values)
|
||||||
@ -130,6 +131,7 @@
|
|||||||
* [class: ExecutionContext](#class-executioncontext)
|
* [class: ExecutionContext](#class-executioncontext)
|
||||||
+ [executionContext.evaluate(pageFunction, ...args)](#executioncontextevaluatepagefunction-args)
|
+ [executionContext.evaluate(pageFunction, ...args)](#executioncontextevaluatepagefunction-args)
|
||||||
+ [executionContext.evaluateHandle(pageFunction, ...args)](#executioncontextevaluatehandlepagefunction-args)
|
+ [executionContext.evaluateHandle(pageFunction, ...args)](#executioncontextevaluatehandlepagefunction-args)
|
||||||
|
+ [executionContext.queryObjects(prototypeHandle)](#executioncontextqueryobjectsprototypehandle)
|
||||||
* [class: JSHandle](#class-jshandle)
|
* [class: JSHandle](#class-jshandle)
|
||||||
+ [jsHandle.asElement()](#jshandleaselement)
|
+ [jsHandle.asElement()](#jshandleaselement)
|
||||||
+ [jsHandle.dispose()](#jshandledispose)
|
+ [jsHandle.dispose()](#jshandledispose)
|
||||||
@ -811,6 +813,27 @@ The `format` options are:
|
|||||||
- `A5`: 5.83in x 8.27in
|
- `A5`: 5.83in x 8.27in
|
||||||
- `A6`: 4.13in x 5.83in
|
- `A6`: 4.13in x 5.83in
|
||||||
|
|
||||||
|
#### page.queryObjects(prototypeHandle)
|
||||||
|
- `prototypeHandle` <[JSHandle]> A handle to the object prototype.
|
||||||
|
- returns: <[JSHandle]> A handle to an array of objects with this prototype
|
||||||
|
|
||||||
|
The method iterates javascript heap and finds all the objects with the given prototype.
|
||||||
|
|
||||||
|
```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();
|
||||||
|
```
|
||||||
|
|
||||||
|
Shortcut for [page.mainFrame().executionContext().queryObjects(prototypeHandle)](#executioncontextqueryobjectsprototypehandle).
|
||||||
|
|
||||||
#### page.reload(options)
|
#### page.reload(options)
|
||||||
- `options` <[Object]> Navigation parameters which might have the following properties:
|
- `options` <[Object]> Navigation parameters which might have the following properties:
|
||||||
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout.
|
- `timeout` <[number]> Maximum navigation time in milliseconds, defaults to 30 seconds, pass `0` to disable timeout.
|
||||||
@ -1513,6 +1536,25 @@ await aHandle.dispose();
|
|||||||
await resultHandle.dispose();
|
await resultHandle.dispose();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### executionContext.queryObjects(prototypeHandle)
|
||||||
|
- `prototypeHandle` <[JSHandle]> A handle to the object prototype.
|
||||||
|
- returns: <[JSHandle]> A handle to an array of objects with this prototype
|
||||||
|
|
||||||
|
The method iterates javascript heap and finds all the objects with the given prototype.
|
||||||
|
|
||||||
|
```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();
|
||||||
|
```
|
||||||
|
|
||||||
### class: JSHandle
|
### class: JSHandle
|
||||||
|
|
||||||
JSHandle represents an in-page javascript object. JSHandles can be created with the [page.evaluateHandle](#pageevaluatehandlepagefunction-args) method.
|
JSHandle represents an in-page javascript object. JSHandles can be created with the [page.evaluateHandle](#pageevaluatehandlepagefunction-args) method.
|
||||||
|
@ -95,6 +95,19 @@ class ExecutionContext {
|
|||||||
return { value: arg };
|
return { value: arg };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!JSHandle} prototypeHandle
|
||||||
|
* @return {!Promise<!JSHandle>}
|
||||||
|
*/
|
||||||
|
async queryObjects(prototypeHandle) {
|
||||||
|
console.assert(!prototypeHandle._disposed, 'Prototype JSHandle is disposed!');
|
||||||
|
console.assert(prototypeHandle._remoteObject.objectId, 'Prototype JSHandle must not be referencing primitive value');
|
||||||
|
const response = await this._client.send('Runtime.queryObjects', {
|
||||||
|
prototypeObjectId: prototypeHandle._remoteObject.objectId
|
||||||
|
});
|
||||||
|
return this._objectHandleFactory(response.objects);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class JSHandle {
|
class JSHandle {
|
||||||
|
@ -178,6 +178,14 @@ class Page extends EventEmitter {
|
|||||||
return this.mainFrame().executionContext().evaluateHandle(pageFunction, ...args);
|
return this.mainFrame().executionContext().evaluateHandle(pageFunction, ...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!Puppeteer.JSHandle} prototypeHandle
|
||||||
|
* @return {!Promise<!Puppeteer.JSHandle>}
|
||||||
|
*/
|
||||||
|
async queryObjects(prototypeHandle) {
|
||||||
|
return this.mainFrame().executionContext().queryObjects(prototypeHandle);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} selector
|
* @param {string} selector
|
||||||
* @param {function()|string} pageFunction
|
* @param {function()|string} pageFunction
|
||||||
|
26
test/test.js
26
test/test.js
@ -335,6 +335,32 @@ describe('Page', function() {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('ExecutionContext.queryObjects', function() {
|
||||||
|
it('should work', SX(async function() {
|
||||||
|
// Instantiate an object
|
||||||
|
await page.evaluate(() => window.set = new Set(['hello', 'world']));
|
||||||
|
const prototypeHandle = await page.evaluateHandle(() => Set.prototype);
|
||||||
|
const objectsHandle = await page.queryObjects(prototypeHandle);
|
||||||
|
const count = await page.evaluate(objects => objects.length, objectsHandle);
|
||||||
|
expect(count).toBe(1);
|
||||||
|
const values = await page.evaluate(objects => Array.from(objects[0].values()), objectsHandle);
|
||||||
|
expect(values).toEqual(['hello', 'world']);
|
||||||
|
}));
|
||||||
|
it('should fail for disposed handles', SX(async function() {
|
||||||
|
const prototypeHandle = await page.evaluateHandle(() => HTMLBodyElement.prototype);
|
||||||
|
await prototypeHandle.dispose();
|
||||||
|
let error = null;
|
||||||
|
await page.queryObjects(prototypeHandle).catch(e => error = e);
|
||||||
|
expect(error.message).toBe('Prototype JSHandle is disposed!');
|
||||||
|
}));
|
||||||
|
it('should fail primitive values as prototypes', SX(async function() {
|
||||||
|
const prototypeHandle = await page.evaluateHandle(() => 42);
|
||||||
|
let error = null;
|
||||||
|
await page.queryObjects(prototypeHandle).catch(e => error = e);
|
||||||
|
expect(error.message).toBe('Prototype JSHandle must not be referencing primitive value');
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
describe('JSHandle.getProperty', function() {
|
describe('JSHandle.getProperty', function() {
|
||||||
it('should work', SX(async function() {
|
it('should work', SX(async function() {
|
||||||
const aHandle = await page.evaluateHandle(() => ({
|
const aHandle = await page.evaluateHandle(() => ({
|
||||||
|
Loading…
Reference in New Issue
Block a user