From 917924d2799a94cb3c1d4470a8527e3f0b212206 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Wed, 8 Dec 2021 09:54:01 -0800 Subject: [PATCH] docs: extract locators doc (#10795) --- docs/src/api/class-locator.md | 246 +---------- docs/src/locators.md | 293 +++++++++++++ docs/src/selectors.md | 498 +++++++++++----------- packages/playwright-core/types/types.d.ts | 71 +-- 4 files changed, 547 insertions(+), 561 deletions(-) create mode 100644 docs/src/locators.md diff --git a/docs/src/api/class-locator.md b/docs/src/api/class-locator.md index 921086c11afe6..06ebb6a1533f0 100644 --- a/docs/src/api/class-locator.md +++ b/docs/src/api/class-locator.md @@ -1,249 +1,9 @@ # class: Locator -Locator represents a view to the element(s) on the page. It captures the logic sufficient to retrieve the element at any given moment. Locator can be created with the [`method: Page.locator`] method. +Locators are the central piece of Playwright's auto-waiting and retry-ability. In a nutshell, locators represent +a way to find element(s) on the page at any moment. Locator can be created with the [`method: Page.locator`] method. -```js -const locator = page.locator('text=Submit'); -await locator.click(); -``` - -```java -Locator locator = page.locator("text=Submit"); -locator.click(); -``` - -```python async -locator = page.locator("text=Submit") -await locator.click() -``` - -```python sync -locator = page.locator("text=Submit") -locator.click() -``` - -```csharp -var locator = page.Locator("text=Submit"); -await locator.ClickAsync(); -``` - -The difference between the Locator and [ElementHandle] is that the latter points to a particular element, while Locator captures the logic of how to retrieve that element. - -In the example below, handle points to a particular DOM element on page. If that element changes text or is used by React to render an entirely different component, handle is still pointing to that very DOM element. This can lead to unexpected behaviors. - -```js -const handle = await page.$('text=Submit'); -// ... -await handle.hover(); -await handle.click(); -``` - -```java -ElementHandle handle = page.querySelector("text=Submit"); -handle.hover(); -handle.click(); -``` - -```python async -handle = await page.query_selector("text=Submit") -await handle.hover() -await handle.click() -``` - -```python sync -handle = page.query_selector("text=Submit") -handle.hover() -handle.click() -``` - -```csharp -var handle = await page.QuerySelectorAsync("text=Submit"); -await handle.HoverAsync(); -await handle.ClickAsync(); -``` - -With the locator, every time the `element` is used, up-to-date DOM element is located in the page using the selector. So in the snippet below, underlying DOM element is going to be located twice. - -```js -const locator = page.locator('text=Submit'); -// ... -await locator.hover(); -await locator.click(); -``` - -```java -Locator locator = page.locator("text=Submit"); -locator.hover(); -locator.click(); -``` - -```python async -locator = page.locator("text=Submit") -await locator.hover() -await locator.click() -``` - -```python sync -locator = page.locator("text=Submit") -locator.hover() -locator.click() -``` - -```csharp -var locator = page.Locator("text=Submit"); -await locator.HoverAsync(); -await locator.ClickAsync(); -``` - -**Strictness** - -Locators are strict. This means that all operations on locators that imply -some target DOM element will throw if more than one element matches given -selector. - -```js -// Throws if there are several buttons in DOM: -await page.locator('button').click(); - -// Works because we explicitly tell locator to pick the first element: -await page.locator('button').first().click(); - -// Works because count knows what to do with multiple matches: -await page.locator('button').count(); -``` - -```python async -# Throws if there are several buttons in DOM: -await page.locator('button').click() - -# Works because we explicitly tell locator to pick the first element: -await page.locator('button').first.click() - -# Works because count knows what to do with multiple matches: -await page.locator('button').count() -``` - -```python sync -# Throws if there are several buttons in DOM: -page.locator('button').click() - -# Works because we explicitly tell locator to pick the first element: -page.locator('button').first.click() - -# Works because count knows what to do with multiple matches: -page.locator('button').count() -``` - -```java -// Throws if there are several buttons in DOM: -page.locator("button").click(); - -// Works because we explicitly tell locator to pick the first element: -page.locator("button").first().click(); - -// Works because count knows what to do with multiple matches: -page.locator("button").count(); -``` - -```csharp -// Throws if there are several buttons in DOM: -await page.Locator("button").ClickAsync(); - -// Works because we explicitly tell locator to pick the first element: -await page.Locator("button").First.ClickAsync(); - -// Works because Count knows what to do with multiple matches: -await page.Locator("button").CountAsync(); -``` - -**Lists** - -You can also use locators to work with the element lists. - -```js -// Locate elements, this locator points to a list. -const rows = page.locator('table tr'); - -// Pattern 1: use locator methods to calculate text on the whole list. -const texts = await rows.allTextContents(); - -// Pattern 2: do something with each element in the list. -const count = await rows.count() -for (let i = 0; i < count; ++i) - console.log(await rows.nth(i).textContent()); - -// Pattern 3: resolve locator to elements on page and map them to their text content. -// Note: the code inside evaluateAll runs in page, you can call any DOM apis there. -const texts = await rows.evaluateAll(list => list.map(element => element.textContent)); -``` - -```python async -# Locate elements, this locator points to a list. -rows = page.locator("table tr") - -# Pattern 1: use locator methods to calculate text on the whole list. -texts = await rows.all_text_contents() - -# Pattern 2: do something with each element in the list. -count = await rows.count() -for i in range(count): - print(await rows.nth(i).text_content()) - -# Pattern 3: resolve locator to elements on page and map them to their text content. -# Note: the code inside evaluateAll runs in page, you can call any DOM apis there. -texts = await rows.evaluate_all("list => list.map(element => element.textContent)") -``` - -```python sync -# Locate elements, this locator points to a list. -rows = page.locator("table tr") - -# Pattern 1: use locator methods to calculate text on the whole list. -texts = rows.all_text_contents() - -# Pattern 2: do something with each element in the list. -count = rows.count() -for i in range(count): - print(rows.nth(i).text_content()) - -# Pattern 3: resolve locator to elements on page and map them to their text content. -# Note: the code inside evaluateAll runs in page, you can call any DOM apis there. -texts = rows.evaluate_all("list => list.map(element => element.textContent)") -``` - -```java -// Locate elements, this locator points to a list. -Locator rows = page.locator("table tr"); - -// Pattern 1: use locator methods to calculate text on the whole list. -List texts = rows.allTextContents(); - -// Pattern 2: do something with each element in the list. -int count = rows.count() -for (int i = 0; i < count; ++i) - System.out.println(rows.nth(i).textContent()); - -// Pattern 3: resolve locator to elements on page and map them to their text content. -// Note: the code inside evaluateAll runs in page, you can call any DOM apis there. -Object texts = rows.evaluateAll("list => list.map(element => element.textContent)"); -``` - -```csharp -// Locate elements, this locator points to a list. -var rows = page.Locator("table tr"); - -// Pattern 1: use locator methods to calculate text on the whole list. -var texts = await rows.AllTextContentsAsync(); - -// Pattern 2: do something with each element in the list: -var count = await rows.CountAsync() -for (let i = 0; i < count; ++i) - Console.WriteLine(await rows.Nth(i).TextContentAsync()); - -// Pattern 3: resolve locator to elements on page and map them to their text content -// Note: the code inside evaluateAll runs in page, you can call any DOM apis there -var texts = await rows.EvaluateAllAsync("list => list.map(element => element.textContent)"); -``` +[Learn more about locators](./locators.md). ## async method: Locator.allInnerTexts - returns: <[Array]<[string]>> diff --git a/docs/src/locators.md b/docs/src/locators.md new file mode 100644 index 0000000000000..585981d97b041 --- /dev/null +++ b/docs/src/locators.md @@ -0,0 +1,293 @@ +--- +id: locators +title: "Locators" +--- + +[Locator]s are the central piece of Playwright's auto-waiting and retry-ability. In a nutshell, locators represent +a way to find element(s) on the page at any moment. Locator can be created with the [`method: Page.locator`] method. + +```js +const locator = page.locator('text=Submit'); +await locator.click(); +``` + +```java +Locator locator = page.locator("text=Submit"); +locator.click(); +``` + +```python async +locator = page.locator("text=Submit") +await locator.click() +``` + +```python sync +locator = page.locator("text=Submit") +locator.click() +``` + +```csharp +var locator = page.Locator("text=Submit"); +await locator.ClickAsync(); +``` + +Every time locator is used for some action, up-to-date DOM element is located in the page. So in the snippet +below, underlying DOM element is going to be located twice, prior to every action. This means that if the +DOM changes in between the calls due to re-render, the new element corresponding to the +locator will be used. + +```js +const locator = page.locator('text=Submit'); +// ... +await locator.hover(); +await locator.click(); +``` + +```java +Locator locator = page.locator("text=Submit"); +locator.hover(); +locator.click(); +``` + +```python async +locator = page.locator("text=Submit") +await locator.hover() +await locator.click() +``` + +```python sync +locator = page.locator("text=Submit") +locator.hover() +locator.click() +``` + +```csharp +var locator = page.Locator("text=Submit"); +await locator.HoverAsync(); +await locator.ClickAsync(); +``` + +## Strictness + +Locators are strict. This means that all operations on locators that imply +some target DOM element will throw if more than one element matches given +selector. + +```js +// Throws if there are several buttons in DOM: +await page.locator('button').click(); + +// Works because we explicitly tell locator to pick the first element: +await page.locator('button').first().click(); + +// Works because count knows what to do with multiple matches: +await page.locator('button').count(); +``` + +```python async +# Throws if there are several buttons in DOM: +await page.locator('button').click() + +# Works because we explicitly tell locator to pick the first element: +await page.locator('button').first.click() + +# Works because count knows what to do with multiple matches: +await page.locator('button').count() +``` + +```python sync +# Throws if there are several buttons in DOM: +page.locator('button').click() + +# Works because we explicitly tell locator to pick the first element: +page.locator('button').first.click() + +# Works because count knows what to do with multiple matches: +page.locator('button').count() +``` + +```java +// Throws if there are several buttons in DOM: +page.locator("button").click(); + +// Works because we explicitly tell locator to pick the first element: +page.locator("button").first().click(); + +// Works because count knows what to do with multiple matches: +page.locator("button").count(); +``` + +```csharp +// Throws if there are several buttons in DOM: +await page.Locator("button").ClickAsync(); + +// Works because we explicitly tell locator to pick the first element: +await page.Locator("button").First.ClickAsync(); + +// Works because Count knows what to do with multiple matches: +await page.Locator("button").CountAsync(); +``` + +## Lists + +You can also use locators to work with the element lists. + +```js +// Locate elements, this locator points to a list. +const rows = page.locator('table tr'); + +// Pattern 1: use locator methods to calculate text on the whole list. +const texts = await rows.allTextContents(); + +// Pattern 2: do something with each element in the list. +const count = await rows.count() +for (let i = 0; i < count; ++i) + console.log(await rows.nth(i).textContent()); + +// Pattern 3: resolve locator to elements on page and map them to their text content. +// Note: the code inside evaluateAll runs in page, you can call any DOM apis there. +const texts = await rows.evaluateAll(list => list.map(element => element.textContent)); +``` + +```python async +# Locate elements, this locator points to a list. +rows = page.locator("table tr") + +# Pattern 1: use locator methods to calculate text on the whole list. +texts = await rows.all_text_contents() + +# Pattern 2: do something with each element in the list. +count = await rows.count() +for i in range(count): + print(await rows.nth(i).text_content()) + +# Pattern 3: resolve locator to elements on page and map them to their text content. +# Note: the code inside evaluateAll runs in page, you can call any DOM apis there. +texts = await rows.evaluate_all("list => list.map(element => element.textContent)") +``` + +```python sync +# Locate elements, this locator points to a list. +rows = page.locator("table tr") + +# Pattern 1: use locator methods to calculate text on the whole list. +texts = rows.all_text_contents() + +# Pattern 2: do something with each element in the list. +count = rows.count() +for i in range(count): + print(rows.nth(i).text_content()) + +# Pattern 3: resolve locator to elements on page and map them to their text content. +# Note: the code inside evaluateAll runs in page, you can call any DOM apis there. +texts = rows.evaluate_all("list => list.map(element => element.textContent)") +``` + +```java +// Locate elements, this locator points to a list. +Locator rows = page.locator("table tr"); + +// Pattern 1: use locator methods to calculate text on the whole list. +List texts = rows.allTextContents(); + +// Pattern 2: do something with each element in the list. +int count = rows.count() +for (int i = 0; i < count; ++i) + System.out.println(rows.nth(i).textContent()); + +// Pattern 3: resolve locator to elements on page and map them to their text content. +// Note: the code inside evaluateAll runs in page, you can call any DOM apis there. +Object texts = rows.evaluateAll("list => list.map(element => element.textContent)"); +``` + +```csharp +// Locate elements, this locator points to a list. +var rows = page.Locator("table tr"); + +// Pattern 1: use locator methods to calculate text on the whole list. +var texts = await rows.AllTextContentsAsync(); + +// Pattern 2: do something with each element in the list: +var count = await rows.CountAsync() +for (let i = 0; i < count; ++i) + Console.WriteLine(await rows.Nth(i).TextContentAsync()); + +// Pattern 3: resolve locator to elements on page and map them to their text content +// Note: the code inside evaluateAll runs in page, you can call any DOM apis there +var texts = await rows.EvaluateAllAsync("list => list.map(element => element.textContent)"); +``` + +## Locator vs ElementHandle + +:::caution +We only recommend using [ElementHandle] in the rare cases when you need to perform extensive DOM traversal +on a static page. For all user actions and assertions use locator instead. +::: + +The difference between the [Locator] and [ElementHandle] is that the latter points to a particular element, while Locator captures the logic of how to retrieve that element. + +In the example below, handle points to a particular DOM element on page. If that element changes text or is used by React to render an entirely different component, handle is still pointing to that very stale DOM element. This can lead to unexpected behaviors. + +```js +const handle = await page.$('text=Submit'); +// ... +await handle.hover(); +await handle.click(); +``` + +```java +ElementHandle handle = page.querySelector("text=Submit"); +handle.hover(); +handle.click(); +``` + +```python async +handle = await page.query_selector("text=Submit") +await handle.hover() +await handle.click() +``` + +```python sync +handle = page.query_selector("text=Submit") +handle.hover() +handle.click() +``` + +```csharp +var handle = await page.QuerySelectorAsync("text=Submit"); +await handle.HoverAsync(); +await handle.ClickAsync(); +``` + +With the locator, every time the locator is used, up-to-date DOM element is located in the page using the selector. So in the snippet below, underlying DOM element is going to be located twice. + +```js +const locator = page.locator('text=Submit'); +// ... +await locator.hover(); +await locator.click(); +``` + +```java +Locator locator = page.locator("text=Submit"); +locator.hover(); +locator.click(); +``` + +```python async +locator = page.locator("text=Submit") +await locator.hover() +await locator.click() +``` + +```python sync +locator = page.locator("text=Submit") +locator.hover() +locator.click() +``` + +```csharp +var locator = page.Locator("text=Submit"); +await locator.HoverAsync(); +await locator.ClickAsync(); +``` diff --git a/docs/src/selectors.md b/docs/src/selectors.md index f7baba8b69eca..04d53dfe44e30 100644 --- a/docs/src/selectors.md +++ b/docs/src/selectors.md @@ -1,11 +1,9 @@ --- id: selectors -title: "Element selectors" +title: "Selectors" --- -Selectors are strings that point to the elements in the page. They are used to perform actions on those -elements by means of methods such as [`method: Page.click`], [`method: Page.fill`] and alike. All those -methods accept [`param: selector`] as their first argument. +Selectors are strings that are used to create [Locator]s. Locators are used to perform actions on the elements by means of methods such as [`method: Locator.click`], [`method: Locator.fill`] and alike. @@ -13,204 +11,204 @@ methods accept [`param: selector`] as their first argument. - Text selector ```js - await page.click('text=Log in'); + await page.locator('text=Log in').click(); ``` ```java - page.click("text=Log in"); + page.locator("text=Log in").click(); ``` ```python async - await page.click("text=Log in") + await page.locator("text=Log in").click() ``` ```python sync - page.click("text=Log in") + page.locator("text=Log in").click() ``` ```csharp - await page.ClickAsync("text=Log in"); + await page.Locator("text=Log in").ClickAsync(); ``` Learn more about [text selector][text]. - CSS selector ```js - await page.click('button'); - await page.click('#nav-bar .contact-us-item'); + await page.locator('button').click(); + await page.locator('#nav-bar .contact-us-item').click(); ``` ```java - page.click("button"); - page.click("#nav-bar .contact-us-item"); + page.locator("button").click(); + page.locator("#nav-bar .contact-us-item").click(); ``` ```python async - await page.click("button") - await page.click("#nav-bar .contact-us-item") + await page.locator("button").click() + await page.locator("#nav-bar .contact-us-item").click() ``` ```python sync - page.click("button") - page.click("#nav-bar .contact-us-item") + page.locator("button").click() + page.locator("#nav-bar .contact-us-item").click() ``` ```csharp - await page.ClickAsync("button"); - await page.ClickAsync("#nav-bar .contact-us-item"); + await page.Locator("button").ClickAsync(); + await page.Locator("#nav-bar .contact-us-item").ClickAsync(); ``` Learn more about [css selector][css]. - Select by attribute, with css selector ```js - await page.click('[data-test=login-button]'); - await page.click('[aria-label="Sign in"]'); + await page.locator('[data-test=login-button]').click(); + await page.locator('[aria-label="Sign in"]').click(); ``` ```java - page.click("[data-test=login-button]"); - page.click("[aria-label='Sign in']"); + page.locator("[data-test=login-button]").click(); + page.locator("[aria-label='Sign in']").click(); ``` ```python async - await page.click("[data-test=login-button]") - await page.click("[aria-label='Sign in']") + await page.locator("[data-test=login-button]").click() + await page.locator("[aria-label='Sign in']").click() ``` ```python sync - page.click("[data-test=login-button]") - page.click("[aria-label='Sign in']") + page.locator("[data-test=login-button]").click() + page.locator("[aria-label='Sign in']").click() ``` ```csharp - await page.ClickAsync("[data-test=login-button]"); - await page.ClickAsync("[aria-label='Sign in']"); + await page.Locator("[data-test=login-button]").ClickAsync(); + await page.Locator("[aria-label='Sign in']").ClickAsync(); ``` Learn more about [css selector][css]. - Combine css and text selectors ```js - await page.click('article:has-text("Playwright")'); - await page.click('#nav-bar >> text=Contact Us'); + await page.locator('article:has-text("Playwright")').click(); + await page.locator('#nav-bar >> text=Contact Us').click(); ``` ```java - page.click("article:has-text(\"Playwright\")"); - page.click("#nav-bar :text(\"Contact us\")"); + page.locator("article:has-text(\"Playwright\")").click(); + page.locator("#nav-bar :text(\"Contact us\")").click(); ``` ```python async - await page.click("article:has-text('Playwright')") - await page.click("#nav-bar :text('Contact us')") + await page.locator("article:has-text('Playwright')").click() + await page.locator("#nav-bar :text('Contact us')").click() ``` ```python sync - page.click("article:has-text('Playwright')") - page.click("#nav-bar :text('Contact us')") + page.locator("article:has-text('Playwright')").click() + page.locator("#nav-bar :text('Contact us')").click() ``` ```csharp - await page.ClickAsync("article:has-text(\"Playwright\")"); - await page.ClickAsync("#nav-bar :text(\"Contact us\")"); + await page.Locator("article:has-text(\"Playwright\")").ClickAsync(); + await page.Locator("#nav-bar :text(\"Contact us\")").ClickAsync(); ``` Learn more about [`:has-text()` and `:text()` pseudo classes][text]. - Element that contains another, with css selector ```js - await page.click('.item-description:has(.item-promo-banner)'); + await page.locator('.item-description:has(.item-promo-banner)').click(); ``` ```java - page.click(".item-description:has(.item-promo-banner)"); + page.locator(".item-description:has(.item-promo-banner)").click(); ``` ```python async - await page.click(".item-description:has(.item-promo-banner)") + await page.locator(".item-description:has(.item-promo-banner)").click() ``` ```python sync - page.click(".item-description:has(.item-promo-banner)") + page.locator(".item-description:has(.item-promo-banner)").click() ``` ```csharp - await page.ClickAsync(".item-description:has(.item-promo-banner)"); + await page.Locator(".item-description:has(.item-promo-banner)").ClickAsync(); ``` Learn more about [`:has()` pseudo class](#selecting-elements-that-contain-other-elements). - Selecting based on layout, with css selector ```js - await page.click('input:right-of(:text("Username"))'); + await page.locator('input:right-of(:text("Username"))').click(); ``` ```java - page.click("input:right-of(:text(\"Username\"))"); + page.locator("input:right-of(:text(\"Username\"))").click(); ``` ```python async - await page.click("input:right-of(:text('Username'))") + await page.locator("input:right-of(:text('Username'))").click() ``` ```python sync - page.click("input:right-of(:text('Username'))") + page.locator("input:right-of(:text('Username'))").click() ``` ```csharp - await page.ClickAsync("input:right-of(:text(\"Username\"))"); + await page.Locator("input:right-of(:text(\"Username\"))").ClickAsync(); ``` Learn more about [layout selectors](#selecting-elements-based-on-layout). - Only visible elements, with css selector ```js - await page.click('.login-button:visible'); + await page.locator('.login-button:visible').click(); ``` ```java - page.click(".login-button:visible"); + page.locator(".login-button:visible").click(); ``` ```python async - await page.click(".login-button:visible") + await page.locator(".login-button:visible").click() ``` ```python sync - page.click(".login-button:visible") + page.locator(".login-button:visible").click() ``` ```csharp - await page.ClickAsync(".login-button:visible"); + await page.Locator(".login-button:visible").ClickAsync(); ``` Learn more about [selecting visible elements](#selecting-visible-elements). - Pick n-th match ```js - await page.click(':nth-match(:text("Buy"), 3)'); + await page.locator(':nth-match(:text("Buy"), 3)').click(); ``` ```java - page.click(":nth-match(:text('Buy'), 3)"); + page.locator(":nth-match(:text('Buy'), 3)").click(); ``` ```python async - await page.click(":nth-match(:text('Buy'), 3)") + await page.locator(":nth-match(:text('Buy'), 3)").click() ``` ```python sync - page.click(":nth-match(:text('Buy'), 3)") + page.locator(":nth-match(:text('Buy'), 3)").click() ``` ```csharp - await page.ClickAsync(":nth-match(:text('Buy'), 3)"); + await page.Locator(":nth-match(:text('Buy'), 3)").ClickAsync(); ``` Learn more about [`:nth-match()` pseudo-class](#pick-n-th-match-from-the-query-result). - XPath selector ```js - await page.click('xpath=//button'); + await page.locator('xpath=//button').click(); ``` ```java - page.click("xpath=//button"); + page.locator("xpath=//button").click(); ``` ```python async - await page.click("xpath=//button") + await page.locator("xpath=//button").click() ``` ```python sync - page.click("xpath=//button") + page.locator("xpath=//button").click() ``` ```csharp - await page.ClickAsync("xpath=//button"); + await page.Locator("xpath=//button").ClickAsync(); ``` Learn more about [XPath selector][xpath]. - React selector (experimental) ```js - await page.click('_react=ListItem[text *= "milk" i]'); + await page.locator('_react=ListItem[text *= "milk" i]').click(); ``` ```java - page.click("_react=ListItem[text *= 'milk' i]"); + page.locator("_react=ListItem[text *= 'milk' i]").click(); ``` ```python async - await page.click("_react=ListItem[text *= 'milk' i]") + await page.locator("_react=ListItem[text *= 'milk' i]").click() ``` ```python sync - page.click("_react=ListItem[text *= 'milk' i]") + page.locator("_react=ListItem[text *= 'milk' i]").click() ``` ```csharp - await page.ClickAsync("_react=ListItem[text *= 'milk' i]"); + await page.Locator("_react=ListItem[text *= 'milk' i]").ClickAsync(); ``` Learn more about [React selectors][react]. - Vue selector (experimental) ```js - await page.click('_vue=list-item[text *= "milk" i]'); + await page.locator('_vue=list-item[text *= "milk" i]').click(); ``` ```java - page.click("_vue=list-item[text *= 'milk' i]"); + page.locator("_vue=list-item[text *= 'milk' i]").click(); ``` ```python async - await page.click("_vue=list-item[text *= "milk" i]") + await page.locator("_vue=list-item[text *= "milk" i]").click() ``` ```python sync - page.click("_vue=list-item[text *= 'milk' i]") + page.locator("_vue=list-item[text *= 'milk' i]").click() ``` ```csharp - await page.ClickAsync("_vue=list-item[text *= 'milk' i]"); + await page.Locator("_vue=list-item[text *= 'milk' i]").ClickAsync(); ``` Learn more about [Vue selectors][vue]. @@ -221,19 +219,19 @@ methods accept [`param: selector`] as their first argument. Text selector locates elements that contain passed text. ```js -await page.click('text=Log in'); +await page.locator('text=Log in').click(); ``` ```java -page.click("text=Log in"); +page.locator("text=Log in").click(); ``` ```python async -await page.click("text=Log in") +await page.locator("text=Log in").click() ``` ```python sync -page.click("text=Log in") +page.locator("text=Log in").click() ``` ```csharp -await page.ClickAsync("text=Log in"); +await page.Locator("text=Log in").ClickAsync(); ``` Text selector has a few variations: @@ -241,19 +239,19 @@ Text selector has a few variations: - `text=Log in` - default matching is case-insensitive and searches for a substring. For example, `text=Log` matches ``. ```js - await page.click('text=Log in'); + await page.locator('text=Log in').click(); ``` ```java - page.click("text=Log in"); + page.locator("text=Log in").click(); ``` ```python async - await page.click("text=Log in") + await page.locator("text=Log in").click() ``` ```python sync - page.click("text=Log in") + page.locator("text=Log in").click() ``` ```csharp - await page.ClickAsync("text=Log in"); + await page.Locator("text=Log in").ClickAsync(); ``` - `text="Log in"` - text body can be escaped with single or double quotes to search for a text node with exact content. For example, `text="Log"` does not match `` because ``, because `` and ``. ```js - await page.click('text=/Log\\s*in/i'); + await page.locator('text=/Log\\s*in/i').click(); ``` ```java - page.click("text=/Log\\s*in/i"); + page.locator("text=/Log\\s*in/i").click(); ``` ```python async - await page.click("text=/Log\s*in/i") + await page.locator("text=/Log\s*in/i").click() ``` ```python sync - page.click("text=/Log\s*in/i") + page.locator("text=/Log\s*in/i").click() ``` ```csharp - await page.ClickAsync("text=/Log\\s*in/i"); + await page.Locator("text=/Log\\s*in/i").ClickAsync(); ``` - `article:has-text("Playwright")` - the `:has-text()` pseudo-class can be used inside a [css] selector. It matches any element containing specified text somewhere inside, possibly in a child or a descendant element. For example, `article:has-text("Playwright")` matches `
Playwright
`. @@ -317,54 +315,54 @@ Text selector has a few variations: Note that `:has-text()` should be used together with other `css` specifiers, otherwise it will match all the elements containing specified text, including the ``. ```js // Wrong, will match many elements including - await page.click(':has-text("Playwright")'); + await page.locator(':has-text("Playwright")').click(); // Correct, only matches the
element - await page.click('article:has-text("Playwright")'); + await page.locator('article:has-text("Playwright")').click(); ``` ```java // Wrong, will match many elements including - page.click(":has-text(\"Playwright\")"); + page.locator(":has-text(\"Playwright\")").click(); // Correct, only matches the
element - page.click("article:has-text(\"Playwright\")"); + page.locator("article:has-text(\"Playwright\")").click(); ``` ```python async # Wrong, will match many elements including - await page.click(':has-text("Playwright")') + await page.locator(':has-text("Playwright")').click() # Correct, only matches the
element - await page.click('article:has-text("Playwright")') + await page.locator('article:has-text("Playwright")').click() ``` ```python sync # Wrong, will match many elements including - page.click(':has-text("Playwright")') + page.locator(':has-text("Playwright")').click() # Correct, only matches the
element - page.click('article:has-text("All products")') + page.locator('article:has-text("All products")').click() ``` ```csharp // Wrong, will match many elements including - await page.ClickAsync(":has-text(\"Playwright\")"); + await page.Locator(":has-text(\"Playwright\")").ClickAsync(); // Correct, only matches the
element - await page.ClickAsync("article:has-text(\"Playwright\")"); + await page.Locator("article:has-text(\"Playwright\")").ClickAsync(); ``` - `#nav-bar :text("Home")` - the `:text()` pseudo-class can be used inside a [css] selector. It matches the smallest element containing specified text. This example is equivalent to `text=Home`, but inside the `#nav-bar` element. ```js - await page.click('#nav-bar :text("Home")'); + await page.locator('#nav-bar :text("Home")').click(); ``` ```java - page.click("#nav-bar :text('Home')"); + page.locator("#nav-bar :text('Home')").click(); ``` ```python async - await page.click("#nav-bar :text('Home')") + await page.locator("#nav-bar :text('Home')").click() ``` ```python sync - page.click("#nav-bar :text('Home')") + page.locator("#nav-bar :text('Home')").click() ``` ```csharp - await page.ClickAsync("#nav-bar :text('Home')"); + await page.Locator("#nav-bar :text('Home')").ClickAsync(); ``` - `#nav-bar :text-is("Home")` - the `:text-is()` pseudo-class can be used inside a [css] selector, for strict text node match. This example is equivalent to `text="Home"` (note quotes), but inside the `#nav-bar` element. @@ -386,23 +384,23 @@ Playwright augments standard CSS selectors in two ways: * Playwright adds custom pseudo-classes like `:visible`, `:text` and more. ```js -await page.click('button'); +await page.locator('button').click(); ``` ```java -page.click("button"); +page.locator("button").click(); ``` ```python async -await page.click("button") +await page.locator("button").click() ``` ```python sync -page.click("button") +page.locator("button").click() ``` ```csharp -await page.ClickAsync("button"); +await page.Locator("button").ClickAsync(); ``` ## Selecting visible elements @@ -432,46 +430,46 @@ Consider a page with two buttons, first invisible and second visible. * This will find the first button, because it is the first one in DOM order. Then it will wait for the button to become visible before clicking, or timeout while waiting: ```js - await page.click('button'); + await page.locator('button').click(); ``` ```java - page.click("button"); + page.locator("button").click(); ``` ```python async - await page.click("button") + await page.locator("button").click() ``` ```python sync - page.click("button") + page.locator("button").click() ``` ```csharp - await page.ClickAsync("button"); + await page.Locator("button").ClickAsync(); ``` * These will find a second button, because it is visible, and then click it. ```js - await page.click('button:visible'); - await page.click('button >> visible=true'); + await page.locator('button:visible').click(); + await page.locator('button >> visible=true').click(); ``` ```java - page.click("button:visible"); - page.click("button >> visible=true"); + page.locator("button:visible").click(); + page.locator("button >> visible=true").click(); ``` ```python async - await page.click("button:visible") - await page.click("button >> visible=true") + await page.locator("button:visible").click() + await page.locator("button >> visible=true").click() ``` ```python sync - page.click("button:visible") - page.click("button >> visible=true") + page.locator("button:visible").click() + page.locator("button >> visible=true").click() ``` ```csharp - await page.ClickAsync("button:visible"); - await page.ClickAsync("button >> visible=true"); + await page.Locator("button:visible").ClickAsync(); + await page.Locator("button >> visible=true").ClickAsync(); ``` ## Selecting elements that contain other elements @@ -482,23 +480,23 @@ relative to the :scope of the given element match at least one element. Following snippet returns text content of an `
` element that has a `
` inside. ```js -await page.textContent('article:has(div.promo)'); +await page.locator('article:has(div.promo)').textContent(); ``` ```java -page.textContent("article:has(div.promo)"); +page.locator("article:has(div.promo)").textContent(); ``` ```python async -await page.text_content("article:has(div.promo)") +await page.locator("article:has(div.promo)").text_content() ``` ```python sync -page.text_content("article:has(div.promo)") +page.locator("article:has(div.promo)").text_content() ``` ```csharp -await page.TextContentAsync("article:has(div.promo)"); +await page.Locator("article:has(div.promo)").TextContentAsync(); ``` ## Selecting elements matching one of the conditions @@ -510,27 +508,27 @@ one of the selectors in that list. ```js // Clicks a