[api] Introduce Page.select method (#779)
This patch adds `Page.select` method to select values in a `select` tag.
This commit is contained in:
parent
acdb588964
commit
45f264024b
14
docs/api.md
14
docs/api.md
@ -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]>
|
||||
|
23
lib/Page.js
23
lib/Page.js
@ -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
|
||||
|
55
test/assets/input/select.html
Normal file
55
test/assets/input/select.html
Normal 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>
|
44
test/test.js
44
test/test.js
@ -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() {
|
||||
|
Loading…
Reference in New Issue
Block a user