docs: emphasize that has is a relative locator (#28588)
References #28556.
This commit is contained in:
parent
23415da3db
commit
ee9a7dad12
|
|
@ -1023,9 +1023,11 @@ For example, `"Playwright"` matches `<article><div>Playwright</div></article>`.
|
||||||
## locator-option-has
|
## locator-option-has
|
||||||
- `has` <[Locator]>
|
- `has` <[Locator]>
|
||||||
|
|
||||||
Matches elements containing an element that matches an inner locator. Inner locator is queried against the outer one.
|
Narrows down the results of the method to those which contain elements matching this relative locator.
|
||||||
For example, `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`.
|
For example, `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`.
|
||||||
|
|
||||||
|
Inner locator **must be relative** to the outer locator and is queried starting with the outer locator match, not the document root. For example, you can find `content` that has `div` in `<article><content><div>Playwright</div></content></article>`. However, looking for `content` that has `article div` will fail, because the inner locator must be relative and should not use any elements outside the `content`.
|
||||||
|
|
||||||
Note that outer and inner locators must belong to the same frame. Inner locator must not contain [FrameLocator]s.
|
Note that outer and inner locators must belong to the same frame. Inner locator must not contain [FrameLocator]s.
|
||||||
|
|
||||||
## locator-option-has-not
|
## locator-option-has-not
|
||||||
|
|
|
||||||
|
|
@ -973,19 +973,21 @@ await page
|
||||||
.ClickAsync();
|
.ClickAsync();
|
||||||
```
|
```
|
||||||
|
|
||||||
We can also assert the product card to make sure there is only one
|
We can also assert the product card to make sure there is only one:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
await expect(page
|
await expect(page
|
||||||
.getByRole('listitem')
|
.getByRole('listitem')
|
||||||
.filter({ has: page.getByText('Product 2') }))
|
.filter({ has: page.getByRole('heading', { name: 'Product 2' }) }))
|
||||||
.toHaveCount(1);
|
.toHaveCount(1);
|
||||||
```
|
```
|
||||||
|
|
||||||
```java
|
```java
|
||||||
assertThat(page
|
assertThat(page
|
||||||
.getByRole(AriaRole.LISTITEM)
|
.getByRole(AriaRole.LISTITEM)
|
||||||
.filter(new Locator.FilterOptions().setHas(page.getByText("Product 2")))
|
.filter(new Locator.FilterOptions()
|
||||||
|
.setHas(page.GetByRole(AriaRole.HEADING,
|
||||||
|
new Page.GetByRoleOptions().setName("Product 2"))))
|
||||||
.hasCount(1);
|
.hasCount(1);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -1014,6 +1016,55 @@ await Expect(Page
|
||||||
.ToHaveCountAsync(1);
|
.ToHaveCountAsync(1);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The filtering locator **must be relative** to the original locator and is queried starting with the original locator match, not the document root. Therefore, the following will not work, because the filtering locator starts matching from the `<ul>` list element that is outside of the `<li>` list item matched by the original locator:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// ✖ WRONG
|
||||||
|
await expect(page
|
||||||
|
.getByRole('listitem')
|
||||||
|
.filter({ has: page.getByRole('list').getByText('Product 2') }))
|
||||||
|
.toHaveCount(1);
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
// ✖ WRONG
|
||||||
|
assertThat(page
|
||||||
|
.getByRole(AriaRole.LISTITEM)
|
||||||
|
.filter(new Locator.FilterOptions()
|
||||||
|
.setHas(page.GetByRole(AriaRole.LIST)
|
||||||
|
.GetByRole(AriaRole.HEADING,
|
||||||
|
new Page.GetByRoleOptions().setName("Product 2"))))
|
||||||
|
.hasCount(1);
|
||||||
|
```
|
||||||
|
|
||||||
|
```python async
|
||||||
|
# ✖ WRONG
|
||||||
|
await expect(
|
||||||
|
page.get_by_role("listitem").filter(
|
||||||
|
has=page.get_by_role("list").get_by_role("heading", name="Product 2")
|
||||||
|
)
|
||||||
|
).to_have_count(1)
|
||||||
|
```
|
||||||
|
|
||||||
|
```python sync
|
||||||
|
# ✖ WRONG
|
||||||
|
expect(
|
||||||
|
page.get_by_role("listitem").filter(
|
||||||
|
has=page.get_by_role("list").get_by_role("heading", name="Product 2")
|
||||||
|
)
|
||||||
|
).to_have_count(1)
|
||||||
|
```
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// ✖ WRONG
|
||||||
|
await Expect(Page
|
||||||
|
.GetByRole(AriaRole.Listitem)
|
||||||
|
.Filter(new() {
|
||||||
|
Has = page.GetByRole(AriaRole.List).GetByRole(AriaRole.Heading, new() { Name = "Product 2" })
|
||||||
|
}))
|
||||||
|
.ToHaveCountAsync(1);
|
||||||
|
```
|
||||||
|
|
||||||
### Filter by not having child/descendant
|
### Filter by not having child/descendant
|
||||||
|
|
||||||
We can also filter by **not having** a matching element inside.
|
We can also filter by **not having** a matching element inside.
|
||||||
|
|
|
||||||
45
packages/playwright-core/types/types.d.ts
vendored
45
packages/playwright-core/types/types.d.ts
vendored
|
|
@ -3243,8 +3243,13 @@ export interface Page {
|
||||||
*/
|
*/
|
||||||
locator(selector: string, options?: {
|
locator(selector: string, options?: {
|
||||||
/**
|
/**
|
||||||
* Matches elements containing an element that matches an inner locator. Inner locator is queried against the outer
|
* Narrows down the results of the method to those which contain elements matching this relative locator. For example,
|
||||||
* one. For example, `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`.
|
* `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`.
|
||||||
|
*
|
||||||
|
* Inner locator **must be relative** to the outer locator and is queried starting with the outer locator match, not
|
||||||
|
* the document root. For example, you can find `content` that has `div` in
|
||||||
|
* `<article><content><div>Playwright</div></content></article>`. However, looking for `content` that has `article
|
||||||
|
* div` will fail, because the inner locator must be relative and should not use any elements outside the `content`.
|
||||||
*
|
*
|
||||||
* Note that outer and inner locators must belong to the same frame. Inner locator must not contain {@link
|
* Note that outer and inner locators must belong to the same frame. Inner locator must not contain {@link
|
||||||
* FrameLocator}s.
|
* FrameLocator}s.
|
||||||
|
|
@ -6676,8 +6681,13 @@ export interface Frame {
|
||||||
*/
|
*/
|
||||||
locator(selector: string, options?: {
|
locator(selector: string, options?: {
|
||||||
/**
|
/**
|
||||||
* Matches elements containing an element that matches an inner locator. Inner locator is queried against the outer
|
* Narrows down the results of the method to those which contain elements matching this relative locator. For example,
|
||||||
* one. For example, `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`.
|
* `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`.
|
||||||
|
*
|
||||||
|
* Inner locator **must be relative** to the outer locator and is queried starting with the outer locator match, not
|
||||||
|
* the document root. For example, you can find `content` that has `div` in
|
||||||
|
* `<article><content><div>Playwright</div></content></article>`. However, looking for `content` that has `article
|
||||||
|
* div` will fail, because the inner locator must be relative and should not use any elements outside the `content`.
|
||||||
*
|
*
|
||||||
* Note that outer and inner locators must belong to the same frame. Inner locator must not contain {@link
|
* Note that outer and inner locators must belong to the same frame. Inner locator must not contain {@link
|
||||||
* FrameLocator}s.
|
* FrameLocator}s.
|
||||||
|
|
@ -11252,8 +11262,13 @@ export interface Locator {
|
||||||
*/
|
*/
|
||||||
filter(options?: {
|
filter(options?: {
|
||||||
/**
|
/**
|
||||||
* Matches elements containing an element that matches an inner locator. Inner locator is queried against the outer
|
* Narrows down the results of the method to those which contain elements matching this relative locator. For example,
|
||||||
* one. For example, `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`.
|
* `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`.
|
||||||
|
*
|
||||||
|
* Inner locator **must be relative** to the outer locator and is queried starting with the outer locator match, not
|
||||||
|
* the document root. For example, you can find `content` that has `div` in
|
||||||
|
* `<article><content><div>Playwright</div></content></article>`. However, looking for `content` that has `article
|
||||||
|
* div` will fail, because the inner locator must be relative and should not use any elements outside the `content`.
|
||||||
*
|
*
|
||||||
* Note that outer and inner locators must belong to the same frame. Inner locator must not contain {@link
|
* Note that outer and inner locators must belong to the same frame. Inner locator must not contain {@link
|
||||||
* FrameLocator}s.
|
* FrameLocator}s.
|
||||||
|
|
@ -11956,8 +11971,13 @@ export interface Locator {
|
||||||
*/
|
*/
|
||||||
locator(selectorOrLocator: string|Locator, options?: {
|
locator(selectorOrLocator: string|Locator, options?: {
|
||||||
/**
|
/**
|
||||||
* Matches elements containing an element that matches an inner locator. Inner locator is queried against the outer
|
* Narrows down the results of the method to those which contain elements matching this relative locator. For example,
|
||||||
* one. For example, `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`.
|
* `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`.
|
||||||
|
*
|
||||||
|
* Inner locator **must be relative** to the outer locator and is queried starting with the outer locator match, not
|
||||||
|
* the document root. For example, you can find `content` that has `div` in
|
||||||
|
* `<article><content><div>Playwright</div></content></article>`. However, looking for `content` that has `article
|
||||||
|
* div` will fail, because the inner locator must be relative and should not use any elements outside the `content`.
|
||||||
*
|
*
|
||||||
* Note that outer and inner locators must belong to the same frame. Inner locator must not contain {@link
|
* Note that outer and inner locators must belong to the same frame. Inner locator must not contain {@link
|
||||||
* FrameLocator}s.
|
* FrameLocator}s.
|
||||||
|
|
@ -17735,8 +17755,13 @@ export interface FrameLocator {
|
||||||
*/
|
*/
|
||||||
locator(selectorOrLocator: string|Locator, options?: {
|
locator(selectorOrLocator: string|Locator, options?: {
|
||||||
/**
|
/**
|
||||||
* Matches elements containing an element that matches an inner locator. Inner locator is queried against the outer
|
* Narrows down the results of the method to those which contain elements matching this relative locator. For example,
|
||||||
* one. For example, `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`.
|
* `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`.
|
||||||
|
*
|
||||||
|
* Inner locator **must be relative** to the outer locator and is queried starting with the outer locator match, not
|
||||||
|
* the document root. For example, you can find `content` that has `div` in
|
||||||
|
* `<article><content><div>Playwright</div></content></article>`. However, looking for `content` that has `article
|
||||||
|
* div` will fail, because the inner locator must be relative and should not use any elements outside the `content`.
|
||||||
*
|
*
|
||||||
* Note that outer and inner locators must belong to the same frame. Inner locator must not contain {@link
|
* Note that outer and inner locators must belong to the same frame. Inner locator must not contain {@link
|
||||||
* FrameLocator}s.
|
* FrameLocator}s.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue