docs: emphasize that has is a relative locator (#28588)

References #28556.
This commit is contained in:
Dmitry Gozman 2023-12-11 17:35:29 -08:00 committed by GitHub
parent 23415da3db
commit ee9a7dad12
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 92 additions and 14 deletions

View file

@ -1023,9 +1023,11 @@ For example, `"Playwright"` matches `<article><div>Playwright</div></article>`.
## locator-option-has
- `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>`.
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.
## locator-option-has-not

View file

@ -973,19 +973,21 @@ await page
.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
await expect(page
.getByRole('listitem')
.filter({ has: page.getByText('Product 2') }))
.filter({ has: page.getByRole('heading', { name: 'Product 2' }) }))
.toHaveCount(1);
```
```java
assertThat(page
.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);
```
@ -1014,6 +1016,55 @@ await Expect(Page
.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
We can also filter by **not having** a matching element inside.

View file

@ -3243,8 +3243,13 @@ export interface Page {
*/
locator(selector: string, options?: {
/**
* Matches elements containing an element that matches an inner locator. Inner locator is queried against the outer
* one. For example, `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`.
* 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>`.
*
* 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
* FrameLocator}s.
@ -6676,8 +6681,13 @@ export interface Frame {
*/
locator(selector: string, options?: {
/**
* Matches elements containing an element that matches an inner locator. Inner locator is queried against the outer
* one. For example, `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`.
* 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>`.
*
* 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
* FrameLocator}s.
@ -11252,8 +11262,13 @@ export interface Locator {
*/
filter(options?: {
/**
* Matches elements containing an element that matches an inner locator. Inner locator is queried against the outer
* one. For example, `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`.
* 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>`.
*
* 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
* FrameLocator}s.
@ -11956,8 +11971,13 @@ export interface Locator {
*/
locator(selectorOrLocator: string|Locator, options?: {
/**
* Matches elements containing an element that matches an inner locator. Inner locator is queried against the outer
* one. For example, `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`.
* 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>`.
*
* 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
* FrameLocator}s.
@ -17735,8 +17755,13 @@ export interface FrameLocator {
*/
locator(selectorOrLocator: string|Locator, options?: {
/**
* Matches elements containing an element that matches an inner locator. Inner locator is queried against the outer
* one. For example, `article` that has `text=Playwright` matches `<article><div>Playwright</div></article>`.
* 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>`.
*
* 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
* FrameLocator}s.