You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -120,41 +120,123 @@ methods accept [`param: selector`] as their first argument.
120
120
```
121
121
Learn more about [XPath selector][xpath].
122
122
123
-
## Basic text selectors
123
+
## Text selector
124
124
125
-
Text selectors locate elements that contain text nodes with the passed text.
125
+
Text selector locates elements that contain passed text.
126
126
127
127
```js
128
128
await page.click('text=Log in');
129
129
```
130
-
131
130
```python async
132
131
await page.click("text=Log in")
133
132
```
134
-
135
133
```python sync
136
134
page.click("text=Log in")
137
135
```
138
136
139
-
Matching is case-insensitive and searches for a substring. This means `text=Login` matches `<button>Button loGIN (click me)</button>`. Matching also normalizes whitespace, for example it turns multiple spaces into one, turns line breaks into spaces and ignores leading and trailing whitespace.
137
+
Text selector has a few variations:
140
138
141
-
Text body can be escaped with single or double quotes for full-string case-sensitive match instead. This means `text="Login"` will match `<button>Login</button>`, but not`<button>Login (click me)</button>`or`<button>login</button>`. Quoted text follows the usual escaping
142
-
rules, e.g. use `\"` to escape double quote in a double-quoted string: `text="foo\"bar"`. Note that quoted match still normalizes whitespace.
139
+
-`text=Log in`- default matching is case-insensitive and searches for a substring. For example `text=Log` matches `<button>Log in</button>`.
143
140
144
-
Text body can also be a JavaScript-like regex wrapped in`/` symbols. This means `text=/^\\s*Login$/i`
145
-
will match `<button> loGIN</button>` withany number of spaces before "Login"and no spaces after.
141
+
```js
142
+
await page.click('text=Log in');
143
+
```
144
+
```python async
145
+
await page.click("text=Log in")
146
+
```
147
+
```python sync
148
+
page.click("text=Log in")
149
+
```
146
150
147
-
Input elements of the type`button`and`submit` are rendered with their value as text, and text
148
-
engine finds them. For example, `text=Login` matches `<inputtype=button value="Login">`.
151
+
-`text="Log in"`- text body can be escaped with single or double quotes for full-string case-sensitive match. For example `text="Log"` does not match `<button>Log in</button>` but instead matches `<span>Log</span>`.
149
152
150
-
Selector string starting and ending with a quote (either `"` or `'`) is assumed to be a text selector.
151
-
For example, Playwright converts `'"Login"'` to `'text="Login"'` internally.
153
+
Quoted body follows the usual escaping rules, e.g. use `\"` to escape double quote in a double-quoted string: `text="foo\"bar"`.
152
154
153
-
## Basic CSS selectors
155
+
```js
156
+
await page.click('text="Log in"');
157
+
```
158
+
```python async
159
+
await page.click("text='Log in'")
160
+
```
161
+
```python sync
162
+
page.click("text='Log in'")
163
+
```
164
+
165
+
-`"Log in"`- selector starting and ending with a quote (either `"` or `'`) is assumed to be a text selector. For example, `"Log in"` is converted to `text="Log in"` internally.
166
+
167
+
```js
168
+
await page.click('"Log in"');
169
+
```
170
+
```python async
171
+
await page.click("'Log in'")
172
+
```
173
+
```python sync
174
+
page.click("'Log in'")
175
+
```
176
+
177
+
-`/Log\s*in/i` - body can be a [JavaScript-like regex](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) wrapped in `/` symbols. For example, `text=/Log\s*in/i` matches `<button>Login</button>` and `<button>log IN</button>`.
178
+
179
+
```js
180
+
await page.click('text=/Log\\s*in/i');
181
+
```
182
+
```python async
183
+
await page.click("text=/Log\s*in/i")
184
+
```
185
+
```python sync
186
+
page.click("text=/Log\s*in/i")
187
+
```
188
+
189
+
-`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 `<article><div>Playwright</div></article>`.
190
+
191
+
Note that `:has-text()` should be used together with other `css` specifiers, otherwise it will match all the elements containing specified text, including the `<body>`.
192
+
```js
193
+
// Wrong, will match many elements including <body>
# Wrong, will match many elements including <body>
206
+
page.click(':has-text("Playwright")')
207
+
# Correct, only matches the <article> element
208
+
page.click('article:has-text("All products")')
209
+
```
210
+
211
+
-`#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.
212
+
213
+
```js
214
+
await page.click('#nav-bar :text("Home")');
215
+
```
216
+
```python async
217
+
await page.click("#nav-bar :text('Home')")
218
+
```
219
+
```python sync
220
+
page.click("#nav-bar :text('Home')")
221
+
```
222
+
223
+
-`#nav-bar :text-is("Home")` - the `:text-is()` pseudo-class can be used inside a [css] selector, for case-sensitive match. This example is equivalent to `text="Home"` (note quotes), but inside the `#nav-bar` element.
224
+
225
+
*`#nav-bar :text-matches("reg?ex", "i")` - the `:text-matches()` pseudo-class can be used inside a [css] selector, for regex-based match. This example is equivalent to `text=/reg?ex/i`, but inside the `#nav-bar` element.
226
+
227
+
:::note
228
+
Matching always normalizes whitespace, for example it turns multiple spaces into one, turns line breaks into spaces and ignores leading and trailing whitespace.
229
+
:::
230
+
231
+
:::note
232
+
Input elements of the type`button`and`submit` are matched by their `value` instead of text content. For example, `text=Log in` matches `<inputtype=button value="Log in">`.
233
+
:::
234
+
235
+
## CSS selector
154
236
155
237
Playwright augments standard CSS selectors in two ways:
156
238
*`css` engine pierces open shadow DOM by default.
157
-
* Playwright adds a few custom pseudo-classes like `:visible`.
239
+
* Playwright adds custom pseudo-classes like `:visible`, `:text`and more.
The `:has-text` pseudo-class matches elements that have specific text somewhere inside, possibly in a child or a descendant element. It is approximately equivalent to `element.textContent.includes(textToSearchFor)`.
264
-
265
-
The `:text` pseudo-class matches elements that have a text node child with specific text. It is similar to the [text] engine.
266
-
267
-
`:has-text`and`:text` should be used differently. Consider the following page:
268
-
```html
269
-
<div class=nav-item>Home</div>
270
-
<div class=nav-item>
271
-
<span class=bold>New</span> products
272
-
</div>
273
-
<div class=nav-item>
274
-
<span class=bold>All</span> products
275
-
</div>
276
-
<div class=nav-item>Contact us</div>
277
-
```
278
-
279
-
Use `:has-text()` to click a navigation item that contains text "All products".
`:has-text()` will match even though "All products" text is split between multiple elements. However, it will also match any parent element of this navigation item, including `<body>`and`<html>`, because each of them contains "All products" somewhere inside. Therefore, `:has-text()` must be used together with other `css` specifiers, like a tag name or a class name.
290
-
```js
291
-
// Wrong, will match many elements including <body>
# Wrong, will match many elements including <body>
304
-
page.click(':has-text("All products")')
305
-
# Correct, only matches the navigation item
306
-
page.click('.nav-item:has-text("All products")')
307
-
```
308
-
309
-
Use `:text()` to click an element that directly contains text "Home".
310
-
```js
311
-
await page.click(':text("Home")');
312
-
```
313
-
```python async
314
-
await page.click(':text("Home")')
315
-
```
316
-
```python sync
317
-
page.click(':text("Home")')
318
-
```
319
-
`:text()` only matches the element that contains the text directly inside, but notany parent elements. It is suitable to use without other `css` specifiers. However, it does not match text across elements. For example, `:text("All products")` will not match anything, because "All"and"products" belong to the different elements.
320
-
321
-
:::note
322
-
Both `:has-text()`and`:text()` perform case-insensitive match. They also normalize whitespace, for example turn multiple spaces into one, turn line breaks into spaces and ignore leading and trailing whitespace.
323
-
:::
324
-
325
-
There are a few `:text()` variations that support different arguments:
326
-
*`:text("substring")`- Matches when a text node inside the element contains "substring". Matching is case-insensitive and normalizes whitespace.
327
-
*`:text-is("string")`- Matches when all text nodes inside the element combined have the text value equal to "string". Matching is case-insensitive and normalizes whitespace.
328
-
*`:text-matches("[+-]?\\d+")`- Matches text nodes against a regular expression. Note that special characters like back-slash `\`, quotes `"`, square brackets `[]` and more should be escaped. Learn more about [regular expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp).
329
-
* `:text-matches("value", "i")` - Matches text nodes against a regular expression with specified flags.
330
-
331
343
## Selecting elements in Shadow DOM
332
344
333
345
Our `css`and`text` engines pierce the [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM) by default:
334
-
- First it searchesfor the elements in the light DOMin the iteration order, and
335
-
- Then it searches recursively inside open shadow roots in the iteration order.
346
+
- First they searchfor the elements in the light DOMin the iteration order, and
347
+
- Then they search recursively inside open shadow roots in the iteration order.
336
348
337
-
In particular, in`css`engines, any [Descendant combinator](https://developer.mozilla.org/en-US/docs/Web/CSS/Descendant_combinator)
349
+
In particular, in`css`engine, any [Descendant combinator](https://developer.mozilla.org/en-US/docs/Web/CSS/Descendant_combinator)
338
350
or [Child combinator](https://developer.mozilla.org/en-US/docs/Web/CSS/Child_combinator) pierces an
339
351
arbitrary number of open shadow roots, including the implicit descendant combinator at the start of the
340
352
selector. It does not search inside closed shadow roots or iframes.
0 commit comments