mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
$ and $$ for querySelector and querySelectorAll
This commit is contained in:
parent
6c7ae41ae6
commit
fa35554166
17
docs/api.md
17
docs/api.md
@ -9,6 +9,8 @@
|
|||||||
- [browser.newPage()](#browsernewpage)
|
- [browser.newPage()](#browsernewpage)
|
||||||
- [browser.version()](#browserversion)
|
- [browser.version()](#browserversion)
|
||||||
+ [class: Page](#class-page)
|
+ [class: Page](#class-page)
|
||||||
|
- [page.$(querySelector, fun, args)](#pagequeryselector-fun-args)
|
||||||
|
- [page.$$(querySelector, fun, args)](#pagequeryselector-fun-args-1)
|
||||||
- [page.addScriptTag(url)](#pageaddscripttagurl)
|
- [page.addScriptTag(url)](#pageaddscripttagurl)
|
||||||
- [page.close()](#pageclose)
|
- [page.close()](#pageclose)
|
||||||
- [page.evaluate(fun, args)](#pageevaluatefun-args)
|
- [page.evaluate(fun, args)](#pageevaluatefun-args)
|
||||||
@ -104,6 +106,20 @@ browser.newPage().then(page => {
|
|||||||
```
|
```
|
||||||
Pages could be closed by `page.close()` method.
|
Pages could be closed by `page.close()` method.
|
||||||
|
|
||||||
|
#### page.$(querySelector, fun, args)
|
||||||
|
|
||||||
|
- `querySelector` <[string]> Query selector to be run on the page
|
||||||
|
- `fun` <[function<[Element]>]> Function to be evaluated with first element matching `querySelector`
|
||||||
|
- `args` <[Array]<[string]>> Arguments to pass to `fun`
|
||||||
|
- returns: <[Promise<[Object]]> Promise which resolves to function return value.
|
||||||
|
|
||||||
|
#### page.$$(querySelector, fun, args)
|
||||||
|
|
||||||
|
- `querySelector` <[string]> Query selector to be run on the page
|
||||||
|
- `fun` <[function<[Element]>]> Function to be evaluted for every element matching `querySelector`.
|
||||||
|
- `args` <[Array]<[string]>> Arguments to pass to `fun`
|
||||||
|
- returns: <[Promise<[Array<[Object]>]>]> Promise which resolves to array of function return values.
|
||||||
|
|
||||||
#### page.addScriptTag(url)
|
#### page.addScriptTag(url)
|
||||||
|
|
||||||
- `url` <[string]> Url of a script to be added
|
- `url` <[string]> Url of a script to be added
|
||||||
@ -295,3 +311,4 @@ Pages could be closed by `page.close()` method.
|
|||||||
[Page]: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#class-page "Page"
|
[Page]: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#class-page "Page"
|
||||||
[Promise]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise "Promise"
|
[Promise]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise "Promise"
|
||||||
[string]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type "String"
|
[string]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type "String"
|
||||||
|
[Element]: https://developer.mozilla.org/en-US/docs/Web/API/element "Element"
|
||||||
|
@ -174,31 +174,11 @@ class FrameManager extends EventEmitter {
|
|||||||
let message = await helper.getExceptionMessage(this._client, exceptionDetails);
|
let message = await helper.getExceptionMessage(this._client, exceptionDetails);
|
||||||
throw new Error('Evaluation failed: ' + message);
|
throw new Error('Evaluation failed: ' + message);
|
||||||
}
|
}
|
||||||
if (remoteObject.unserializableValue) {
|
return helper.serializeRemoteObjet(this._client, remoteObject);
|
||||||
switch (remoteObject.unserializableValue) {
|
|
||||||
case '-0':
|
|
||||||
return -0;
|
|
||||||
case 'NaN':
|
|
||||||
return NaN;
|
|
||||||
case 'Infinity':
|
|
||||||
return Infinity;
|
|
||||||
case '-Infinity':
|
|
||||||
return -Infinity;
|
|
||||||
default:
|
|
||||||
throw new Error('Unsupported unserializable value: ' + remoteObject.unserializableValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!remoteObject.objectId)
|
|
||||||
return remoteObject.value;
|
|
||||||
let response = await this._client.send('Runtime.callFunctionOn', {
|
|
||||||
objectId: remoteObject.objectId,
|
|
||||||
functionDeclaration: 'function() { return this; }',
|
|
||||||
returnByValue: true,
|
|
||||||
});
|
|
||||||
return response.result.value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
FrameManager.Events = {
|
FrameManager.Events = {
|
||||||
FrameAttached: 'frameattached',
|
FrameAttached: 'frameattached',
|
||||||
|
58
lib/Page.js
58
lib/Page.js
@ -499,6 +499,17 @@ class Page extends EventEmitter {
|
|||||||
})).nodeId;
|
})).nodeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} selector
|
||||||
|
* @param {!Promise<!Array<number>>}
|
||||||
|
*/
|
||||||
|
async _querySelectorAll(selector) {
|
||||||
|
return (await this._client.send('DOM.querySelectorAll', {
|
||||||
|
nodeId: await this._rootNodeId(),
|
||||||
|
selector
|
||||||
|
})).nodeIds;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} selector
|
* @param {string} selector
|
||||||
* @param {!Promise}
|
* @param {!Promise}
|
||||||
@ -561,6 +572,53 @@ class Page extends EventEmitter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} nodeId
|
||||||
|
* @param {function(!Element):T} fun
|
||||||
|
* @param {!Array<*>} args
|
||||||
|
* @return {!Promise<T>}
|
||||||
|
*/
|
||||||
|
async _callFunctionOnNode(nodeId, fun, ...args) {
|
||||||
|
let { objectId } = (await this._client.send('DOM.resolveNode', { nodeId })).object;
|
||||||
|
let argsString = ['this'].concat(args.map(x => JSON.stringify(x))).join(',');
|
||||||
|
let {result, exceptionDetails} = await this._client.send('Runtime.callFunctionOn', {
|
||||||
|
objectId,
|
||||||
|
functionDeclaration: `function(){return (${fun})(${argsString})}`,
|
||||||
|
returnByValue: false,
|
||||||
|
});
|
||||||
|
this._client.send('Runtime.releaseObject', {objectId});
|
||||||
|
if (exceptionDetails) {
|
||||||
|
let message = await helper.getExceptionMessage(this._client, exceptionDetails);
|
||||||
|
throw new Error('Evaluation failed: ' + message);
|
||||||
|
}
|
||||||
|
let value = helper.serializeRemoteObjet(this._client, result);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} querySelector
|
||||||
|
* @param {function(!Element):T} fun
|
||||||
|
* @param {!Array<*>} args
|
||||||
|
* @return {!Promise<?T>}
|
||||||
|
*/
|
||||||
|
async $(querySelector, fun, ...args) {
|
||||||
|
let nodeId = await this._querySelector(querySelector);
|
||||||
|
if (!nodeId)
|
||||||
|
return null;
|
||||||
|
return this._callFunctionOnNode(await this._querySelector(querySelector), fun, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} querySelector
|
||||||
|
* @param {function(!Element):T} fun
|
||||||
|
* @param {!Array<*>} args
|
||||||
|
* @return {!Promise<!Array<T>>}
|
||||||
|
*/
|
||||||
|
async $$(querySelector, fun, ...args) {
|
||||||
|
let nodeIds = await this._querySelectorAll(querySelector);
|
||||||
|
return Promise.all(nodeIds.map((nodeId, index) => this._callFunctionOnNode(nodeId, fun, index, ...args)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
|
@ -52,6 +52,36 @@ class Helper {
|
|||||||
}
|
}
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!Connection} client
|
||||||
|
* @param {!Object} remoteObject
|
||||||
|
*/
|
||||||
|
static async serializeRemoteObjet(client, remoteObject) {
|
||||||
|
if (remoteObject.unserializableValue) {
|
||||||
|
switch (remoteObject.unserializableValue) {
|
||||||
|
case '-0':
|
||||||
|
return -0;
|
||||||
|
case 'NaN':
|
||||||
|
return NaN;
|
||||||
|
case 'Infinity':
|
||||||
|
return Infinity;
|
||||||
|
case '-Infinity':
|
||||||
|
return -Infinity;
|
||||||
|
default:
|
||||||
|
throw new Error('Unsupported unserializable value: ' + remoteObject.unserializableValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!remoteObject.objectId)
|
||||||
|
return remoteObject.value;
|
||||||
|
let response = client.send('Runtime.callFunctionOn', {
|
||||||
|
objectId: remoteObject.objectId,
|
||||||
|
functionDeclaration: 'function() { return this; }',
|
||||||
|
returnByValue: true,
|
||||||
|
});
|
||||||
|
client.send('Runtime.releaseObject', {objectId: remoteObject.objectId});
|
||||||
|
return (await response).result.value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Helper;
|
module.exports = Helper;
|
||||||
|
15
test/assets/playground.html
Normal file
15
test/assets/playground.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Playground</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<button>A button</button>
|
||||||
|
<textarea>A text area</textarea>
|
||||||
|
<div id="first">First div</div>
|
||||||
|
<div id="second">
|
||||||
|
Second div
|
||||||
|
<span class="inner">Inner span</span>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
27
test/test.js
27
test/test.js
@ -630,6 +630,33 @@ describe('Puppeteer', function() {
|
|||||||
]);
|
]);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Query selector', function() {
|
||||||
|
it('Page.$', SX(async function() {
|
||||||
|
await page.navigate(STATIC_PREFIX + '/playground.html');
|
||||||
|
expect(await page.$('#first', element => element.textContent)).toBe('First div');
|
||||||
|
expect(await page.$('#second span', element => element.textContent)).toBe('Inner span');
|
||||||
|
expect(await page.$('#first', (element, arg1) => arg1, 'value1')).toBe('value1');
|
||||||
|
expect(await page.$('#first', (element, arg1, arg2) => arg2, 'value1', 'value2')).toBe('value2');
|
||||||
|
expect(await page.$('doesnot-exist', element => 5)).toBe(null);
|
||||||
|
expect(await page.$('button', function(element, arg1) {
|
||||||
|
element.textContent = arg1;
|
||||||
|
return true;
|
||||||
|
}, 'new button text')).toBe(true);
|
||||||
|
expect(await page.$('button', function(element) {
|
||||||
|
return element.textContent;
|
||||||
|
})).toBe('new button text');
|
||||||
|
}));
|
||||||
|
it('Page.$$', SX(async function() {
|
||||||
|
await page.navigate(STATIC_PREFIX + '/playground.html');
|
||||||
|
expect((await page.$$('div', element => element.textContent)).length).toBe(2);
|
||||||
|
expect((await page.$$('div', (element, index) => index))[0]).toBe(0);
|
||||||
|
expect((await page.$$('div', (element, index) => index))[1]).toBe(1);
|
||||||
|
expect((await page.$$('doesnotexist', function(){})).length).toBe(0);
|
||||||
|
expect((await page.$$('div', element => element.textContent))[0]).toBe('First div');
|
||||||
|
expect((await page.$$('span', (element, index, arg1) => arg1, 'value1'))[0]).toBe('value1');
|
||||||
|
}));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Since Jasmine doesn't like async functions, they should be wrapped
|
// Since Jasmine doesn't like async functions, they should be wrapped
|
||||||
|
Loading…
Reference in New Issue
Block a user