feat(inputValue): implement inputValue for select elements (#7951)

This commit is contained in:
Fabian Mendez 2021-08-03 10:22:40 -05:00 committed by GitHub
parent 7c3a037b86
commit 731f9453c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 26 additions and 19 deletions

View File

@ -516,7 +516,7 @@ Returns the `element.innerText`.
## async method: ElementHandle.inputValue
- returns: <[string]>
Returns `input.value` for `<input>` or `<textarea>` element. Throws for non-input elements.
Returns `input.value` for `<input>` or `<textarea>` or `<select>` element. Throws for non-input elements.
### option: ElementHandle.inputValue.timeout = %%-input-timeout-%%

View File

@ -855,7 +855,7 @@ Returns `element.innerText`.
## async method: Frame.inputValue
- returns: <[string]>
Returns `input.value` for the selected `<input>` or `<textarea>` element. Throws for non-input elements.
Returns `input.value` for the selected `<input>` or `<textarea>` or `<select>` element. Throws for non-input elements.
### param: Frame.inputValue.selector = %%-input-selector-%%

View File

@ -520,7 +520,7 @@ Returns the `element.innerText`.
## async method: Locator.inputValue
- returns: <[string]>
Returns `input.value` for `<input>` or `<textarea>` element. Throws for non-input elements.
Returns `input.value` for `<input>` or `<textarea>` or `<select>` element. Throws for non-input elements.
### option: Locator.inputValue.timeout = %%-input-timeout-%%

View File

@ -1961,7 +1961,7 @@ Returns `element.innerText`.
## async method: Page.inputValue
- returns: <[string]>
Returns `input.value` for the selected `<input>` or `<textarea>` element. Throws for non-input elements.
Returns `input.value` for the selected `<input>` or `<textarea>` or `<select>` element. Throws for non-input elements.
### param: Page.inputValue.selector = %%-input-selector-%%

View File

@ -22,7 +22,7 @@ export type FatalDOMError =
'error:notfillablenumberinput' |
'error:notvaliddate' |
'error:notinput' |
'error:notinputvalue' |
'error:hasnovalue' |
'error:notselect' |
'error:notcheckbox' |
'error:notmultiplefileinput';

View File

@ -181,8 +181,8 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
async inputValue(): Promise<string> {
return throwFatalDOMError(await this.evaluateInUtility(([injeced, node]) => {
if (node.nodeType !== Node.ELEMENT_NODE || (node.nodeName !== 'INPUT' && node.nodeName !== 'TEXTAREA'))
return 'error:notinputvalue';
if (node.nodeType !== Node.ELEMENT_NODE || (node.nodeName !== 'INPUT' && node.nodeName !== 'TEXTAREA' && node.nodeName !== 'SELECT'))
return 'error:hasnovalue';
const element = node as unknown as (HTMLInputElement | HTMLTextAreaElement);
return { value: element.value };
}, undefined)).value;
@ -883,8 +883,8 @@ export function throwFatalDOMError<T>(result: T | FatalDOMError): T {
throw new Error(`Malformed value`);
if (result === 'error:notinput')
throw new Error('Node is not an HTMLInputElement');
if (result === 'error:notinputvalue')
throw new Error('Node is not an HTMLInputElement or HTMLTextAreaElement');
if (result === 'error:hasnovalue')
throw new Error('Node is not an HTMLInputElement or HTMLTextAreaElement or HTMLSelectElement');
if (result === 'error:notselect')
throw new Error('Element is not a <select> element.');
if (result === 'error:notcheckbox')
@ -1039,8 +1039,8 @@ export function inputValueTask(selector: SelectorInfo): SchedulableTask<string>
if (!element)
return continuePolling;
progress.log(` selector resolved to ${injected.previewNode(element)}`);
if (element.nodeName !== 'INPUT' && element.nodeName !== 'TEXTAREA')
return 'error:notinputvalue';
if (element.nodeName !== 'INPUT' && element.nodeName !== 'TEXTAREA' && element.nodeName !== 'SELECT')
return 'error:hasnovalue';
return (element as any).value;
});
}, { parsed: selector.parsed, strict: selector.strict, });

View File

@ -2,3 +2,4 @@
more text</div></div><input id="check" type=checkbox checked foo="bar&quot;">
<input id="input"></input>
<textarea id="textarea"></textarea>
<select id="select"><option></option><option value="foo"></option></select>

View File

@ -42,6 +42,9 @@ it('getAttribute should work', async ({ page, server }) => {
it('inputValue should work', async ({ page, server }) => {
await page.goto(`${server.PREFIX}/dom.html`);
await page.selectOption('#select', 'foo');
expect(await page.inputValue('#select')).toBe('foo');
await page.fill('#textarea', 'text value');
expect(await page.inputValue('#textarea')).toBe('text value');
@ -50,9 +53,9 @@ it('inputValue should work', async ({ page, server }) => {
const handle = await page.$('#input');
expect(await handle.inputValue()).toBe('input value');
expect(await page.inputValue('#inner').catch(e => e.message)).toContain('Node is not an HTMLInputElement or HTMLTextAreaElement');
expect(await page.inputValue('#inner').catch(e => e.message)).toContain('Node is not an HTMLInputElement or HTMLTextAreaElement or HTMLSelectElement');
const handle2 = await page.$('#inner');
expect(await handle2.inputValue().catch(e => e.message)).toContain('Node is not an HTMLInputElement or HTMLTextAreaElement');
expect(await handle2.inputValue().catch(e => e.message)).toContain('Node is not an HTMLInputElement or HTMLTextAreaElement or HTMLSelectElement');
});
it('innerHTML should work', async ({ page, server }) => {

View File

@ -42,6 +42,9 @@ it('getAttribute should work', async ({ page, server }) => {
it('inputValue should work', async ({ page, server }) => {
await page.goto(`${server.PREFIX}/dom.html`);
await page.selectOption('#select', 'foo');
expect(await page.inputValue('#select')).toBe('foo');
await page.fill('#textarea', 'text value');
expect(await page.inputValue('#textarea')).toBe('text value');
@ -50,9 +53,9 @@ it('inputValue should work', async ({ page, server }) => {
const locator = page.locator('#input');
expect(await locator.inputValue()).toBe('input value');
expect(await page.inputValue('#inner').catch(e => e.message)).toContain('Node is not an HTMLInputElement or HTMLTextAreaElement');
expect(await page.inputValue('#inner').catch(e => e.message)).toContain('Node is not an HTMLInputElement or HTMLTextAreaElement or HTMLSelectElement');
const locator2 = page.locator('#inner');
expect(await locator2.inputValue().catch(e => e.message)).toContain('Node is not an HTMLInputElement or HTMLTextAreaElement');
expect(await locator2.inputValue().catch(e => e.message)).toContain('Node is not an HTMLInputElement or HTMLTextAreaElement or HTMLSelectElement');
});
it('innerHTML should work', async ({ page, server }) => {

8
types/types.d.ts vendored
View File

@ -1890,7 +1890,7 @@ export interface Page {
}): Promise<string>;
/**
* Returns `input.value` for the selected `<input>` or `<textarea>` element. Throws for non-input elements.
* Returns `input.value` for the selected `<input>` or `<textarea>` or `<select>` element. Throws for non-input elements.
* @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be used. See [working with selectors](https://playwright.dev/docs/selectors) for more details.
* @param options
*/
@ -4141,7 +4141,7 @@ export interface Frame {
}): Promise<string>;
/**
* Returns `input.value` for the selected `<input>` or `<textarea>` element. Throws for non-input elements.
* Returns `input.value` for the selected `<input>` or `<textarea>` or `<select>` element. Throws for non-input elements.
* @param selector A selector to search for an element. If there are multiple elements satisfying the selector, the first will be used. See [working with selectors](https://playwright.dev/docs/selectors) for more details.
* @param options
*/
@ -6461,7 +6461,7 @@ export interface ElementHandle<T=Node> extends JSHandle<T> {
innerText(): Promise<string>;
/**
* Returns `input.value` for `<input>` or `<textarea>` element. Throws for non-input elements.
* Returns `input.value` for `<input>` or `<textarea>` or `<select>` element. Throws for non-input elements.
* @param options
*/
inputValue(options?: {
@ -7543,7 +7543,7 @@ export interface Locator {
}): Promise<string>;
/**
* Returns `input.value` for `<input>` or `<textarea>` element. Throws for non-input elements.
* Returns `input.value` for `<input>` or `<textarea>` or `<select>` element. Throws for non-input elements.
* @param options
*/
inputValue(options?: {