mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
feat(api): add getByLabelText (#17684)
This commit is contained in:
parent
43ccd7bc96
commit
e3a2316013
@ -920,6 +920,16 @@ Attribute name to get the value for.
|
|||||||
* since: v1.8
|
* since: v1.8
|
||||||
|
|
||||||
|
|
||||||
|
## method: Frame.getByLabelText
|
||||||
|
* since: v1.27
|
||||||
|
- returns: <[Locator]>
|
||||||
|
|
||||||
|
%%-template-locator-get-by-label-text-%%
|
||||||
|
|
||||||
|
### param: Frame.getByLabelText.text = %%-locator-get-by-text-text-%%
|
||||||
|
### option: Frame.getByLabelText.exact = %%-locator-get-by-text-exact-%%
|
||||||
|
|
||||||
|
|
||||||
## method: Frame.getByRole
|
## method: Frame.getByRole
|
||||||
* since: v1.27
|
* since: v1.27
|
||||||
- returns: <[Locator]>
|
- returns: <[Locator]>
|
||||||
|
@ -126,6 +126,16 @@ in that iframe.
|
|||||||
* since: v1.27
|
* since: v1.27
|
||||||
|
|
||||||
|
|
||||||
|
## method: FrameLocator.getByLabelText
|
||||||
|
* since: v1.27
|
||||||
|
- returns: <[Locator]>
|
||||||
|
|
||||||
|
%%-template-locator-get-by-label-text-%%
|
||||||
|
|
||||||
|
### param: FrameLocator.getByLabelText.text = %%-locator-get-by-text-text-%%
|
||||||
|
### option: FrameLocator.getByLabelText.exact = %%-locator-get-by-text-exact-%%
|
||||||
|
|
||||||
|
|
||||||
## method: FrameLocator.getByRole
|
## method: FrameLocator.getByRole
|
||||||
* since: v1.27
|
* since: v1.27
|
||||||
- returns: <[Locator]>
|
- returns: <[Locator]>
|
||||||
|
@ -646,6 +646,16 @@ Attribute name to get the value for.
|
|||||||
* since: v1.14
|
* since: v1.14
|
||||||
|
|
||||||
|
|
||||||
|
## method: Locator.getByLabelText
|
||||||
|
* since: v1.27
|
||||||
|
- returns: <[Locator]>
|
||||||
|
|
||||||
|
%%-template-locator-get-by-label-text-%%
|
||||||
|
|
||||||
|
### param: Locator.getByLabelText.text = %%-locator-get-by-text-text-%%
|
||||||
|
### option: Locator.getByLabelText.exact = %%-locator-get-by-text-exact-%%
|
||||||
|
|
||||||
|
|
||||||
## method: Locator.getByRole
|
## method: Locator.getByRole
|
||||||
* since: v1.27
|
* since: v1.27
|
||||||
- returns: <[Locator]>
|
- returns: <[Locator]>
|
||||||
|
@ -2195,6 +2195,16 @@ Attribute name to get the value for.
|
|||||||
* since: v1.8
|
* since: v1.8
|
||||||
|
|
||||||
|
|
||||||
|
## method: Page.getByLabelText
|
||||||
|
* since: v1.27
|
||||||
|
- returns: <[Locator]>
|
||||||
|
|
||||||
|
%%-template-locator-get-by-label-text-%%
|
||||||
|
|
||||||
|
### param: Page.getByLabelText.text = %%-locator-get-by-text-text-%%
|
||||||
|
### option: Page.getByLabelText.exact = %%-locator-get-by-text-exact-%%
|
||||||
|
|
||||||
|
|
||||||
## method: Page.getByRole
|
## method: Page.getByRole
|
||||||
* since: v1.27
|
* since: v1.27
|
||||||
- returns: <[Locator]>
|
- returns: <[Locator]>
|
||||||
|
@ -1180,6 +1180,15 @@ Locate element by the test id. By default, the `data-testid` attribute is used a
|
|||||||
|
|
||||||
Allows locating elements that contain given text.
|
Allows locating elements that contain given text.
|
||||||
|
|
||||||
|
## template-locator-get-by-label-text
|
||||||
|
|
||||||
|
Allows locating input elements by the text of the associated label. For example, this method will find the input by label text Password in the following DOM:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<label for="password-input">Password:</label>
|
||||||
|
<input id="password-input">
|
||||||
|
```
|
||||||
|
|
||||||
## template-locator-get-by-role
|
## template-locator-get-by-role
|
||||||
|
|
||||||
Allows locating elements by their [ARIA role](https://www.w3.org/TR/wai-aria-1.2/#roles), [ARIA attributes](https://www.w3.org/TR/wai-aria-1.2/#aria-attributes) and [accessible name](https://w3c.github.io/accname/#dfn-accessible-name). Note that role selector **does not replace** accessibility audits and conformance tests, but rather gives early feedback about the ARIA guidelines.
|
Allows locating elements by their [ARIA role](https://www.w3.org/TR/wai-aria-1.2/#roles), [ARIA attributes](https://www.w3.org/TR/wai-aria-1.2/#aria-attributes) and [accessible name](https://w3c.github.io/accname/#dfn-accessible-name). Note that role selector **does not replace** accessibility audits and conformance tests, but rather gives early feedback about the ARIA guidelines.
|
||||||
|
@ -21,14 +21,14 @@ If you use DOM Testing Library in the browser (for example, you bundle end-to-en
|
|||||||
| [queries](https://testing-library.com/docs/queries/about) | [locators](./locators) |
|
| [queries](https://testing-library.com/docs/queries/about) | [locators](./locators) |
|
||||||
| [async helpers](https://testing-library.com/docs/dom-testing-library/api-async) | [assertions](./test-assertions) |
|
| [async helpers](https://testing-library.com/docs/dom-testing-library/api-async) | [assertions](./test-assertions) |
|
||||||
| [user events](https://testing-library.com/docs/user-event/intro) | [actions](./api/class-locator) |
|
| [user events](https://testing-library.com/docs/user-event/intro) | [actions](./api/class-locator) |
|
||||||
| `await user.click(screen.getByText('Click me'))` | `await component.locator('text=Click me').click()` |
|
| `await user.click(screen.getByText('Click me'))` | `await component.getByText('Click me').click()` |
|
||||||
| `await user.click(await screen.findByText('Click me'))` | `await component.locator('text=Click me').click()` |
|
| `await user.click(await screen.findByText('Click me'))` | `await component.getByText('Click me').click()` |
|
||||||
| `await user.type(screen.getByLabelText('Password'), 'secret')` | `await component.locator('text=Password').fill('secret')` |
|
| `await user.type(screen.getByLabelText('Password'), 'secret')` | `await component.getByLabelText('Password').fill('secret')` |
|
||||||
| `expect(screen.getByLabelText('Password')).toHaveValue('secret')` | `await expect(component.locator('text=Password')).toHaveValue('secret')` |
|
| `expect(screen.getByLabelText('Password')).toHaveValue('secret')` | `await expect(component.getByLabelText('Password')).toHaveValue('secret')` |
|
||||||
| `screen.findByText('...')` | `component.locator('text=...')` |
|
| `screen.findByText('...')` | `component.getByText('...')` |
|
||||||
| `screen.getByTestId('...')` | `component.locator('data-testid=...')` |
|
| `screen.getByTestId('...')` | `component.getByTestId('...')` |
|
||||||
| `screen.queryByPlaceholderText('...')` | `component.locator('[placeholder="..."]')` |
|
| `screen.queryByPlaceholderText('...')` | `component.get('[placeholder="..."]')` |
|
||||||
| `screen.getAllByRole('button', { pressed: true })` | `component.locator('role=button[pressed]')` |
|
| `screen.getByRole('button', { pressed: true })` | `component.getByRole('button', { pressed: true })`|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
|
@ -307,6 +307,10 @@ export class Frame extends ChannelOwner<channels.FrameChannel> implements api.Fr
|
|||||||
return this.locator(Locator.getByTestIdSelector(testId));
|
return this.locator(Locator.getByTestIdSelector(testId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getByLabelText(text: string | RegExp, options?: { exact?: boolean }): Locator {
|
||||||
|
return this.locator(Locator.getByLabelTextSelector(text, options));
|
||||||
|
}
|
||||||
|
|
||||||
getByText(text: string | RegExp, options?: { exact?: boolean }): Locator {
|
getByText(text: string | RegExp, options?: { exact?: boolean }): Locator {
|
||||||
return this.locator(Locator.getByTextSelector(text, options));
|
return this.locator(Locator.getByTextSelector(text, options));
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,14 @@ export class Locator implements api.Locator {
|
|||||||
return `css=[${Locator._testIdAttributeName}=${JSON.stringify(testId)}]`;
|
return `css=[${Locator._testIdAttributeName}=${JSON.stringify(testId)}]`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getByLabelTextSelector(text: string | RegExp, options?: { exact?: boolean }): string {
|
||||||
|
if (!isString(text))
|
||||||
|
return `text=${text}`;
|
||||||
|
const escaped = JSON.stringify(text);
|
||||||
|
const selector = options?.exact ? `text=${escaped}` : `text=${escaped.substring(1, escaped.length - 1)}`;
|
||||||
|
return selector + ' >> control=resolve-label';
|
||||||
|
}
|
||||||
|
|
||||||
static getByTextSelector(text: string | RegExp, options?: { exact?: boolean }): string {
|
static getByTextSelector(text: string | RegExp, options?: { exact?: boolean }): string {
|
||||||
if (!isString(text))
|
if (!isString(text))
|
||||||
return `text=${text}`;
|
return `text=${text}`;
|
||||||
@ -189,6 +197,10 @@ export class Locator implements api.Locator {
|
|||||||
return this.locator(Locator.getByTestIdSelector(testId));
|
return this.locator(Locator.getByTestIdSelector(testId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getByLabelText(text: string | RegExp, options?: { exact?: boolean }): Locator {
|
||||||
|
return this.locator(Locator.getByLabelTextSelector(text, options));
|
||||||
|
}
|
||||||
|
|
||||||
getByText(text: string | RegExp, options?: { exact?: boolean }): Locator {
|
getByText(text: string | RegExp, options?: { exact?: boolean }): Locator {
|
||||||
return this.locator(Locator.getByTextSelector(text, options));
|
return this.locator(Locator.getByTextSelector(text, options));
|
||||||
}
|
}
|
||||||
@ -379,6 +391,9 @@ export class FrameLocator implements api.FrameLocator {
|
|||||||
return this.locator(Locator.getByTestIdSelector(testId));
|
return this.locator(Locator.getByTestIdSelector(testId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getByLabelText(text: string | RegExp, options?: { exact?: boolean }): Locator {
|
||||||
|
return this.locator(Locator.getByLabelTextSelector(text, options));
|
||||||
|
}
|
||||||
getByText(text: string | RegExp, options?: { exact?: boolean }): Locator {
|
getByText(text: string | RegExp, options?: { exact?: boolean }): Locator {
|
||||||
return this.locator(Locator.getByTextSelector(text, options));
|
return this.locator(Locator.getByTextSelector(text, options));
|
||||||
}
|
}
|
||||||
|
@ -572,6 +572,10 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
|||||||
return this.mainFrame().getByTestId(testId);
|
return this.mainFrame().getByTestId(testId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getByLabelText(text: string | RegExp, options?: { exact?: boolean }): Locator {
|
||||||
|
return this.mainFrame().getByLabelText(text, options);
|
||||||
|
}
|
||||||
|
|
||||||
getByText(text: string | RegExp, options?: { exact?: boolean }): Locator {
|
getByText(text: string | RegExp, options?: { exact?: boolean }): Locator {
|
||||||
return this.mainFrame().getByText(text, options);
|
return this.mainFrame().getByText(text, options);
|
||||||
}
|
}
|
||||||
|
@ -278,6 +278,10 @@ export class InjectedScript {
|
|||||||
return [];
|
return [];
|
||||||
if (body === 'return-empty')
|
if (body === 'return-empty')
|
||||||
return [];
|
return [];
|
||||||
|
if (body === 'resolve-label') {
|
||||||
|
const control = (root as HTMLLabelElement).control;
|
||||||
|
return control ? [control] : [];
|
||||||
|
}
|
||||||
if (body === 'component') {
|
if (body === 'component') {
|
||||||
if (root.nodeType !== 1 /* Node.ELEMENT_NODE */)
|
if (root.nodeType !== 1 /* Node.ELEMENT_NODE */)
|
||||||
return [];
|
return [];
|
||||||
|
76
packages/playwright-core/types/types.d.ts
vendored
76
packages/playwright-core/types/types.d.ts
vendored
@ -2482,6 +2482,25 @@ export interface Page {
|
|||||||
timeout?: number;
|
timeout?: number;
|
||||||
}): Promise<null|string>;
|
}): Promise<null|string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
|
||||||
|
* label text Password in the following DOM:
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <label for="password-input">Password:</label>
|
||||||
|
* <input id="password-input">
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param text Text to locate the element for.
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
getByLabelText(text: string|RegExp, options?: {
|
||||||
|
/**
|
||||||
|
* Whether to find an exact match: case-sensitive and whole-string. Default to false.
|
||||||
|
*/
|
||||||
|
exact?: boolean;
|
||||||
|
}): Locator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows locating elements by their [ARIA role](https://www.w3.org/TR/wai-aria-1.2/#roles),
|
* Allows locating elements by their [ARIA role](https://www.w3.org/TR/wai-aria-1.2/#roles),
|
||||||
* [ARIA attributes](https://www.w3.org/TR/wai-aria-1.2/#aria-attributes) and
|
* [ARIA attributes](https://www.w3.org/TR/wai-aria-1.2/#aria-attributes) and
|
||||||
@ -5523,6 +5542,25 @@ export interface Frame {
|
|||||||
timeout?: number;
|
timeout?: number;
|
||||||
}): Promise<null|string>;
|
}): Promise<null|string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
|
||||||
|
* label text Password in the following DOM:
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <label for="password-input">Password:</label>
|
||||||
|
* <input id="password-input">
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param text Text to locate the element for.
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
getByLabelText(text: string|RegExp, options?: {
|
||||||
|
/**
|
||||||
|
* Whether to find an exact match: case-sensitive and whole-string. Default to false.
|
||||||
|
*/
|
||||||
|
exact?: boolean;
|
||||||
|
}): Locator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows locating elements by their [ARIA role](https://www.w3.org/TR/wai-aria-1.2/#roles),
|
* Allows locating elements by their [ARIA role](https://www.w3.org/TR/wai-aria-1.2/#roles),
|
||||||
* [ARIA attributes](https://www.w3.org/TR/wai-aria-1.2/#aria-attributes) and
|
* [ARIA attributes](https://www.w3.org/TR/wai-aria-1.2/#aria-attributes) and
|
||||||
@ -9911,6 +9949,25 @@ export interface Locator {
|
|||||||
timeout?: number;
|
timeout?: number;
|
||||||
}): Promise<null|string>;
|
}): Promise<null|string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
|
||||||
|
* label text Password in the following DOM:
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <label for="password-input">Password:</label>
|
||||||
|
* <input id="password-input">
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param text Text to locate the element for.
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
getByLabelText(text: string|RegExp, options?: {
|
||||||
|
/**
|
||||||
|
* Whether to find an exact match: case-sensitive and whole-string. Default to false.
|
||||||
|
*/
|
||||||
|
exact?: boolean;
|
||||||
|
}): Locator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows locating elements by their [ARIA role](https://www.w3.org/TR/wai-aria-1.2/#roles),
|
* Allows locating elements by their [ARIA role](https://www.w3.org/TR/wai-aria-1.2/#roles),
|
||||||
* [ARIA attributes](https://www.w3.org/TR/wai-aria-1.2/#aria-attributes) and
|
* [ARIA attributes](https://www.w3.org/TR/wai-aria-1.2/#aria-attributes) and
|
||||||
@ -15120,6 +15177,25 @@ export interface FrameLocator {
|
|||||||
hasText?: string|RegExp;
|
hasText?: string|RegExp;
|
||||||
}): Locator;
|
}): Locator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows locating input elements by the text of the associated label. For example, this method will find the input by
|
||||||
|
* label text Password in the following DOM:
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <label for="password-input">Password:</label>
|
||||||
|
* <input id="password-input">
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param text Text to locate the element for.
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
getByLabelText(text: string|RegExp, options?: {
|
||||||
|
/**
|
||||||
|
* Whether to find an exact match: case-sensitive and whole-string. Default to false.
|
||||||
|
*/
|
||||||
|
exact?: boolean;
|
||||||
|
}): Locator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows locating elements by their [ARIA role](https://www.w3.org/TR/wai-aria-1.2/#roles),
|
* Allows locating elements by their [ARIA role](https://www.w3.org/TR/wai-aria-1.2/#roles),
|
||||||
* [ARIA attributes](https://www.w3.org/TR/wai-aria-1.2/#aria-attributes) and
|
* [ARIA attributes](https://www.w3.org/TR/wai-aria-1.2/#aria-attributes) and
|
||||||
|
@ -35,6 +35,7 @@ async function routeIframe(page: Page) {
|
|||||||
</div>
|
</div>
|
||||||
<span>1</span>
|
<span>1</span>
|
||||||
<span>2</span>
|
<span>2</span>
|
||||||
|
<label for=target>Name</label><input id=target type=text>
|
||||||
</html>`,
|
</html>`,
|
||||||
contentType: 'text/html'
|
contentType: 'text/html'
|
||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
@ -247,4 +248,6 @@ it('role and text coverage', async ({ page, server }) => {
|
|||||||
await expect(button1).toHaveText('Hello iframe');
|
await expect(button1).toHaveText('Hello iframe');
|
||||||
await expect(button2).toHaveText('Hello iframe');
|
await expect(button2).toHaveText('Hello iframe');
|
||||||
await expect(button3).toHaveText('Hello iframe');
|
await expect(button3).toHaveText('Hello iframe');
|
||||||
|
const input = page.frameLocator('iframe').getByLabelText('Name');
|
||||||
|
await expect(input).toHaveValue('');
|
||||||
});
|
});
|
||||||
|
@ -454,3 +454,11 @@ it('should work with paired quotes in the middle of selector', async ({ page })
|
|||||||
// Should double escape inside quoted text.
|
// Should double escape inside quoted text.
|
||||||
await expect(page.locator(`div >> text='pattern "^-?\\\\d+$"'`)).toBeVisible();
|
await expect(page.locator(`div >> text='pattern "^-?\\\\d+$"'`)).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('getByLabelText should work', async ({ page, asset }) => {
|
||||||
|
await page.setContent(`<div><label for=target>Name</label><input id=target type=text></div>`);
|
||||||
|
expect(await page.getByText('Name').evaluate(e => e.nodeName)).toBe('LABEL');
|
||||||
|
expect(await page.getByLabelText('Name').evaluate(e => e.nodeName)).toBe('INPUT');
|
||||||
|
expect(await page.mainFrame().getByLabelText('Name').evaluate(e => e.nodeName)).toBe('INPUT');
|
||||||
|
expect(await page.get('div').getByLabelText('Name').evaluate(e => e.nodeName)).toBe('INPUT');
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user