mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
feat(api): introduce Locator.all, enumerate (#19461)
This commit is contained in:
parent
a1bb1dd94f
commit
17a0074459
@ -6,6 +6,40 @@ a way to find element(s) on the page at any moment. Locator can be created with
|
||||
|
||||
[Learn more about locators](../locators.md).
|
||||
|
||||
## async method: Locator.all
|
||||
* since: v1.14
|
||||
- returns: <[Array]<[Locator]>>
|
||||
|
||||
When locator points to a list of elements, returns array of locators, pointing
|
||||
to respective elements.
|
||||
|
||||
**Usage**
|
||||
|
||||
```js
|
||||
for (const li of await page.getByRole('listitem').all())
|
||||
await li.click();
|
||||
```
|
||||
|
||||
```python async
|
||||
for li in await page.get_by_role('listitem').all():
|
||||
await li.click();
|
||||
```
|
||||
|
||||
```python sync
|
||||
for li in page.get_by_role('listitem').all():
|
||||
li.click();
|
||||
```
|
||||
|
||||
```java
|
||||
for (Locator li : page.getByRole('listitem').all())
|
||||
li.click();
|
||||
```
|
||||
|
||||
```csharp
|
||||
foreach (var li in await page.GetByRole('listitem').AllAsync())
|
||||
await li.ClickAsync();
|
||||
```
|
||||
|
||||
## async method: Locator.allInnerTexts
|
||||
* since: v1.14
|
||||
- returns: <[Array]<[string]>>
|
||||
@ -424,6 +458,36 @@ Resolves given locator to the first matching DOM element. If no elements matchin
|
||||
|
||||
Resolves given locator to all matching DOM elements.
|
||||
|
||||
## async method: Locator.enumerate
|
||||
* since: v1.14
|
||||
* langs: js, python, csharp
|
||||
- returns: <[Array]<[Tuple]<[Locator],[int]>>>
|
||||
|
||||
When locator points to a list of elements, returns array of (locator, index) pairs,
|
||||
pointing to respective elements.
|
||||
|
||||
**Usage**
|
||||
|
||||
```js
|
||||
for (const [li, i] of await page.getByRole('listitem').enumerate())
|
||||
await li.click();
|
||||
```
|
||||
|
||||
```python async
|
||||
for (li, index) in await page.get_by_role('listitem').enumerate():
|
||||
await li.click();
|
||||
```
|
||||
|
||||
```python sync
|
||||
for (li, index) in page.get_by_role('listitem').enumerate():
|
||||
li.click();
|
||||
```
|
||||
|
||||
```csharp
|
||||
foreach (var (li, index) in await page.GetByRole('listitem').AllAsync())
|
||||
await li.ClickAsync();
|
||||
```
|
||||
|
||||
## async method: Locator.evaluate
|
||||
* since: v1.14
|
||||
- returns: <[Serializable]>
|
||||
|
@ -1360,34 +1360,58 @@ You should now have a "screenshot.png" file in your project's root directory.
|
||||
|
||||
### Rare use cases
|
||||
|
||||
#### Get All text contents
|
||||
#### Do something with each element in the list
|
||||
|
||||
Iterate elements:
|
||||
|
||||
```js
|
||||
const rows = page.getByRole('listitem');
|
||||
const texts = await rows.allTextContents();
|
||||
for (const row of await page.getByRole('listitem').all())
|
||||
console.log(await row.textContent());
|
||||
```
|
||||
|
||||
```python async
|
||||
rows = page.get_by_role("listitem")
|
||||
texts = await rows.all_text_contents()
|
||||
for row in await page.get_by_role("listitem").all():
|
||||
print(await row.text_content())
|
||||
```
|
||||
|
||||
```python sync
|
||||
rows = page.get_by_role("listitem")
|
||||
texts = rows.all_text_contents()
|
||||
for row in page.get_by_role("listitem").all():
|
||||
print(row.text_content())
|
||||
```
|
||||
|
||||
```java
|
||||
Locator rows = page.getByRole(AriaRole.LISTITEM);
|
||||
List<String> texts = rows.allTextContents();
|
||||
for (Locator row : page.getByRole(AriaRole.LISTITEM).all())
|
||||
System.out.println(row.textContent());
|
||||
```
|
||||
|
||||
```csharp
|
||||
var rows = page.GetByRole(AriaRole.Listitem);
|
||||
var texts = await rows.AllTextContentsAsync();
|
||||
foreach (var row in await page.GetByRole(AriaRole.Listitem).AllAsync())
|
||||
Console.WriteLine(await row.TextContentAsync());
|
||||
```
|
||||
|
||||
#### Do something with each element in the list
|
||||
Iterate elements with their respective indexes:
|
||||
|
||||
```js
|
||||
for (const [row, index] of await page.getByRole('listitem').enumerate())
|
||||
console.log(index, await row.textContent());
|
||||
```
|
||||
|
||||
```python async
|
||||
for (row, index) in await page.get_by_role('listitem').enumerate():
|
||||
print(index, await row.text_content())
|
||||
```
|
||||
|
||||
```python sync
|
||||
for (row, index) in page.get_by_role('listitem').enumerate():
|
||||
print(index, row.text_content())
|
||||
```
|
||||
|
||||
```csharp
|
||||
foreach (var (row, index) in await page.GetByRole('listitem').AllAsync())
|
||||
Console.WriteLine(index + ' ' + await row.TextContentAsync());
|
||||
```
|
||||
|
||||
Iterate using regular for loop:
|
||||
|
||||
```js
|
||||
const rows = page.getByRole('listitem');
|
||||
|
@ -292,6 +292,14 @@ export class Locator implements api.Locator {
|
||||
return this._frame.uncheck(this._selector, { strict: true, ...options });
|
||||
}
|
||||
|
||||
async all(): Promise<Locator[]> {
|
||||
return new Array(await this.count()).fill(0).map((e, i) => this.nth(i));
|
||||
}
|
||||
|
||||
async enumerate(): Promise<[Locator, number][]> {
|
||||
return new Array(await this.count()).fill(0).map((e, i) => [this.nth(i), i]);
|
||||
}
|
||||
|
||||
async allInnerTexts(): Promise<string[]> {
|
||||
return this._frame.$$eval(this._selector, ee => ee.map(e => (e as HTMLElement).innerText));
|
||||
}
|
||||
|
29
packages/playwright-core/types/types.d.ts
vendored
29
packages/playwright-core/types/types.d.ts
vendored
@ -21,6 +21,8 @@ import { ReadStream } from 'fs';
|
||||
import { Protocol } from './protocol';
|
||||
import { Serializable, EvaluationArgument, PageFunction, PageFunctionOn, SmartHandle, ElementHandleForTag, BindingSource } from './structs';
|
||||
|
||||
type Tuple<A,B> = [A,B];
|
||||
|
||||
type PageWaitForSelectorOptionsNotHidden = PageWaitForSelectorOptions & {
|
||||
state?: 'visible'|'attached';
|
||||
};
|
||||
@ -9803,6 +9805,19 @@ export interface Locator {
|
||||
elementHandle(options?: {
|
||||
timeout?: number;
|
||||
}): Promise<null|ElementHandle<SVGElement | HTMLElement>>;
|
||||
/**
|
||||
* When locator points to a list of elements, returns array of locators, pointing to respective elements.
|
||||
*
|
||||
* **Usage**
|
||||
*
|
||||
* ```js
|
||||
* for (const li of await page.getByRole('listitem').all())
|
||||
* await li.click();
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
all(): Promise<Array<Locator>>;
|
||||
|
||||
/**
|
||||
* Returns an array of `node.innerText` values for all matching nodes.
|
||||
*/
|
||||
@ -10239,6 +10254,20 @@ export interface Locator {
|
||||
*/
|
||||
elementHandles(): Promise<Array<ElementHandle>>;
|
||||
|
||||
/**
|
||||
* When locator points to a list of elements, returns array of (locator, index) pairs, pointing to respective
|
||||
* elements.
|
||||
*
|
||||
* **Usage**
|
||||
*
|
||||
* ```js
|
||||
* for (const [li, i] of await page.getByRole('listitem').enumerate())
|
||||
* await li.click();
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
enumerate(): Promise<Array<Tuple<Locator, number>>>;
|
||||
|
||||
/**
|
||||
* Returns the return value of `pageFunction` as a [JSHandle].
|
||||
*
|
||||
|
35
tests/page/locator-list.spec.ts
Normal file
35
tests/page/locator-list.spec.ts
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './pageTest';
|
||||
|
||||
it('locator.all should work', async ({ page }) => {
|
||||
await page.setContent(`<div><p>A</p><p>B</p><p>C</p></div>`);
|
||||
const texts = [];
|
||||
for (const p of await page.locator('div >> p').all())
|
||||
texts.push(await p.textContent());
|
||||
expect(texts).toEqual(['A', 'B', 'C']);
|
||||
});
|
||||
|
||||
it('locator.enumerate should work', async ({ page }) => {
|
||||
await page.setContent(`<div><p>0</p><p>1</p><p>2</p><p>3</p></div>`);
|
||||
let items = 0;
|
||||
for (const [p, i] of await page.locator('div >> p').enumerate()) {
|
||||
++items;
|
||||
expect(await p.textContent()).toBe(String(i));
|
||||
}
|
||||
expect(items).toBe(4);
|
||||
});
|
2
utils/generate_types/overrides.d.ts
vendored
2
utils/generate_types/overrides.d.ts
vendored
@ -20,6 +20,8 @@ import { ReadStream } from 'fs';
|
||||
import { Protocol } from './protocol';
|
||||
import { Serializable, EvaluationArgument, PageFunction, PageFunctionOn, SmartHandle, ElementHandleForTag, BindingSource } from './structs';
|
||||
|
||||
type Tuple<A,B> = [A,B];
|
||||
|
||||
type PageWaitForSelectorOptionsNotHidden = PageWaitForSelectorOptions & {
|
||||
state?: 'visible'|'attached';
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user