Skip to content

Commit

Permalink
feat(Page): introduce Page.$$eval method (puppeteer#1006)
Browse files Browse the repository at this point in the history
This patch adds a `Page.$$eval` method that runs `document.querySelectorAll`
and passes resulting array to the page function.

Fixes puppeteer#625.
  • Loading branch information
aslushnikov authored and ithinkihaveacat committed Oct 31, 2017
1 parent 9a1bae1 commit 8e04e03
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 2 deletions.
33 changes: 33 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
+ [event: 'response'](#event-response)
+ [page.$(selector)](#pageselector)
+ [page.$$(selector)](#pageselector)
+ [page.$$eval(selector, pageFunction[, ...args])](#pageevalselector-pagefunction-args)
+ [page.$eval(selector, pageFunction[, ...args])](#pageevalselector-pagefunction-args)
+ [page.addScriptTag(url)](#pageaddscripttagurl)
+ [page.addStyleTag(url)](#pageaddstyletagurl)
Expand Down Expand Up @@ -110,6 +111,7 @@
* [class: Frame](#class-frame)
+ [frame.$(selector)](#frameselector)
+ [frame.$$(selector)](#frameselector)
+ [frame.$$eval(selector, pageFunction[, ...args])](#frameevalselector-pagefunction-args)
+ [frame.$eval(selector, pageFunction[, ...args])](#frameevalselector-pagefunction-args)
+ [frame.addScriptTag(url)](#frameaddscripttagurl)
+ [frame.addStyleTag(url)](#frameaddstyletagurl)
Expand Down Expand Up @@ -379,6 +381,22 @@ The method runs `document.querySelectorAll` within the page. If no elements matc

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])
- `selector` <[string]> A [selector] to query page for
- `pageFunction` <[function]> Function to be evaluated in browser context
Expand Down Expand Up @@ -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 `[]`.

#### 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])
- `selector` <[string]> A [selector] to query frame for
- `pageFunction` <[function]> Function to be evaluated in browser context
Expand Down
16 changes: 14 additions & 2 deletions lib/FrameManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,12 +232,24 @@ class Frame {
const elementHandle = await this.$(selector);
if (!elementHandle)
throw new Error(`Error: failed to find element matching selector "${selector}"`);
args = [elementHandle].concat(args);
const result = await this.evaluate(pageFunction, ...args);
const result = await this.evaluate(pageFunction, elementHandle, ...args);
await elementHandle.dispose();
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
* @return {!Promise<!Array<!ElementHandle>>}
Expand Down
10 changes: 10 additions & 0 deletions lib/Page.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,16 @@ class Page extends EventEmitter {
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
* @return {!Promise<!Array<!Puppeteer.ElementHandle>>}
Expand Down
8 changes: 8 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
it('should query existing element', SX(async function() {
await page.setContent('<section>test</section>');
Expand Down

0 comments on commit 8e04e03

Please sign in to comment.