[api] Introduce Page.select method (#779)

This patch adds `Page.select` method to select
values in a `select` tag.
This commit is contained in:
Alix Axel 2017-09-25 11:23:34 +02:00 committed by Andrey Lushnikov
parent acdb588964
commit 45f264024b
4 changed files with 136 additions and 0 deletions

View File

@ -60,6 +60,7 @@
+ [page.press(key[, options])](#pagepresskey-options)
+ [page.reload(options)](#pagereloadoptions)
+ [page.screenshot([options])](#pagescreenshotoptions)
+ [page.select(selector, ...values)](#pageselectselector-values)
+ [page.setContent(html)](#pagesetcontenthtml)
+ [page.setCookie(...cookies)](#pagesetcookiecookies)
+ [page.setExtraHTTPHeaders(headers)](#pagesetextrahttpheadersheaders)
@ -725,6 +726,19 @@ Shortcut for [`keyboard.down`](#keyboarddownkey-options) and [`keyboard.up`](#ke
- `omitBackground` <[boolean]> Hides default white background and allows capturing screenshots with transparency. Defaults to `false`.
- returns: <[Promise]<[Buffer]>> Promise which resolves to buffer with captured screenshot
#### page.select(selector, ...values)
- `selector` <[string]> A [selector] to query page for
- `...values` <...[string]> Values of options to select. If the `<select>` has the `multiple` attribute, all values are considered, otherwise only the first one is taken into account.
- returns: <[Promise]>
Triggers a `change` and `input` event once all the provided options have been selected.
If there's no `<select>` element matching `selector`, the method throws an error.
```js
page.select('select#colors', 'blue'); // single selection
page.select('select#colors', 'red', 'green', 'blue'); // multiple selections
```
#### page.setContent(html)
- `html` <[string]> HTML markup to assign to the page.
- returns: <[Promise]>

View File

@ -693,6 +693,29 @@ class Page extends EventEmitter {
await handle.dispose();
}
/**
* @param {string} selector
* @param {!Array<string>} values
*/
async select(selector, ...values) {
await this.$eval(selector, (element, values) => {
if (element.nodeName.toLowerCase() !== 'select')
throw new Error('Element is not a <select> element.');
const options = Array.from(element.options);
if (element.multiple) {
for (const option of options)
option.selected = values.includes(option.value);
} else {
element.value = values.shift();
}
element.dispatchEvent(new Event('change'));
element.dispatchEvent(new Event('input'));
}, values);
}
/**
* @param {string} text
* @param {{delay: (number|undefined)}=} options

View File

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html>
<head>
<title>Selection Test</title>
</head>
<body>
<select>
<option value="black">Black</option>
<option value="blue">Blue</option>
<option value="brown">Brown</option>
<option value="cyan">Cyan</option>
<option value="gray">Gray</option>
<option value="green">Green</option>
<option value="indigo">Indigo</option>
<option value="magenta">Magenta</option>
<option value="orange">Orange</option>
<option value="pink">Pink</option>
<option value="purple">Purple</option>
<option value="red">Red</option>
<option value="violet">Violet</option>
<option value="white">White</option>
<option value="yellow">Yellow</option>
</select>
<script>
window.result = {
onInput: null,
onChange: null,
};
let select = document.querySelector('select');
function makeEmpty() {
for (let i = select.options.length - 1; i >= 0; --i) {
select.remove(i);
}
}
function makeMultiple() {
select.setAttribute('multiple', true);
}
select.addEventListener('input', () => {
result.onInput = Array.from(select.querySelectorAll('option:checked')).map((option) => {
return option.value;
});
}, false);
select.addEventListener('change', () => {
result.onChange = Array.from(select.querySelectorAll('option:checked')).map((option) => {
return option.value;
});
}, false);
</script>
</body>
</html>

View File

@ -1177,6 +1177,7 @@ describe('Page', function() {
expect(element).toBe(null);
}));
});
describe('Page.$$', function() {
it('should query existing elements', SX(async function() {
await page.setContent('<div>A</div><br/><div>B</div>');
@ -1530,6 +1531,7 @@ describe('Page', function() {
expect(await page.evaluate(() => navigator.userAgent)).toContain('Safari');
}));
});
describe('Page.setExtraHTTPHeaders', function() {
it('should work', SX(async function() {
await page.setExtraHTTPHeaders({
@ -1551,6 +1553,7 @@ describe('Page', function() {
expect(error.message).toBe('Expected value of header "foo" to be String, but "number" is found.');
}));
});
describe('Page.authenticate', function() {
it('should work', SX(async function() {
server.setAuth('/empty.html', 'user', 'pass');
@ -1588,6 +1591,7 @@ describe('Page', function() {
expect(response.status).toBe(401);
}));
});
describe('Page.setContent', function() {
const expectedOutput = '<html><head></head><body><div>hello</div></body></html>';
it('should work', SX(async function() {
@ -1609,6 +1613,7 @@ describe('Page', function() {
expect(result).toBe(`${doctype}${expectedOutput}`);
}));
});
describe('Network Events', function() {
it('Page.Events.Request', SX(async function() {
const requests = [];
@ -2021,6 +2026,45 @@ describe('Page', function() {
}));
});
describe('Page.select', function() {
it('should select single option', SX(async function() {
await page.goto(PREFIX + '/input/select.html');
await page.select('select', 'blue');
expect(await page.evaluate(() => result.onInput)).toEqual(['blue']);
expect(await page.evaluate(() => result.onChange)).toEqual(['blue']);
}));
it('should select multiple options', SX(async function() {
await page.goto(PREFIX + '/input/select.html');
await page.evaluate(() => makeMultiple());
await page.select('select', 'blue', 'green', 'red');
expect(await page.evaluate(() => result.onInput)).toEqual(['blue', 'green', 'red']);
expect(await page.evaluate(() => result.onChange)).toEqual(['blue', 'green', 'red']);
}));
it('should work with no options', SX(async function() {
await page.goto(PREFIX + '/input/select.html');
await page.evaluate(() => makeEmpty());
await page.select('select', '42');
expect(await page.evaluate(() => result.onInput)).toEqual([]);
expect(await page.evaluate(() => result.onChange)).toEqual([]);
}));
it('should not select a non-existent option', SX(async function() {
await page.goto(PREFIX + '/input/select.html');
await page.select('select', '42');
expect(await page.evaluate(() => result.onInput)).toEqual([]);
expect(await page.evaluate(() => result.onChange)).toEqual([]);
}));
it('should throw', SX(async function() {
let error = null;
await page.goto(PREFIX + '/input/select.html');
await page.select('body', '').catch(e => error = e);
expect(error.message).toContain('Element is not a <select> element.');
}));
});
describe('Tracing', function() {
const outputFile = path.join(__dirname, 'assets', 'trace.json');
afterEach(function() {