Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,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)
Expand Down Expand Up @@ -720,6 +721,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]>
Expand Down
23 changes: 23 additions & 0 deletions lib/Page.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
55 changes: 55 additions & 0 deletions test/assets/input/select.html
Original file line number Diff line number Diff line change
@@ -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 changes: 44 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1168,6 +1168,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>');
Expand Down Expand Up @@ -1519,6 +1520,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({
Expand All @@ -1529,6 +1531,7 @@ describe('Page', function() {
expect(request.headers['foo']).toBe('bar');
}));
});

describe('Page.authenticate', function() {
it('should work', SX(async function() {
server.setAuth('/empty.html', 'user', 'pass');
Expand Down Expand Up @@ -1566,6 +1569,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() {
Expand All @@ -1587,6 +1591,7 @@ describe('Page', function() {
expect(result).toBe(`${doctype}${expectedOutput}`);
}));
});

describe('Network Events', function() {
it('Page.Events.Request', SX(async function() {
const requests = [];
Expand Down Expand Up @@ -1999,6 +2004,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() {
Expand Down