Kill page.$ and page.$$ functions (#197)

page.$ and page.$$ conflicts with our ideas about element handles.

This patch removes functions in favor of future implementation.

References #111
This commit is contained in:
Andrey Lushnikov 2017-08-03 13:35:31 -07:00 committed by JoelEinbinder
parent 211c372a3a
commit 31224392bb
4 changed files with 19 additions and 155 deletions

View File

@ -25,8 +25,6 @@
+ [event: 'requestfailed'](#event-requestfailed) + [event: 'requestfailed'](#event-requestfailed)
+ [event: 'requestfinished'](#event-requestfinished) + [event: 'requestfinished'](#event-requestfinished)
+ [event: 'response'](#event-response) + [event: 'response'](#event-response)
+ [page.$(selector, pageFunction, ...args)](#pageselector-pagefunction-args)
+ [page.$$(selector, pageFunction, ...args)](#pageselector-pagefunction-args)
+ [page.addScriptTag(url)](#pageaddscripttagurl) + [page.addScriptTag(url)](#pageaddscripttagurl)
+ [page.click(selector[, options])](#pageclickselector-options) + [page.click(selector[, options])](#pageclickselector-options)
+ [page.close()](#pageclose) + [page.close()](#pageclose)
@ -81,8 +79,6 @@
+ [dialog.message()](#dialogmessage) + [dialog.message()](#dialogmessage)
+ [dialog.type](#dialogtype) + [dialog.type](#dialogtype)
* [class: Frame](#class-frame) * [class: Frame](#class-frame)
+ [frame.$(selector, pageFunction, ...args)](#frameselector-pagefunction-args)
+ [frame.$$(selector, pageFunction, ...args)](#frameselector-pagefunction-args)
+ [frame.addScriptTag(url)](#frameaddscripttagurl) + [frame.addScriptTag(url)](#frameaddscripttagurl)
+ [frame.childFrames()](#framechildframes) + [frame.childFrames()](#framechildframes)
+ [frame.click(selector[, options])](#frameclickselector-options) + [frame.click(selector[, options])](#frameclickselector-options)
@ -316,30 +312,6 @@ Emitted when a request is successfully finished.
Emitted when a [response] is received. Emitted when a [response] is received.
#### page.$(selector, pageFunction, ...args)
- `selector` <[string]> A [selector] to be matched in the page
- `pageFunction` <[function]\([Element]\)> Function to be evaluated with first element matching `selector`
- `...args` <...[string]> Arguments to pass to `pageFunction`
- returns: <[Promise]<[Object]>> Promise which resolves to function return value.
Example:
```js
const outerhtml = await page.$('#box', e => e.outerHTML);
```
Shortcut for [page.mainFrame().$(selector, pageFunction, ...args)](#frameselector-pagefunction-args).
#### page.$$(selector, pageFunction, ...args)
- `selector` <[string]> A [selector] to be matched in the page
- `pageFunction` <[function]\([Element]\)> Function to be evaluted for every element matching `selector`.
- `...args` <...[string]> Arguments to pass to `pageFunction`
- returns: <[Promise]<[Array]<[Object]>>> Promise which resolves to array of function return values.
Example:
```js
const headings = await page.$$('h1,h2,h3,h4', el => el.textContent);
for (const heading of headings) console.log(heading);
```
Shortcut for [page.mainFrame().$$(selector, pageFunction, ...args)](#frameselector-pagefunction-args-1).
#### page.addScriptTag(url) #### page.addScriptTag(url)
- `url` <[string]> Url of a script to be added - `url` <[string]> Url of a script to be added
- returns: <[Promise]> Promise which resolves as the script gets added and loads. - returns: <[Promise]> Promise which resolves as the script gets added and loads.
@ -916,28 +888,6 @@ browser.newPage().then(async page => {
}); });
``` ```
#### frame.$(selector, pageFunction, ...args)
- `selector` <[string]> A [selector] to be matched in the page
- `pageFunction` <[function]\([Element]\)> Function to be evaluated with first element matching `selector`
- `...args` <...[string]> Arguments to pass to `pageFunction`
- returns: <[Promise]<[Object]>> Promise which resolves to function return value.
Example:
```js
const outerhtml = await page.$('#box', e => e.outerHTML);
```
#### frame.$$(selector, pageFunction, ...args)
- `selector` <[string]> A [selector] to be matched in the page
- `pageFunction` <[function]\([Element]\)> Function to be evaluted for every element matching `selector`.
- `...args` <...[string]> Arguments to pass to `pageFunction`
- returns: <[Promise]<[Array]<[Object]>>> Promise which resolves to array of function return values.
Example:
```js
const headings = await page.$$('h1,h2,h3,h4', el => el.textContent);
for (const heading of headings) console.log(heading);
```
#### frame.addScriptTag(url) #### frame.addScriptTag(url)
- `url` <[string]> Url of a script to be added - `url` <[string]> Url of a script to be added

View File

@ -317,40 +317,6 @@ class Frame {
return this._client.send('DOM.setFileInputFiles', { objectId, files: filePaths }); return this._client.send('DOM.setFileInputFiles', { objectId, files: filePaths });
} }
/**
* @template T
* @param {string} selector
* @param {function(!Element):T} pageFunction
* @param {!Array<*>} args
* @return {!Promise<?T>}
*/
async $(selector, pageFunction, ...args) {
let argsString = ['node'].concat(args.map(x => JSON.stringify(x))).join(',');
let expression = `(()=>{
let node = document.querySelector(${JSON.stringify(selector)});
if (!node)
return null;
return (${pageFunction})(${argsString});
})()`;
return this.evaluate(expression);
}
/**
* @template T
* @param {string} selector
* @param {function(!Element):T} pageFunction
* @param {!Array<*>} args
* @return {!Promise<!Array<T>>}
*/
async $$(selector, pageFunction, ...args) {
let argsString = ['node, index'].concat(args.map(x => JSON.stringify(x))).join(',');
let expression = `(()=>{
let nodes = document.querySelectorAll(${JSON.stringify(selector)});
return Array.prototype.map.call(nodes, (node, index) => (${pageFunction})(${argsString}));
})()`;
return this.evaluate(expression);
}
/** /**
* @return {!Promise<string>} * @return {!Promise<string>}
*/ */

View File

@ -623,28 +623,6 @@ class Page extends EventEmitter {
async uploadFile(selector, ...filePaths) { async uploadFile(selector, ...filePaths) {
return this.mainFrame().uploadFile(selector, ...filePaths); return this.mainFrame().uploadFile(selector, ...filePaths);
} }
/**
* @template T
* @param {string} selector
* @param {function(!Element):T} pageFunction
* @param {!Array<*>} args
* @return {!Promise<?T>}
*/
async $(selector, pageFunction, ...args) {
return this.mainFrame().$(selector, pageFunction, ...args);
}
/**
* @template T
* @param {string} selector
* @param {function(!Element):T} pageFunction
* @param {!Array<*>} args
* @return {!Promise<!Array<T>>}
*/
async $$(selector, pageFunction, ...args) {
return this.mainFrame().$$(selector, pageFunction, ...args);
}
} }
/** @enum {string} */ /** @enum {string} */

View File

@ -311,13 +311,10 @@ describe('Page', function() {
it('should work when node is added through innerHTML', SX(async function() { it('should work when node is added through innerHTML', SX(async function() {
await page.navigate(EMPTY_PAGE); await page.navigate(EMPTY_PAGE);
let frame = page.mainFrame(); let watchdog = page.waitForSelector('h3 div');
let added = false; await page.evaluate(addElement, 'span');
frame.waitForSelector('h3 div').then(() => added = true); await page.evaluate(() => document.querySelector('span').innerHTML = '<h3><div></div></h3>');
expect(added).toBe(false); await watchdog;
await frame.evaluate(addElement, 'span');
await page.$('span', span => span.innerHTML = '<h3><div></div></h3>');
expect(added).toBe(true);
})); }));
it('Page.waitForSelector is shortcut for main frame', SX(async function() { it('Page.waitForSelector is shortcut for main frame', SX(async function() {
@ -956,21 +953,21 @@ describe('Page', function() {
await page.navigate(PREFIX + '/input/textarea.html'); await page.navigate(PREFIX + '/input/textarea.html');
await page.focus('textarea'); await page.focus('textarea');
await page.press('a', {text: 'f'}); await page.press('a', {text: 'f'});
expect(await page.$('textarea', t => t.value)).toBe('f'); expect(await page.evaluate(() => document.querySelector('textarea').value)).toBe('f');
await page.evaluate(() => window.addEventListener('keydown', e => e.preventDefault(), true)); await page.evaluate(() => window.addEventListener('keydown', e => e.preventDefault(), true));
await page.press('a', {text: 'y'}); await page.press('a', {text: 'y'});
expect(await page.$('textarea', t => t.value)).toBe('f'); expect(await page.evaluate(() => document.querySelector('textarea').value)).toBe('f');
})); }));
it('should send a character with sendCharacter', SX(async function() { it('should send a character with sendCharacter', SX(async function() {
await page.navigate(PREFIX + '/input/textarea.html'); await page.navigate(PREFIX + '/input/textarea.html');
await page.focus('textarea'); await page.focus('textarea');
await page.keyboard.sendCharacter('嗨'); await page.keyboard.sendCharacter('嗨');
expect(await page.$('textarea', t => t.value)).toBe('嗨'); expect(await page.evaluate(() => document.querySelector('textarea').value)).toBe('嗨');
await page.evaluate(() => window.addEventListener('keydown', e => e.preventDefault(), true)); await page.evaluate(() => window.addEventListener('keydown', e => e.preventDefault(), true));
await page.keyboard.sendCharacter('a'); await page.keyboard.sendCharacter('a');
expect(await page.$('textarea', t => t.value)).toBe('嗨a'); expect(await page.evaluate(() => document.querySelector('textarea').value)).toBe('嗨a');
})); }));
it('should report shiftKey', SX(async function(){ it('should report shiftKey', SX(async function(){
await page.navigate(PREFIX + '/input/keyboard.html'); await page.navigate(PREFIX + '/input/keyboard.html');
@ -1070,13 +1067,14 @@ describe('Page', function() {
it('should scroll and click the button', SX(async function(){ it('should scroll and click the button', SX(async function(){
await page.navigate(PREFIX + '/input/scrollable.html'); await page.navigate(PREFIX + '/input/scrollable.html');
await page.click('#button-5'); await page.click('#button-5');
expect(await page.$('#button-5', button => button.textContent)).toBe('clicked'); expect(await page.evaluate(() => document.querySelector('#button-5').textContent)).toBe('clicked');
await page.click('#button-80'); await page.click('#button-80');
expect(await page.$('#button-80', button => button.textContent)).toBe('clicked'); expect(await page.evaluate(() => document.querySelector('#button-80').textContent)).toBe('clicked');
})); }));
it('should click a partially obscured button', SX(async function() { it('should click a partially obscured button', SX(async function() {
await page.navigate(PREFIX + '/input/button.html'); await page.navigate(PREFIX + '/input/button.html');
await page.$('button', button => { await page.evaluate(() => {
let button = document.querySelector('button');
button.textContent = 'Some really long text that will go offscreen'; button.textContent = 'Some really long text that will go offscreen';
button.style.position = 'absolute'; button.style.position = 'absolute';
button.style.left = '368px'; button.style.left = '368px';
@ -1089,7 +1087,7 @@ describe('Page', function() {
await page.focus('textarea'); await page.focus('textarea');
let text = 'This is the text that we are going to try to select. Let\'s see how it goes.'; let text = 'This is the text that we are going to try to select. Let\'s see how it goes.';
await page.type(text); await page.type(text);
await page.$('textarea', textarea => textarea.scrollTop = 0); await page.evaluate(() => document.querySelector('textarea').scrollTop = 0);
let {x, y} = await page.evaluate(dimensions); let {x, y} = await page.evaluate(dimensions);
await page.mouse.move(x + 2,y + 2); await page.mouse.move(x + 2,y + 2);
await page.mouse.down(); await page.mouse.down();
@ -1110,20 +1108,20 @@ describe('Page', function() {
it('should trigger hover state', SX(async function(){ it('should trigger hover state', SX(async function(){
await page.navigate(PREFIX + '/input/scrollable.html'); await page.navigate(PREFIX + '/input/scrollable.html');
await page.hover('#button-6'); await page.hover('#button-6');
expect(await page.$('button:hover', button => button.id)).toBe('button-6'); expect(await page.evaluate(() => document.querySelector('button:hover').id)).toBe('button-6');
await page.hover('#button-2'); await page.hover('#button-2');
expect(await page.$('button:hover', button => button.id)).toBe('button-2'); expect(await page.evaluate(() => document.querySelector('button:hover').id)).toBe('button-2');
await page.hover('#button-91'); await page.hover('#button-91');
expect(await page.$('button:hover', button => button.id)).toBe('button-91'); expect(await page.evaluate(() => document.querySelector('button:hover').id)).toBe('button-91');
})); }));
it('should fire contextmenu event on right click', SX(async function(){ it('should fire contextmenu event on right click', SX(async function(){
await page.navigate(PREFIX + '/input/scrollable.html'); await page.navigate(PREFIX + '/input/scrollable.html');
await page.click('#button-8', {button: 'right'}); await page.click('#button-8', {button: 'right'});
expect(await page.$('#button-8', button => button.textContent)).toBe('context menu'); expect(await page.evaluate(() => document.querySelector('#button-8').textContent)).toBe('context menu');
})); }));
it('should set modifier keys on click', SX(async function(){ it('should set modifier keys on click', SX(async function(){
await page.navigate(PREFIX + '/input/scrollable.html'); await page.navigate(PREFIX + '/input/scrollable.html');
await page.$('#button-3', button => button.addEventListener('mousedown', e => window.lastEvent = e, true)); await page.evaluate(() => document.querySelector('#button-3').addEventListener('mousedown', e => window.lastEvent = e, true));
let modifiers = {'Shift': 'shiftKey', 'Control': 'ctrlKey', 'Alt': 'altKey', 'Meta': 'metaKey'}; let modifiers = {'Shift': 'shiftKey', 'Control': 'ctrlKey', 'Alt': 'altKey', 'Meta': 'metaKey'};
for (let modifier in modifiers) { for (let modifier in modifiers) {
await page.keyboard.down(modifier); await page.keyboard.down(modifier);
@ -1141,7 +1139,7 @@ describe('Page', function() {
it('should specify repeat property', SX(async function(){ it('should specify repeat property', SX(async function(){
await page.navigate(PREFIX + '/input/textarea.html'); await page.navigate(PREFIX + '/input/textarea.html');
await page.focus('textarea'); await page.focus('textarea');
await page.$('textarea', textarea => textarea.addEventListener('keydown', e => window.lastEvent = e, true)); await page.evaluate(() => document.querySelector('textarea').addEventListener('keydown', e => window.lastEvent = e, true));
await page.keyboard.down('a', {text: 'a'}); await page.keyboard.down('a', {text: 'a'});
expect(await page.evaluate(() => window.lastEvent.repeat)).toBe(false); expect(await page.evaluate(() => window.lastEvent.repeat)).toBe(false);
await page.press('a'); await page.press('a');
@ -1394,34 +1392,6 @@ describe('Page', function() {
})); }));
}); });
describe('Query selector', function() {
it('Page.$', SX(async function() {
await page.navigate(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(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');
}));
});
describe('Page.screenshot', function() { describe('Page.screenshot', function() {
it('should work', SX(async function() { it('should work', SX(async function() {
await page.setViewport({width: 500, height: 500}); await page.setViewport({width: 500, height: 500});