chore: replace locator.visible with filter({ visible }) (#34947)
This commit is contained in:
parent
837abfbc15
commit
3ce9ae6a7d
|
|
@ -1090,6 +1090,9 @@ await rowLocator
|
|||
### option: Locator.filter.hasNotText = %%-locator-option-has-not-text-%%
|
||||
* since: v1.33
|
||||
|
||||
### option: Locator.filter.visible = %%-locator-option-visible-%%
|
||||
* since: v1.51
|
||||
|
||||
## method: Locator.first
|
||||
* since: v1.14
|
||||
- returns: <[Locator]>
|
||||
|
|
@ -2478,18 +2481,6 @@ When all steps combined have not finished during the specified [`option: timeout
|
|||
### option: Locator.uncheck.trial = %%-input-trial-%%
|
||||
* since: v1.14
|
||||
|
||||
## method: Locator.visible
|
||||
* since: v1.51
|
||||
- returns: <[Locator]>
|
||||
|
||||
Returns a locator that only matches [visible](../actionability.md#visible) elements.
|
||||
|
||||
### option: Locator.visible.visible
|
||||
* since: v1.51
|
||||
- `visible` <[boolean]>
|
||||
|
||||
Whether to match visible or invisible elements.
|
||||
|
||||
## async method: Locator.waitFor
|
||||
* since: v1.16
|
||||
|
||||
|
|
|
|||
|
|
@ -1155,6 +1155,11 @@ Note that outer and inner locators must belong to the same frame. Inner locator
|
|||
|
||||
Matches elements that do not contain specified text somewhere inside, possibly in a child or a descendant element. When passed a [string], matching is case-insensitive and searches for a substring.
|
||||
|
||||
## locator-option-visible
|
||||
- `visible` <[boolean]>
|
||||
|
||||
Only matches visible or invisible elements.
|
||||
|
||||
## locator-options-list-v1.14
|
||||
- %%-locator-option-has-text-%%
|
||||
- %%-locator-option-has-%%
|
||||
|
|
|
|||
|
|
@ -751,10 +751,10 @@ page.locator("x-details", new Page.LocatorOptions().setHasText("Details"))
|
|||
.click();
|
||||
```
|
||||
```python async
|
||||
await page.locator("x-details", has_text="Details" ).click()
|
||||
await page.locator("x-details", has_text="Details").click()
|
||||
```
|
||||
```python sync
|
||||
page.locator("x-details", has_text="Details" ).click()
|
||||
page.locator("x-details", has_text="Details").click()
|
||||
```
|
||||
```csharp
|
||||
await page
|
||||
|
|
@ -1310,19 +1310,19 @@ Consider a page with two buttons, the first invisible and the second [visible](.
|
|||
* This will only find a second button, because it is visible, and then click it.
|
||||
|
||||
```js
|
||||
await page.locator('button').visible().click();
|
||||
await page.locator('button').filter({ visible: true }).click();
|
||||
```
|
||||
```java
|
||||
page.locator("button").visible().click();
|
||||
page.locator("button").filter(new Locator.FilterOptions.setVisible(true)).click();
|
||||
```
|
||||
```python async
|
||||
await page.locator("button").visible().click()
|
||||
await page.locator("button").filter(visible=True).click()
|
||||
```
|
||||
```python sync
|
||||
page.locator("button").visible().click()
|
||||
page.locator("button").filter(visible=True).click()
|
||||
```
|
||||
```csharp
|
||||
await page.Locator("button").Visible().ClickAsync();
|
||||
await page.Locator("button").Filter(new() { Visible = true }).ClickAsync();
|
||||
```
|
||||
|
||||
## Lists
|
||||
|
|
|
|||
16
packages/playwright-client/types/types.d.ts
vendored
16
packages/playwright-client/types/types.d.ts
vendored
|
|
@ -13129,6 +13129,11 @@ export interface Locator {
|
|||
* `<article><div>Playwright</div></article>`.
|
||||
*/
|
||||
hasText?: string|RegExp;
|
||||
|
||||
/**
|
||||
* Only matches visible or invisible elements.
|
||||
*/
|
||||
visible?: boolean;
|
||||
}): Locator;
|
||||
|
||||
/**
|
||||
|
|
@ -14520,17 +14525,6 @@ export interface Locator {
|
|||
trial?: boolean;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Returns a locator that only matches [visible](https://playwright.dev/docs/actionability#visible) elements.
|
||||
* @param options
|
||||
*/
|
||||
visible(options?: {
|
||||
/**
|
||||
* Whether to match visible or invisible elements.
|
||||
*/
|
||||
visible?: boolean;
|
||||
}): Locator;
|
||||
|
||||
/**
|
||||
* Returns when element specified by locator satisfies the
|
||||
* [`state`](https://playwright.dev/docs/api/class-locator#locator-wait-for-option-state) option.
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ export type LocatorOptions = {
|
|||
hasNotText?: string | RegExp;
|
||||
has?: Locator;
|
||||
hasNot?: Locator;
|
||||
visible?: boolean;
|
||||
};
|
||||
|
||||
export class Locator implements api.Locator {
|
||||
|
|
@ -65,6 +66,9 @@ export class Locator implements api.Locator {
|
|||
this._selector += ` >> internal:has-not=` + JSON.stringify(locator._selector);
|
||||
}
|
||||
|
||||
if (options?.visible !== undefined)
|
||||
this._selector += ` >> visible=${options.visible ? 'true' : 'false'}`;
|
||||
|
||||
if (this._frame._platform.inspectCustom)
|
||||
(this as any)[this._frame._platform.inspectCustom] = () => this._inspect();
|
||||
}
|
||||
|
|
@ -150,7 +154,7 @@ export class Locator implements api.Locator {
|
|||
return await this._frame._highlight(this._selector);
|
||||
}
|
||||
|
||||
locator(selectorOrLocator: string | Locator, options?: LocatorOptions): Locator {
|
||||
locator(selectorOrLocator: string | Locator, options?: Omit<LocatorOptions, 'visible'>): Locator {
|
||||
if (isString(selectorOrLocator))
|
||||
return new Locator(this._frame, this._selector + ' >> ' + selectorOrLocator, options);
|
||||
if (selectorOrLocator._frame !== this._frame)
|
||||
|
|
@ -218,11 +222,6 @@ export class Locator implements api.Locator {
|
|||
return new Locator(this._frame, this._selector + ` >> nth=${index}`);
|
||||
}
|
||||
|
||||
visible(options: { visible?: boolean } = {}): Locator {
|
||||
const { visible = true } = options;
|
||||
return new Locator(this._frame, this._selector + ` >> visible=${visible ? 'true' : 'false'}`);
|
||||
}
|
||||
|
||||
and(locator: Locator): Locator {
|
||||
if (locator._frame !== this._frame)
|
||||
throw new Error(`Locators must belong to the same frame.`);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class Locator {
|
|||
element: Element | undefined;
|
||||
elements: Element[] | undefined;
|
||||
|
||||
constructor(injectedScript: InjectedScript, selector: string, options?: { hasText?: string | RegExp, hasNotText?: string | RegExp, has?: Locator, hasNot?: Locator }) {
|
||||
constructor(injectedScript: InjectedScript, selector: string, options?: { hasText?: string | RegExp, hasNotText?: string | RegExp, has?: Locator, hasNot?: Locator, visible?: boolean }) {
|
||||
if (options?.hasText)
|
||||
selector += ` >> internal:has-text=${escapeForTextSelector(options.hasText, false)}`;
|
||||
if (options?.hasNotText)
|
||||
|
|
@ -38,6 +38,8 @@ class Locator {
|
|||
selector += ` >> internal:has=` + JSON.stringify(options.has[selectorSymbol]);
|
||||
if (options?.hasNot)
|
||||
selector += ` >> internal:has-not=` + JSON.stringify(options.hasNot[selectorSymbol]);
|
||||
if (options?.visible !== undefined)
|
||||
selector += ` >> visible=${options.visible ? 'true' : 'false'}`;
|
||||
this[selectorSymbol] = selector;
|
||||
if (selector) {
|
||||
const parsed = injectedScript.parseSelector(selector);
|
||||
|
|
@ -46,7 +48,7 @@ class Locator {
|
|||
}
|
||||
const selectorBase = selector;
|
||||
const self = this as any;
|
||||
self.locator = (selector: string, options?: { hasText?: string | RegExp, has?: Locator }): Locator => {
|
||||
self.locator = (selector: string, options?: { hasText?: string | RegExp, hasNotText?: string | RegExp, has?: Locator, hasNot?: Locator }): Locator => {
|
||||
return new Locator(injectedScript, selectorBase ? selectorBase + ' >> ' + selector : selector, options);
|
||||
};
|
||||
self.getByTestId = (testId: string): Locator => self.locator(getByTestIdSelector(injectedScript.testIdAttributeNameForStrictErrorAndConsoleCodegen(), testId));
|
||||
|
|
@ -56,7 +58,7 @@ class Locator {
|
|||
self.getByText = (text: string | RegExp, options?: { exact?: boolean }): Locator => self.locator(getByTextSelector(text, options));
|
||||
self.getByTitle = (text: string | RegExp, options?: { exact?: boolean }): Locator => self.locator(getByTitleSelector(text, options));
|
||||
self.getByRole = (role: string, options: ByRoleOptions = {}): Locator => self.locator(getByRoleSelector(role, options));
|
||||
self.filter = (options?: { hasText?: string | RegExp, has?: Locator }): Locator => new Locator(injectedScript, selector, options);
|
||||
self.filter = (options?: { hasText?: string | RegExp, hasNotText?: string | RegExp, has?: Locator, hasNot?: Locator, visible?: boolean }): Locator => new Locator(injectedScript, selector, options);
|
||||
self.first = (): Locator => self.locator('nth=0');
|
||||
self.last = (): Locator => self.locator('nth=-1');
|
||||
self.nth = (index: number): Locator => self.locator(`nth=${index}`);
|
||||
|
|
|
|||
|
|
@ -280,7 +280,7 @@ export class JavaScriptLocatorFactory implements LocatorFactory {
|
|||
case 'last':
|
||||
return `last()`;
|
||||
case 'visible':
|
||||
return `visible(${body === 'true' ? '' : '{ visible: false }'})`;
|
||||
return `filter({ visible: ${body === 'true' ? 'true' : 'false'} })`;
|
||||
case 'role':
|
||||
const attrs: string[] = [];
|
||||
if (isRegExp(options.name)) {
|
||||
|
|
@ -376,7 +376,7 @@ export class PythonLocatorFactory implements LocatorFactory {
|
|||
case 'last':
|
||||
return `last`;
|
||||
case 'visible':
|
||||
return `visible(${body === 'true' ? '' : 'visible=False'})`;
|
||||
return `filter(visible=${body === 'true' ? 'True' : 'False'})`;
|
||||
case 'role':
|
||||
const attrs: string[] = [];
|
||||
if (isRegExp(options.name)) {
|
||||
|
|
@ -485,7 +485,7 @@ export class JavaLocatorFactory implements LocatorFactory {
|
|||
case 'last':
|
||||
return `last()`;
|
||||
case 'visible':
|
||||
return `visible(${body === 'true' ? '' : `new ${clazz}.VisibleOptions().setVisible(false)`})`;
|
||||
return `filter(new ${clazz}.FilterOptions().setVisible(${body === 'true' ? 'true' : 'false'}))`;
|
||||
case 'role':
|
||||
const attrs: string[] = [];
|
||||
if (isRegExp(options.name)) {
|
||||
|
|
@ -584,7 +584,7 @@ export class CSharpLocatorFactory implements LocatorFactory {
|
|||
case 'last':
|
||||
return `Last`;
|
||||
case 'visible':
|
||||
return `Visible(${body === 'true' ? '' : 'new() { Visible = false }'})`;
|
||||
return `Filter(new() { Visible = ${body === 'true' ? 'true' : 'false'} })`;
|
||||
case 'role':
|
||||
const attrs: string[] = [];
|
||||
if (isRegExp(options.name)) {
|
||||
|
|
|
|||
|
|
@ -170,9 +170,8 @@ function transform(template: string, params: TemplateParams, testIdAttributeName
|
|||
.replace(/first(\(\))?/g, 'nth=0')
|
||||
.replace(/last(\(\))?/g, 'nth=-1')
|
||||
.replace(/nth\(([^)]+)\)/g, 'nth=$1')
|
||||
.replace(/visible\(,?visible=true\)/g, 'visible=true')
|
||||
.replace(/visible\(,?visible=false\)/g, 'visible=false')
|
||||
.replace(/visible\(\)/g, 'visible=true')
|
||||
.replace(/filter\(,?visible=true\)/g, 'visible=true')
|
||||
.replace(/filter\(,?visible=false\)/g, 'visible=false')
|
||||
.replace(/filter\(,?hastext=([^)]+)\)/g, 'internal:has-text=$1')
|
||||
.replace(/filter\(,?hasnottext=([^)]+)\)/g, 'internal:has-not-text=$1')
|
||||
.replace(/filter\(,?has2=([^)]+)\)/g, 'internal:has=$1')
|
||||
|
|
|
|||
16
packages/playwright-core/types/types.d.ts
vendored
16
packages/playwright-core/types/types.d.ts
vendored
|
|
@ -13129,6 +13129,11 @@ export interface Locator {
|
|||
* `<article><div>Playwright</div></article>`.
|
||||
*/
|
||||
hasText?: string|RegExp;
|
||||
|
||||
/**
|
||||
* Only matches visible or invisible elements.
|
||||
*/
|
||||
visible?: boolean;
|
||||
}): Locator;
|
||||
|
||||
/**
|
||||
|
|
@ -14520,17 +14525,6 @@ export interface Locator {
|
|||
trial?: boolean;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* Returns a locator that only matches [visible](https://playwright.dev/docs/actionability#visible) elements.
|
||||
* @param options
|
||||
*/
|
||||
visible(options?: {
|
||||
/**
|
||||
* Whether to match visible or invisible elements.
|
||||
*/
|
||||
visible?: boolean;
|
||||
}): Locator;
|
||||
|
||||
/**
|
||||
* Returns when element specified by locator satisfies the
|
||||
* [`state`](https://playwright.dev/docs/api/class-locator#locator-wait-for-option-state) option.
|
||||
|
|
|
|||
|
|
@ -92,13 +92,14 @@ it('should support locator.or()', async ({ page }) => {
|
|||
});
|
||||
|
||||
it('should support playwright.getBy*', async ({ page }) => {
|
||||
await page.setContent('<span>Hello</span><span title="world">World</span>');
|
||||
await page.setContent('<span>Hello</span><span title="world">World</span><div>one</div><div style="display:none">two</div>');
|
||||
expect(await page.evaluate(`playwright.getByText('hello').element.innerHTML`)).toContain('Hello');
|
||||
expect(await page.evaluate(`playwright.getByTitle('world').element.innerHTML`)).toContain('World');
|
||||
expect(await page.evaluate(`playwright.locator('span').filter({ hasText: 'hello' }).element.innerHTML`)).toContain('Hello');
|
||||
expect(await page.evaluate(`playwright.locator('span').first().element.innerHTML`)).toContain('Hello');
|
||||
expect(await page.evaluate(`playwright.locator('span').last().element.innerHTML`)).toContain('World');
|
||||
expect(await page.evaluate(`playwright.locator('span').nth(1).element.innerHTML`)).toContain('World');
|
||||
expect(await page.evaluate(`playwright.locator('div').filter({ visible: false }).element.innerHTML`)).toContain('two');
|
||||
});
|
||||
|
||||
it('expected properties on playwright object', async ({ page }) => {
|
||||
|
|
|
|||
|
|
@ -321,23 +321,17 @@ it('reverse engineer hasNotText', async ({ page }) => {
|
|||
});
|
||||
|
||||
it('reverse engineer visible', async ({ page }) => {
|
||||
expect.soft(generate(page.getByText('Hello').visible().locator('div'))).toEqual({
|
||||
csharp: `GetByText("Hello").Visible().Locator("div")`,
|
||||
java: `getByText("Hello").visible().locator("div")`,
|
||||
javascript: `getByText('Hello').visible().locator('div')`,
|
||||
python: `get_by_text("Hello").visible().locator("div")`,
|
||||
expect.soft(generate(page.getByText('Hello').filter({ visible: true }).locator('div'))).toEqual({
|
||||
csharp: `GetByText("Hello").Filter(new() { Visible = true }).Locator("div")`,
|
||||
java: `getByText("Hello").filter(new Locator.FilterOptions().setVisible(true)).locator("div")`,
|
||||
javascript: `getByText('Hello').filter({ visible: true }).locator('div')`,
|
||||
python: `get_by_text("Hello").filter(visible=True).locator("div")`,
|
||||
});
|
||||
expect.soft(generate(page.getByText('Hello').visible({ visible: true }).locator('div'))).toEqual({
|
||||
csharp: `GetByText("Hello").Visible().Locator("div")`,
|
||||
java: `getByText("Hello").visible().locator("div")`,
|
||||
javascript: `getByText('Hello').visible().locator('div')`,
|
||||
python: `get_by_text("Hello").visible().locator("div")`,
|
||||
});
|
||||
expect.soft(generate(page.getByText('Hello').visible({ visible: false }).locator('div'))).toEqual({
|
||||
csharp: `GetByText("Hello").Visible(new() { Visible = false }).Locator("div")`,
|
||||
java: `getByText("Hello").visible(new Locator.VisibleOptions().setVisible(false)).locator("div")`,
|
||||
javascript: `getByText('Hello').visible({ visible: false }).locator('div')`,
|
||||
python: `get_by_text("Hello").visible(visible=False).locator("div")`,
|
||||
expect.soft(generate(page.getByText('Hello').filter({ visible: false }).locator('div'))).toEqual({
|
||||
csharp: `GetByText("Hello").Filter(new() { Visible = false }).Locator("div")`,
|
||||
java: `getByText("Hello").filter(new Locator.FilterOptions().setVisible(false)).locator("div")`,
|
||||
javascript: `getByText('Hello').filter({ visible: false }).locator('div')`,
|
||||
python: `get_by_text("Hello").filter(visible=False).locator("div")`,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ it('should combine visible with other selectors', async ({ page }) => {
|
|||
await expect(page.locator('.item >> visible=true >> text=data3')).toHaveText('visible data3');
|
||||
});
|
||||
|
||||
it('should support .visible()', async ({ page }) => {
|
||||
it('should support filter(visible)', async ({ page }) => {
|
||||
await page.setContent(`<div>
|
||||
<div class="item" style="display: none">Hidden data0</div>
|
||||
<div class="item">visible data1</div>
|
||||
|
|
@ -160,11 +160,10 @@ it('should support .visible()', async ({ page }) => {
|
|||
<div class="item">visible data3</div>
|
||||
</div>
|
||||
`);
|
||||
const locator = page.locator('.item').visible().nth(1);
|
||||
const locator = page.locator('.item').filter({ visible: true }).nth(1);
|
||||
await expect(locator).toHaveText('visible data2');
|
||||
await expect(page.locator('.item').visible().getByText('data3')).toHaveText('visible data3');
|
||||
await expect(page.locator('.item').visible({ visible: true }).getByText('data2')).toHaveText('visible data2');
|
||||
await expect(page.locator('.item').visible({ visible: false }).getByText('data1')).toHaveText('Hidden data1');
|
||||
await expect(page.locator('.item').filter({ visible: true }).getByText('data3')).toHaveText('visible data3');
|
||||
await expect(page.locator('.item').filter({ visible: false }).getByText('data1')).toHaveText('Hidden data1');
|
||||
});
|
||||
|
||||
it('locator.count should work with deleted Map in main world', async ({ page }) => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue