feat(fill): make fill work when targeting elements inside the label (#5143)

This commit is contained in:
Dmitry Gozman 2021-01-25 13:40:19 -08:00 коммит произвёл GitHub
Родитель 7d2293c6ed
Коммит d78d337e29
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 44 добавлений и 19 удалений

Просмотреть файл

@ -363,9 +363,10 @@ Optional event-specific initialization properties.
## async method: ElementHandle.fill
This method waits for [actionability](./actionability.md) checks, focuses the element, fills it and triggers an `input`
event after filling. If the element is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws
an error. Note that you can pass an empty string to clear the input field.
This method waits for [actionability](./actionability.md) checks, focuses the element, fills it and triggers an `input` event after filling.
If the element is inside the `<label>` element that has associated [control](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control), that control will be filled instead.
If the element to be filled is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws an error.
Note that you can pass an empty string to clear the input field.
### param: ElementHandle.fill.value
- `value` <[string]>

Просмотреть файл

@ -564,10 +564,10 @@ Optional argument to pass to [`param: pageFunction`]
## async method: Frame.fill
This method waits for an element matching [`param: selector`], waits for [actionability](./actionability.md) checks,
focuses the element, fills it and triggers an `input` event after filling. If the element matching [`param: selector`]
is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws an error. Note that you can pass an
empty string to clear the input field.
This method waits for an element matching [`param: selector`], waits for [actionability](./actionability.md) checks, focuses the element, fills it and triggers an `input` event after filling.
If the element is inside the `<label>` element that has associated [control](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control), that control will be filled instead.
If the element to be filled is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws an error.
Note that you can pass an empty string to clear the input field.
To send fine-grained keyboard events, use [`method: Frame.type`].

Просмотреть файл

@ -1245,10 +1245,10 @@ Callback function which will be called in Playwright's context.
## async method: Page.fill
This method waits for an element matching [`param: selector`], waits for [actionability](./actionability.md) checks,
focuses the element, fills it and triggers an `input` event after filling. If the element matching [`param: selector`]
is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws an error. Note that you can pass an
empty string to clear the input field.
This method waits for an element matching [`param: selector`], waits for [actionability](./actionability.md) checks, focuses the element, fills it and triggers an `input` event after filling.
If the element is inside the `<label>` element that has associated [control](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control), that control will be filled instead.
If the element to be filled is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws an error.
Note that you can pass an empty string to clear the input field.
To send fine-grained keyboard events, use [`method: Page.type`].

Просмотреть файл

@ -323,7 +323,15 @@ export class InjectedScript {
return this.pollRaf((progress, continuePolling) => {
if (node.nodeType !== Node.ELEMENT_NODE)
return 'error:notelement';
if (node && node.nodeName.toLowerCase() !== 'input' &&
node.nodeName.toLowerCase() !== 'textarea' &&
!(node as any).isContentEditable) {
// Go up to the label that might be connected to the input/textarea.
node = (node as Element).closest('label') || node;
}
const element = this.findLabelTarget(node as Element);
if (element && !element.isConnected)
return 'error:notconnected';
if (!element || !this.isVisible(element)) {

Просмотреть файл

@ -46,6 +46,18 @@ it('should fill input with label 2', async ({page}) => {
expect(await page.$eval('input', input => input.value)).toBe('some value');
});
it('should fill input with span inside the label', async ({page}) => {
await page.setContent(`<label for=target><span>Fill me</span></label><input id=target>`);
await page.fill('text=Fill me', 'some value');
expect(await page.$eval('input', input => input.value)).toBe('some value');
});
it('should fill input inside the label', async ({page}) => {
await page.setContent(`<label><input id=target></label>`);
await page.fill('input', 'some value');
expect(await page.$eval('input', input => input.value)).toBe('some value');
});
it('should fill textarea with label', async ({page}) => {
await page.setContent(`<label for=target>Fill me</label><textarea id=target>hey</textarea>`);
await page.fill('text=Fill me', 'some value');

20
types/types.d.ts поставляемый
Просмотреть файл

@ -1668,9 +1668,10 @@ export interface Page {
/**
* This method waits for an element matching `selector`, waits for [actionability](https://playwright.dev/docs/actionability) checks, focuses the
* element, fills it and triggers an `input` event after filling. If the element matching `selector` is not an `<input>`,
* `<textarea>` or `[contenteditable]` element, this method throws an error. Note that you can pass an empty string to
* clear the input field.
* element, fills it and triggers an `input` event after filling. If the element is inside the `<label>` element that has
* associated [control](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control), that control will be
* filled instead. If the element to be filled is not an `<input>`, `<textarea>` or `[contenteditable]` element, this
* method throws an error. Note that you can pass an empty string to clear the input field.
*
* To send fine-grained keyboard events, use
* [page.type(selector, text[, options])](https://playwright.dev/docs/api/class-page#pagetypeselector-text-options).
@ -3678,9 +3679,10 @@ export interface Frame {
/**
* This method waits for an element matching `selector`, waits for [actionability](https://playwright.dev/docs/actionability) checks, focuses the
* element, fills it and triggers an `input` event after filling. If the element matching `selector` is not an `<input>`,
* `<textarea>` or `[contenteditable]` element, this method throws an error. Note that you can pass an empty string to
* clear the input field.
* element, fills it and triggers an `input` event after filling. If the element is inside the `<label>` element that has
* associated [control](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control), that control will be
* filled instead. If the element to be filled is not an `<input>`, `<textarea>` or `[contenteditable]` element, this
* method throws an error. Note that you can pass an empty string to clear the input field.
*
* To send fine-grained keyboard events, use
* [frame.type(selector, text[, options])](https://playwright.dev/docs/api/class-frame#frametypeselector-text-options).
@ -5630,8 +5632,10 @@ export interface ElementHandle<T=Node> extends JSHandle<T> {
/**
* This method waits for [actionability](https://playwright.dev/docs/actionability) checks, focuses the element, fills it and triggers an `input`
* event after filling. If the element is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws
* an error. Note that you can pass an empty string to clear the input field.
* event after filling. If the element is inside the `<label>` element that has associated
* [control](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control), that control will be filled
* instead. If the element to be filled is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method
* throws an error. Note that you can pass an empty string to clear the input field.
* @param value Value to set for the `<input>`, `<textarea>` or `[contenteditable]` element.
* @param options
*/