diff --git a/docs/api.md b/docs/api.md index 6476d7b577..cd7afc2793 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1615,16 +1615,29 @@ Page is guaranteed to have a main frame which persists during navigations. > **NOTE** Screenshots take at least 1/6 second on OS X. See https://crbug.com/741689 for discussion. #### page.select(selector, ...values) -- `selector` <[string]> A [selector] to query page for -- `...values` <...[string]> Values of options to select. If the `` has the `multiple` attribute, all matching options are selected, otherwise only the first option matching one of the passed options is selected. String values are equivalent to `{value:'string'}`. Option is considered matching if all specified properties match. + - `value` <[string]> Matches by `option.value`. + - `label` <[string]> Matches by `option.label`. + - `id` <[string]> Matches by `option.id`. + - `index` <[number]> Matches by the index. - returns: <[Promise]<[Array]<[string]>>> An array of option values that have been successfully selected. Triggers a `change` and `input` event once all the provided options have been selected. If there's no `` has the `multiple` attribute, all values are considered, otherwise only the first one is taken into account. +- `selector` <[string]> A [selector] to query frame for. +- `...values` <...[string]|[Object]> Options to select. If the `` element matching `selector`, the method throws an error. ```js -frame.select('select#colors', 'blue'); // single selection -frame.select('select#colors', 'red', 'green', 'blue'); // multiple selections +// single selection matching the value +frame.select('select#colors', 'blue'); + +// single selection matching both the value and the label +frame.select('select#colors', { value: 'blue', label: 'Blue' }); + +// multiple selection +frame.select('select#colors', 'red', 'green', 'blue'); + +// multiple selection matching blue, red and second option +frame.select('select#colors', { value: 'blue' }, { index: 2 }, 'red'); ``` #### frame.setContent(html[, options]) @@ -3523,15 +3549,28 @@ This method scrolls element into view if needed, and then uses [page.screenshot] If the element is detached from DOM, the method throws an error. #### elementHandle.select(...values) -- `...values` <...[string]> Values of options to select. If the `` has the `multiple` attribute, all matching options are selected, otherwise only the first option matching one of the passed options is selected. String values are equivalent to `{value:'string'}`. Option is considered matching if all specified properties match. + - `value` <[string]> Matches by `option.value`. + - `label` <[string]> Matches by `option.label`. + - `id` <[string]> Matches by `option.id`. + - `index` <[number]> Matches by the index. - returns: <[Promise]<[Array]<[string]>>> An array of option values that have been successfully selected. Triggers a `change` and `input` event once all the provided options have been selected. If element is not a ` element.'); const options = Array.from(element.options); element.value = undefined; - for (const option of options) { - option.selected = values.includes(option.value); + for (let index = 0; index < options.length; index++) { + const option = options[index]; + option.selected = optionsToSelect.some(optionToSelect => { + let matches = true; + if (optionToSelect.value !== undefined) + matches = matches && optionToSelect.value === option.value; + if (optionToSelect.label !== undefined) + matches = matches && optionToSelect.label === option.label; + if (optionToSelect.id !== undefined) + matches = matches && optionToSelect.id === option.id; + if (optionToSelect.index !== undefined) + matches = matches && optionToSelect.index === index; + return matches; + }); if (option.selected && !element.multiple) break; } element.dispatchEvent(new Event('input', { 'bubbles': true })); element.dispatchEvent(new Event('change', { 'bubbles': true })); return options.filter(option => option.selected).map(option => option.value); - }, values); + }, options); } async fill(value: string): Promise { diff --git a/src/chromium/Page.ts b/src/chromium/Page.ts index a86b370c64..c99a926a38 100644 --- a/src/chromium/Page.ts +++ b/src/chromium/Page.ts @@ -33,7 +33,7 @@ import { PDF } from './features/pdf'; import { Frame } from './Frame'; import { FrameManager, FrameManagerEvents } from './FrameManager'; import { Keyboard, Mouse } from './Input'; -import { ClickOptions, createJSHandle, ElementHandle, JSHandle, MultiClickOptions, PointerActionOptions } from './JSHandle'; +import { ClickOptions, createJSHandle, ElementHandle, JSHandle, MultiClickOptions, PointerActionOptions, SelectOption } from './JSHandle'; import { NetworkManagerEvents, Response } from './NetworkManager'; import { Protocol } from './protocol'; import { getExceptionMessage, releaseObject, valueFromRemoteObject } from './protocolHelper'; @@ -715,7 +715,7 @@ export class Page extends EventEmitter { return this.mainFrame().hover(selector, options); } - select(selector: string, ...values: string[]): Promise { + select(selector: string, ...values: (string | SelectOption)[]): Promise { return this.mainFrame().select(selector, ...values); } diff --git a/test/assets/input/select.html b/test/assets/input/select.html index 879a537a76..53dd06adf6 100644 --- a/test/assets/input/select.html +++ b/test/assets/input/select.html @@ -18,7 +18,7 @@ - +