选择器
Selector 是用于创建 Locator 的字符串。Locator 用于通过诸如 locator.click(**kwargs)、locator.fill(value, **kwargs) 等方法对元素执行操作。有关调试 selector 的信息,请参阅 此处。
编写好的 selector 既是一门艺术,也是一门科学,因此请务必查看 最佳实践 部分。
快速指南
文本选择器
- Sync
- Async
page.locator("text=Log in").click()await page.locator("text=Log in").click()了解更多关于 文本选择器 的信息。
CSS 选择器
- Sync
- Async
page.locator("button").click()
page.locator("#nav-bar .contact-us-item").click()await page.locator("button").click()
await page.locator("#nav-bar .contact-us-item").click()了解更多关于 css 选择器 的信息。
通过属性选择,使用 css 选择器
- Sync
- Async
page.locator("[data-test=login-button]").click()
page.locator("[aria-label='Sign in']").click()await page.locator("[data-test=login-button]").click()
await page.locator("[aria-label='Sign in']").click()了解更多关于 css 选择器 的信息。
组合 css 和文本选择器
- Sync
- Async
page.locator("article:has-text('Playwright')").click()
page.locator("#nav-bar :text('Contact us')").click()await page.locator("article:has-text('Playwright')").click()
await page.locator("#nav-bar :text('Contact us')").click()了解更多关于
:has-text()和:text()伪类 的信息。包含另一个元素的元素,使用 css 选择器
- Sync
- Async
page.locator(".item-description:has(.item-promo-banner)").click()await page.locator(".item-description:has(.item-promo-banner)").click()了解更多关于
:has()伪类 的信息。基于布局选择,使用 css 选择器
- Sync
- Async
page.locator("input:right-of(:text('Username'))").click()await page.locator("input:right-of(:text('Username'))").click()了解更多关于 布局选择器 的信息。
仅可见元素,使用 css 选择器
- Sync
- Async
page.locator(".login-button:visible").click()await page.locator(".login-button:visible").click()了解更多关于 选择可见元素 的信息。
选择第 n 个匹配项
- Sync
- Async
page.locator(":nth-match(:text('Buy'), 3)").click()await page.locator(":nth-match(:text('Buy'), 3)").click()了解更多关于
:nth-match()伪类 的信息。XPath 选择器
- Sync
- Async
page.locator("xpath=//button").click()await page.locator("xpath=//button").click()了解更多关于 XPath 选择器 的信息。
React 选择器 (实验性)
- Sync
- Async
page.locator("_react=ListItem[text *= 'milk' i]").click()await page.locator("_react=ListItem[text *= 'milk' i]").click()了解更多关于 React 选择器 的信息。
Vue 选择器 (实验性)
- Sync
- Async
page.locator("_vue=list-item[text *= 'milk' i]").click()await page.locator("_vue=list-item[text *= 'milk' i]").click()了解更多关于 Vue 选择器 的信息。
文本选择器
文本选择器定位包含传递文本的元素。
- Sync
- Async
page.locator("text=Log in").click()
await page.locator("text=Log in").click()
文本选择器有几种变体:
text=Log in- 默认匹配不区分大小写,修剪空格并搜索子字符串。例如,text=Log匹配<button>Log in</button>。- Sync
- Async
page.locator("text=Log in").click()await page.locator("text=Log in").click()text="Log in"- 文本主体可以用单引号或双引号转义,以搜索修剪空格后具有确切内容的文本节点。例如,text="Log"不匹配<button>Log in</button>,因为<button>包含一个不等于"Log"的单个文本节点"Log in"。但是,text="Log"匹配<button> Log <span>in</span></button>,因为<button>包含一个文本节点" Log "。这种精确模式意味着区分大小写的匹配,因此text="Download"将不匹配<button>download</button>。引用的主体遵循通常的转义规则,例如使用
\"在双引号字符串中转义双引号:text="foo\"bar"。- Sync
- Async
page.locator("text='Log in'").click()await page.locator("text='Log in'").click()"Log in"- 以引号("或')开头和结尾的选择器被假定为文本选择器。例如,"Log in"在内部转换为text="Log in"。- Sync
- Async
page.locator("'Log in'").click()await page.locator("'Log in'").click()/Log\s*in/i- 主体可以是包裹在/符号中的 类 JavaScript 正则表达式。例如,text=/Log\s*in/i匹配<button>Login</button>和<button>log IN</button>。- Sync
- Async
page.locator("text=/Log\s*in/i").click()await page.locator("text=/Log\s*in/i").click()article:has-text("Playwright")-:has-text()伪类可以在 css 选择器内部使用。它匹配内部某处包含指定文本的任何元素,可能在子元素或后代元素中。匹配不区分大小写,修剪空格并搜索子字符串。例如,article:has-text("Playwright")匹配<article><div>Playwright</div></article>。请注意,
:has-text()应与其他css说明符一起使用,否则它将匹配包含指定文本的所有元素,包括<body>。- Sync
- Async
# Wrong, will match many elements including <body>
page.locator(':has-text("Playwright")').click()
# Correct, only matches the <article> element
page.locator('article:has-text("All products")').click()# Wrong, will match many elements including <body>
await page.locator(':has-text("Playwright")').click()
# Correct, only matches the <article> element
await page.locator('article:has-text("Playwright")').click()#nav-bar :text("Home")-:text()伪类可以在 css 选择器内部使用。它匹配包含指定文本的最小元素。此示例等效于text=Home,但在#nav-bar元素内部。- Sync
- Async
page.locator("#nav-bar :text('Home')").click()await page.locator("#nav-bar :text('Home')").click()#nav-bar :text-is("Home")-:text-is()伪类可以在 css 选择器内部使用,用于严格的文本节点匹配。此示例等效于text="Home"(注意引号),但在#nav-bar元素内部。
#nav-bar :text-matches("reg?ex", "i")-:text-matches()伪类可以在 css 选择器内部使用,用于基于正则表达式的匹配。此示例等效于text=/reg?ex/i,但在#nav-bar元素内部。
匹配总是规范化空格。例如,它将多个空格转换为一个,将换行符转换为空格,并忽略前导和尾随空格。
类型为 button 和 submit 的输入元素通过其 value 而不是文本内容进行匹配。例如,text=Log in 匹配 <input type=button value="Log in">。
CSS 选择器
Playwright 以两种方式增强了标准 CSS 选择器:
css引擎默认穿透 shadow DOM。- Playwright 添加了自定义伪类,如
:visible、:text等。
- Sync
- Async
page.locator("button").click()
await page.locator("button").click()
选择可见元素
在 Playwright 中有两种方法仅选择 可见 元素:
- CSS 选择器中的
:visible伪类 visible=选择器引擎
如果您希望您的选择器是 CSS 并且不想依赖 链式选择器,请像这样使用 :visible 伪类:input:visible。如果您更喜欢组合选择器引擎,请使用 input >> visible=true。后者允许您将 text=、xpath= 和其他选择器引擎与可见性过滤器结合使用。
例如,input 匹配页面上的所有输入,而 input:visible 和 input >> visible=true 仅匹配可见输入。这对于区分非常相似但在可见性方面不同的元素很有用。
通常最好遵循 最佳实践 并找到更可靠的方法来唯一标识元素。
考虑一个带有两个按钮的页面,第一个不可见,第二个可见。
<button style='display: none'>Invisible</button>
<button>Visible</button>
这将找到第一个按钮,因为它是 DOM 顺序中的第一个元素。然后它将等待按钮变为可见再单击,或者在等待时超时:
- Sync
- Async
page.locator("button").click()await page.locator("button").click()这些将找到第二个按钮,因为它是可见的,然后单击它。
- Sync
- Async
page.locator("button:visible").click()
page.locator("button >> visible=true").click()await page.locator("button:visible").click()
await page.locator("button >> visible=true").click()
选择包含其他元素的元素
按文本过滤
Locator 支持一个选项,仅选择内部某处(可能在后代元素中)具有某些文本的元素。匹配不区分大小写并搜索子字符串。
- Sync
- Async
page.locator("button", has_text="Click me").click()
await page.locator("button", has_text="Click me").click()
您也可以传递正则表达式。
按另一个 locator 过滤
Locator 支持一个选项,仅选择具有匹配另一个 locator 的后代的元素。
- Sync
- Async
page.locator("article", has=page.locator("button.subscribe"))
page.locator("article", has=page.locator("button.subscribe"))
请注意,内部 locator 是从外部 locator 开始匹配的,而不是从文档根目录开始。
在 CSS 选择器内部
:has() 伪类是一个 实验性 CSS 伪类。如果作为参数传递的任何选择器相对于给定元素的 :scope 匹配至少一个元素,则返回该元素。
以下代码段返回内部具有 <div class=promo> 的 <article> 元素的文本内容。
- Sync
- Async
page.locator("article:has(div.promo)").text_content()
await page.locator("article:has(div.promo)").text_content()
增强现有的 locators
您可以通过将 :scope 选择器传递给 locator.locator(selector, **kwargs) 并指定所需的选项来向任何 locator 添加过滤。例如,给定选择表中某些行的 locator row,您可以过滤为仅包含文本 "Hello" 的那些行。
- Sync
- Async
row = page.locator(".row")
# ... later on ...
row.locator(":scope", has_text="Hello").click()
row = page.locator(".row")
# ... later on ...
await row.locator(":scope", has_text="Hello").click()
选择匹配条件之一的元素
CSS 选择器列表
逗号分隔的 CSS 选择器列表将匹配可以由该列表中选择器之一选择的所有元素。
- Sync
- Async
# Clicks a <button> that has either a "Log in" or "Sign in" text.
page.locator('button:has-text("Log in"), button:has-text("Sign in")').click()
# Clicks a <button> that has either a "Log in" or "Sign in" text.
await page.locator('button:has-text("Log in"), button:has-text("Sign in")').click()
:is() 伪类是一个 实验性 CSS 伪类,对于指定元素上的额外条件列表可能很有用。
XPath 联合
管道运算符 (|) 可用于在 XPath 中指定多个选择器。它将匹配可以由该列表中选择器之一选择的所有元素。
- Sync
- Async
# Waits for either confirmation dialog or load spinner.
page.locator("//span[contains(@class, 'spinner__loading')]|//div[@id='confirmation']").wait_for()
# Waits for either confirmation dialog or load spinner.
await page.locator("//span[contains(@class, 'spinner__loading')]|//div[@id='confirmation']").wait_for()
在 Shadow DOM 中选择元素
Playwright 的 css 和 text 引擎默认穿透 Shadow DOM:
- 首先,它们按迭代顺序在 light DOM 中搜索元素,并且
- 然后,它们按迭代顺序在打开的 shadow roots 内部递归搜索。
特别是,在 css 引擎中,任何 后代组合器 或 子组合器 都会穿透任意数量的打开 shadow roots,包括选择器开头的隐式后代组合器。它不会在关闭的 shadow roots 或 iframes 内部搜索。
如果您想退出此行为,可以使用 :light CSS 扩展或 text:light 选择器引擎。它们不穿透 shadow roots。
- Sync
- Async
page.locator(":light(.article > .header)").click()
await page.locator(":light(.article > .header)").click()
更高级的 Shadow DOM 用例:
<article>
<div>In the light dom</div>
<div slot='myslot'>In the light dom, but goes into the shadow slot</div>
#shadow-root
<div class='in-the-shadow'>
<span class='content'>
In the shadow dom
#shadow-root
<li id='target'>Deep in the shadow</li>
</span>
</div>
<slot name='myslot'></slot>
</article>
"article div"和":light(article div)"都匹配第一个<div>In the light dom</div>。"article > div"和":light(article > div)"都匹配作为article直接子元素的两个div元素。"article .in-the-shadow"匹配<div class='in-the-shadow'>,穿透 shadow root,而":light(article .in-the-shadow)"不匹配任何内容。":light(article div > span)"不匹配任何内容,因为两个 light-domdiv元素都不包含span。"article div > span"匹配<span class='content'>,穿透 shadow root。"article > .in-the-shadow"不匹配任何内容,因为<div class='in-the-shadow'>不是article的直接子元素。":light(article > .in-the-shadow)"不匹配任何内容。"article li#target"匹配<li id='target'>Deep in the shadow</li>,穿透两个 shadow roots。
基于布局选择元素
有时,当目标元素缺乏明显的特征时,很难为其想出一个好的选择器。在这种情况下,使用 Playwright 布局选择器可能会有所帮助。这些可以与常规 CSS 结合使用以精确定位多个选择之一。
例如,input:right-of(:text("Password")) 匹配位于文本 "Password" 右侧的输入字段 - 当页面有多个难以相互区分的输入时很有用。
请注意,布局选择器通常与其他选择器(如 input)结合使用。如果单独使用布局选择器,如 :right-of(:text("Password")),您很可能得到的不是您正在寻找的输入,而是文本和目标输入之间的一些空元素。
布局选择器取决于页面布局,可能会产生意想不到的结果。例如,当布局改变一个像素时,可能会匹配不同的元素。
布局选择器使用 bounding client rect 来计算元素的距离和相对位置。
:right-of(inner > selector)- 匹配位于匹配内部选择器的任何元素右侧的元素,处于任何垂直位置。:left-of(inner > selector)- 匹配位于匹配内部选择器的任何元素左侧的元素,处于任何垂直位置。:above(inner > selector)- 匹配位于匹配内部选择器的任何元素上方的元素,处于任何水平位置。:below(inner > selector)- 匹配位于匹配内部选择器的任何元素下方的元素,处于任何水平位置。:near(inner > selector)- 匹配位于匹配内部选择器的任何元素附近(50 CSS 像素内)的元素。
请注意,生成的匹配项按其与锚元素的距离排序,因此您可以使用 locator.first 来选择最近的一个。这仅在您有类似元素列表的情况下有用,其中最近的一个显然是正确的。但是,在其他情况下使用 locator.first 很可能无法按预期工作 - 它不会针对您正在搜索的元素,而是碰巧最近的其他元素,如随机空的 <div>,或者是滚动出且当前不可见的元素。
- Sync
- Async
# Fill an input to the right of "Username".
page.locator("input:right-of(:text(\"Username\"))").fill("value")
# Click a button near the promo card.
page.locator("button:near(.promo-card)").click()
# Click the radio input in the list closest to the "Label 3".
page.locator("[type=radio]:left-of(:text(\"Label 3\"))").first.click()
# Fill an input to the right of "Username".
await page.locator("input:right-of(:text(\"Username\"))").fill("value")
# Click a button near the promo card.
await page.locator("button:near(.promo-card)").click()
# Click the radio input in the list closest to the "Label 3".
await page.locator("[type=radio]:left-of(:text(\"Label 3\"))").first.click()
所有布局选择器都支持可选的最大像素距离作为最后一个参数。例如 button:near(:text("Username"), 120) 匹配距离文本为 "Username" 的元素最多 120 像素的按钮。
通过标签文本选择元素
Playwright 中的目标输入操作会自动区分标签和控件,因此您可以定位标签以对关联的控件执行操作。
例如,考虑以下 DOM 结构:<label for="password">Password:</label><input id="password" type="password">。您可以使用类似 text=Password 的内容定位标签,并对输入执行以下操作:
click将单击标签并自动聚焦输入字段;fill将填充输入字段;inputValue将返回输入字段的值;selectText将选择输入字段中的文本;setInputFiles将为type=file的输入字段设置文件;selectOption将从选择框中选择一个选项。
- Sync
- Async
# Fill the input by targeting the label.
page.locator('text=Password').fill('secret')
# Fill the input by targeting the label.
await page.locator('text=Password').fill('secret')
但是,其他方法将针对标签本身,例如 textContent 将返回标签的文本内容,而不是输入字段。
XPath 选择器
XPath 选择器等效于调用 Document.evaluate。示例:xpath=//html/body。
以 // 或 .. 开头的选择器被假定为 xpath 选择器。例如,Playwright 将 '//html/body' 转换为 'xpath=//html/body'。
xpath 不穿透 shadow roots
第 n 个元素选择器
您可以使用 nth= 选择器将查询范围缩小到第 n 个匹配项。与 CSS 的 nth-match 不同,提供的索引是从 0 开始的。
- Sync
- Async
# Click first button
page.locator("button >> nth=0").click()
# Click last button
page.locator("button >> nth=-1").click()
# Click first button
await page.locator("button >> nth=0").click()
# Click last button
await page.locator("button >> nth=-1").click()
React 选择器
React 选择器是实验性的,前缀为 _。功能可能会在未来发生变化。
React 选择器允许通过组件名称和属性值选择元素。语法与 属性选择器 非常相似,并支持所有属性选择器运算符。
在 react 选择器中,组件名称使用 CamelCase 转录。
选择器示例:
- 按 组件 匹配:
_react=BookItem - 按组件和 确切属性值 匹配,区分大小写:
_react=BookItem[author = "Steven King"] - 仅按属性值匹配,不区分大小写:
_react=[author = "steven king" i] - 按组件和 真值属性值 匹配:
_react=MyButton[enabled] - 按组件和 布尔值 匹配:
_react=MyButton[enabled = false] - 按属性 值子字符串 匹配:
_react=[author *= "King"] - 按组件和 多个属性 匹配:
_react=BookItem[author *= "king" i][year = 1990] - 按 嵌套 属性值匹配:
_react=[some.nested.value = 12] - 按组件和属性值 前缀 匹配:
_react=BookItem[author ^= "Steven"] - 按组件和属性值 后缀 匹配:
_react=BookItem[author $= "Steven"] - 按组件和 key 匹配:
_react=BookItem[key = '2'] - 按属性值 正则表达式 匹配:
_react=[author = /Steven(\\s+King)?/i]
要在树中查找 React 元素名称,请使用 React DevTools。
React 选择器支持 React 15 及更高版本。
React 选择器以及 React DevTools,仅适用于 未压缩 的应用程序构建。
Vue 选择器
Vue 选择器是实验性的,前缀为 _。功能可能会在未来发生变化。
Vue 选择器允许通过组件名称和属性值选择元素。语法与 属性选择器 非常相似,并支持所有属性选择器运算符。
在 Vue 选择器中,组件名称使用 kebab-case 转录。
选择器示例:
- 按 组件 匹配:
_vue=book-item - 按组件和 确切属性值 匹配,区分大小写:
_vue=book-item[author = "Steven King"] - 仅按属性值匹配,不区分大小写:
_vue=[author = "steven king" i] - 按组件和 真值属性值 匹配:
_vue=my-button[enabled] - 按组件和 布尔值 匹配:
_vue=my-button[enabled = false] - 按属性 值子字符串 匹配:
_vue=[author *= "King"] - 按组件和 多个属性 匹配:
_vue=book-item[author *= "king" i][year = 1990] - 按 嵌套 属性值匹配:
_vue=[some.nested.value = 12] - 按组件和属性值 前缀 匹配:
_vue=book-item[author ^= "Steven"] - 按组件和属性值 后缀 匹配:
_vue=book-item[author $= "Steven"] - 按属性值 正则表达式 匹配:
_vue=[author = /Steven(\\s+King)?/i]
要在树中查找 Vue 元素名称,请使用 Vue DevTools。
Vue 选择器支持 Vue2 及更高版本。
Vue 选择器以及 Vue DevTools,仅适用于 未压缩 的应用程序构建。
Role 选择器
Role 选择器允许通过其 ARIA role、ARIA 属性 和 可访问名称 选择元素。请注意,role 选择器 不能替代 可访问性审计和一致性测试,而是提供有关 ARIA 指南的早期反馈。
语法与 CSS 属性选择器 非常相似。例如,role=button[name="Click me"][pressed] 选择具有可访问名称 "Click me" 的按下按钮。
请注意,许多 html 元素具有由 role 选择器识别的隐式 定义角色。您可以在 此处找到所有支持的角色。ARIA 指南 不建议 通过将 role 和/或 aria-* 属性设置为默认值来复制隐式角色和属性。
Role 选择器支持的属性:
checked- 通常由aria-checked或本机<input type=checkbox>控件设置的属性。checked 的可用值为true、false和"mixed"。示例:role=checkbox[checked=true],等效于role=checkbox[checked]role=checkbox[checked=false]role=checkbox[checked="mixed"]
了解更多关于
aria-checked的信息。disabled- 通常由aria-disabled或disabled设置的布尔属性。示例:role=button[disabled=true],等效于role=button[disabled]role=button[disabled=false]
请注意,与大多数其他属性不同,
disabled通过 DOM 层次结构继承。了解更多关于aria-disabled的信息。expanded- 通常由aria-expanded设置的布尔属性。示例:role=button[expanded=true],等效于role=button[expanded]role=button[expanded=false]
了解更多关于
aria-expanded的信息。include-hidden- 控制是否匹配隐藏元素的布尔属性。默认情况下,role 选择器仅匹配 ARIA 定义 的非隐藏元素。使用[include-hidden],匹配隐藏和非隐藏元素。示例:role=button[include-hidden=true],等效于role=button[include-hidden]role=button[include-hidden=false]
了解更多关于
aria-hidden的信息。level- 通常出现在角色heading、listitem、row、treeitem中的数字属性,<h1>-<h6>元素的默认值。示例:role=heading[level=1]
了解更多关于
aria-level的信息。name- 匹配 可访问名称 的字符串属性。支持像=和*=这样的属性运算符,以及正则表达式。role=button[name="Click me"]role=button[name*="Click"]role=button[name=/Click( me)?/]
了解更多关于 可访问名称 的信息。
pressed- 通常由aria-pressed设置的属性。pressed 的可用值为true、false和"mixed"。示例:role=button[pressed=true],等效于role=button[pressed]role=button[pressed=false]role=button[pressed="mixed"]
了解更多关于
aria-pressed的信息。selected- 通常由aria-selected设置的布尔属性。示例:role=option[selected=true],等效于role=option[selected]role=option[selected=false]
了解更多关于
aria-selected的信息。
示例:
role=button匹配所有按钮;role=button[name="Click me"]匹配具有 "Click me" 可访问名称的按钮;role=checkbox[checked][include-hidden]匹配已选中的复选框,包括当前隐藏的复选框。
id, data-testid, data-test-id, data-test 选择器
Playwright 支持使用某些属性选择元素的简写。目前,仅支持以下属性:
iddata-testiddata-test-iddata-test
- Sync
- Async
# Fill an input with the id "username"
page.locator('id=username').fill('value')
# Click an element with data-test-id "submit"
page.locator('data-test-id=submit').click()
# Fill an input with the id "username"
await page.locator('id=username').fill('value')
# Click an element with data-test-id "submit"
await page.locator('data-test-id=submit').click()
属性选择器不是 CSS 选择器,因此不支持任何特定于 CSS 的内容,如 :enabled。要获得更多功能,请使用适当的 css 选择器,例如 css=[data-test="login"]:enabled。
属性选择器穿透 shadow DOM。要退出此行为,请在属性后使用 :light 后缀,例如 page.locator('data-test-id:light=submit').click()
从查询结果中选择第 n 个匹配项
有时页面包含许多相似的元素,很难选择特定的一个。例如:
<section> <button>Buy</button> </section>
<article><div> <button>Buy</button> </div></article>
<div><div> <button>Buy</button> </div></div>
在这种情况下,:nth-match(:text("Buy"), 3) 将选择上面代码段中的第三个按钮。请注意,索引是从 1 开始的。
- Sync
- Async
# Click the third "Buy" button
page.locator(":nth-match(:text('Buy'), 3)").click()
# Click the third "Buy" button
await page.locator(":nth-match(:text('Buy'), 3)").click()
:nth-match() 对于等待指定数量的元素出现也很有用,使用 locator.wait_for(**kwargs)。
- Sync
- Async
# Wait until all three buttons are visible
page.locator(":nth-match(:text('Buy'), 3)").wait_for()
# Wait until all three buttons are visible
await page.locator(":nth-match(:text('Buy'), 3)").wait_for()
与 :nth-child() 不同,元素不必是兄弟元素,它们可以在页面上的任何位置。在上面的代码段中,所有三个按钮都匹配 :text("Buy") 选择器,并且 :nth-match() 选择第三个按钮。
父选择器
可以使用 .. 选择父级,这是 xpath=.. 的缩写形式。
例如:
- Sync
- Async
parent_locator = element_locator.locator('..')
parent_locator = element_locator.locator('..')
链式选择器
定义为 engine=body 或缩写形式的选择器可以与 >> 标记组合,例如 selector1 >> selector2 >> selectors3。当选择器被链接时,下一个选择器是相对于上一个选择器的结果进行查询的。
例如,
css=article >> css=.bar > .baz >> css=span[attr=value]
等效于
document
.querySelector('article')
.querySelector('.bar > .baz')
.querySelector('span[attr=value]')
如果选择器需要在主体中包含 >>,则应在字符串内转义,以免与链式分隔符混淆,例如 text="some >> text"。
中间匹配
默认情况下,链式选择器解析为最后一个选择器查询的元素。选择器可以以 * 为前缀,以捕获中间选择器查询的元素。
例如,css=article >> text=Hello 捕获具有文本 Hello 的元素,而 *css=article >> text=Hello(注意 *)捕获包含具有文本 Hello 的元素的 article 元素。
最佳实践
选择器的选择决定了自动化脚本的弹性。为了减少维护负担,我们建议优先考虑面向用户的属性和显式契约。
优先考虑面向用户的属性
文本内容、输入占位符、可访问性角色和标签等属性是很少更改的面向用户的属性。这些属性不受 DOM 结构更改的影响。
- Sync
- Async
# queries "Login" text selector
page.locator('text="Login"').click()
page.locator('"Login"').click() # short-form
# queries "Search GitHub" placeholder attribute
page.locator('css=[placeholder="Search GitHub"]').fill('query')
page.locator('[placeholder="Search GitHub"]').fill('query') # short-form
# queries "Close" accessibility label
page.locator('css=[aria-label="Close"]').click()
page.locator('[aria-label="Close"]').click() # short-form
# combine role and text queries
page.locator('css=nav >> text=Login').click()
# queries "Login" text selector
await page.locator('text="Login"').click()
await page.locator('"Login"').click() # short-form
# queries "Search GitHub" placeholder attribute
await page.locator('css=[placeholder="Search GitHub"]').fill('query')
await page.locator('[placeholder="Search GitHub"]').fill('query') # short-form
# queries "Close" accessibility label
await page.locator('css=[aria-label="Close"]').click()
await page.locator('[aria-label="Close"]').click() # short-form
# combine role and text queries
await page.locator('css=nav >> text=Login').click()
定义显式契约
当面向用户的属性经常更改时,建议使用显式测试 ID,如 data-test-id。这些 data-* 属性受 css 和 id 选择器 支持。
<button data-test-id="directions">Itinéraire</button>
- Sync
- Async
# queries data-test-id attribute with css
page.locator('css=[data-test-id=directions]').click()
page.locator('[data-test-id=directions]').click() # short-form
# queries data-test-id with id
page.locator('data-test-id=directions').click()
# queries data-test-id attribute with css
await page.locator('css=[data-test-id=directions]').click()
await page.locator('[data-test-id=directions]').click() # short-form
# queries data-test-id with id
await page.locator('data-test-id=directions').click()
避免绑定到实现的选择器
xpath 和 css 可以绑定到 DOM 结构或实现。当 DOM 结构更改时,这些选择器可能会中断。同样,locator.nth(index)、locator.first 和 locator.last 绑定到实现和 DOM 结构,如果 DOM 更改,将针对不正确的元素。
- Sync
- Async
# avoid long css or xpath chains
page.locator('#tsf > div:nth-child(2) > div.A8SBwf > div.RNNXgb > div > div.a4bIc > input').click()
page.locator('//*[@id="tsf"]/div[2]/div[1]/div[1]/div/div[2]/input').click()
# avoid long css or xpath chains
await page.locator('#tsf > div:nth-child(2) > div.A8SBwf > div.RNNXgb > div > div.a4bIc > input').click()
await page.locator('//*[@id="tsf"]/div[2]/div[1]/div[1]/div/div[2]/input').click()