feat(Page): introduce Page.$$eval method (#1006)

This patch adds a `Page.$$eval` method that runs `document.querySelectorAll`
and passes resulting array to the page function.

Fixes #625.
This commit is contained in:
Andrey Lushnikov 2017-10-10 23:23:14 -07:00 committed by GitHub
parent 464b6a9616
commit 7a8aa73466
4 changed files with 65 additions and 2 deletions

View File

@ -33,6 +33,7 @@
+ [event: 'response'](#event-response) + [event: 'response'](#event-response)
+ [page.$(selector)](#pageselector) + [page.$(selector)](#pageselector)
+ [page.$$(selector)](#pageselector) + [page.$$(selector)](#pageselector)
+ [page.$$eval(selector, pageFunction[, ...args])](#pageevalselector-pagefunction-args)
+ [page.$eval(selector, pageFunction[, ...args])](#pageevalselector-pagefunction-args) + [page.$eval(selector, pageFunction[, ...args])](#pageevalselector-pagefunction-args)
+ [page.addScriptTag(url)](#pageaddscripttagurl) + [page.addScriptTag(url)](#pageaddscripttagurl)
+ [page.addStyleTag(url)](#pageaddstyletagurl) + [page.addStyleTag(url)](#pageaddstyletagurl)
@ -110,6 +111,7 @@
* [class: Frame](#class-frame) * [class: Frame](#class-frame)
+ [frame.$(selector)](#frameselector) + [frame.$(selector)](#frameselector)
+ [frame.$$(selector)](#frameselector) + [frame.$$(selector)](#frameselector)
+ [frame.$$eval(selector, pageFunction[, ...args])](#frameevalselector-pagefunction-args)
+ [frame.$eval(selector, pageFunction[, ...args])](#frameevalselector-pagefunction-args) + [frame.$eval(selector, pageFunction[, ...args])](#frameevalselector-pagefunction-args)
+ [frame.addScriptTag(url)](#frameaddscripttagurl) + [frame.addScriptTag(url)](#frameaddscripttagurl)
+ [frame.addStyleTag(url)](#frameaddstyletagurl) + [frame.addStyleTag(url)](#frameaddstyletagurl)
@ -379,6 +381,22 @@ The method runs `document.querySelectorAll` within the page. If no elements matc
Shortcut for [page.mainFrame().$$(selector)](#frameselector-1). Shortcut for [page.mainFrame().$$(selector)](#frameselector-1).
#### page.$$eval(selector, pageFunction[, ...args])
- `selector` <[string]> A [selector] to query frame for
- `pageFunction` <[function]> Function to be evaluated in browser context
- `...args` <...[Serializable]|[ElementHandle]> Arguments to pass to `pageFunction`
- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
This method runs `document.querySelectorAll` within the page and passes it as the first argument to `pageFunction`.
If `pageFunction` returns a [Promise], then `page.$$eval` would wait for the promise to resolve and return its value.
Examples:
```js
const divsCounts = await page.$$eval('div', divs => divs.length);
```
#### page.$eval(selector, pageFunction[, ...args]) #### page.$eval(selector, pageFunction[, ...args])
- `selector` <[string]> A [selector] to query page for - `selector` <[string]> A [selector] to query page for
- `pageFunction` <[function]> Function to be evaluated in browser context - `pageFunction` <[function]> Function to be evaluated in browser context
@ -1260,6 +1278,21 @@ The method queries frame for the selector. If there's no such element within the
The method runs `document.querySelectorAll` within the frame. If no elements match the selector, the return value resolve to `[]`. The method runs `document.querySelectorAll` within the frame. If no elements match the selector, the return value resolve to `[]`.
#### frame.$$eval(selector, pageFunction[, ...args])
- `selector` <[string]> A [selector] to query frame for
- `pageFunction` <[function]> Function to be evaluated in browser context
- `...args` <...[Serializable]|[ElementHandle]> Arguments to pass to `pageFunction`
- returns: <[Promise]<[Serializable]>> Promise which resolves to the return value of `pageFunction`
This method runs `document.querySelectorAll` within the frame and passes it as the first argument to `pageFunction`.
If `pageFunction` returns a [Promise], then `frame.$$eval` would wait for the promise to resolve and return its value.
Examples:
```js
const divsCounts = await frame.$$eval('div', divs => divs.length);
```
#### frame.$eval(selector, pageFunction[, ...args]) #### frame.$eval(selector, pageFunction[, ...args])
- `selector` <[string]> A [selector] to query frame for - `selector` <[string]> A [selector] to query frame for
- `pageFunction` <[function]> Function to be evaluated in browser context - `pageFunction` <[function]> Function to be evaluated in browser context

View File

@ -232,12 +232,24 @@ class Frame {
const elementHandle = await this.$(selector); const elementHandle = await this.$(selector);
if (!elementHandle) if (!elementHandle)
throw new Error(`Error: failed to find element matching selector "${selector}"`); throw new Error(`Error: failed to find element matching selector "${selector}"`);
args = [elementHandle].concat(args); const result = await this.evaluate(pageFunction, elementHandle, ...args);
const result = await this.evaluate(pageFunction, ...args);
await elementHandle.dispose(); await elementHandle.dispose();
return result; return result;
} }
/**
* @param {string} selector
* @param {Function|string} pageFunction
* @param {!Array<*>} args
* @return {!Promise<(!Object|undefined)>}
*/
async $$eval(selector, pageFunction, ...args) {
const arrayHandle = await this._context.evaluateHandle(selector => Array.from(document.querySelectorAll(selector)), selector);
const result = await this.evaluate(pageFunction, arrayHandle, ...args);
await arrayHandle.dispose();
return result;
}
/** /**
* @param {string} selector * @param {string} selector
* @return {!Promise<!Array<!ElementHandle>>} * @return {!Promise<!Array<!ElementHandle>>}

View File

@ -186,6 +186,16 @@ class Page extends EventEmitter {
return this.mainFrame().$eval(selector, pageFunction, ...args); return this.mainFrame().$eval(selector, pageFunction, ...args);
} }
/**
* @param {string} selector
* @param {Function|string} pageFunction
* @param {!Array<*>} args
* @return {!Promise<(!Object|undefined)>}
*/
async $$eval(selector, pageFunction, ...args) {
return this.mainFrame().$$eval(selector, pageFunction, ...args);
}
/** /**
* @param {string} selector * @param {string} selector
* @return {!Promise<!Array<!Puppeteer.ElementHandle>>} * @return {!Promise<!Array<!Puppeteer.ElementHandle>>}

View File

@ -1392,6 +1392,14 @@ describe('Page', function() {
})); }));
}); });
describe('Page.$$eval', function() {
it('should work', SX(async function() {
await page.setContent('<div>hello</div><div>beautiful</div><div>world!</div>');
const divsCount = await page.$$eval('div', divs => divs.length);
expect(divsCount).toBe(3);
}));
});
describe('Page.$', function() { describe('Page.$', function() {
it('should query existing element', SX(async function() { it('should query existing element', SX(async function() {
await page.setContent('<section>test</section>'); await page.setContent('<section>test</section>');