跳至主要内容

其他定位器

简介

note

查看主要的定位器指南了解最常见和推荐的定位器。

除了推荐的定位器如Page.getByRole()Page.getByText()之外,Playwright还支持本指南中描述的各种其他定位器。

CSS定位器

note

我们建议优先使用用户可见的定位器,如文本或可访问角色,而不是使用与实现绑定的CSS,因为页面更改时可能会失效。

Playwright可以通过CSS选择器定位元素。

page.locator("css=button").click();

Playwright通过两种方式增强了标准CSS选择器:

  • CSS选择器可以穿透打开shadow DOM。
  • Playwright 添加了自定义伪类,如 :visible:has-text():has():is():nth-match() 等。

CSS: 按文本匹配

Playwright 包含多个CSS伪类,用于根据元素的文本内容进行匹配。

  • article:has-text("Playwright") - :has-text() 选择器会匹配任何内部包含指定文本的元素,可能是在子元素或后代元素中。匹配时不区分大小写,会去除空格并搜索子字符串。

    例如,article:has-text("Playwright") 会匹配

    Playwright

    请注意 :has-text() 应该与其他CSS选择器一起使用,否则它会匹配所有包含指定文本的元素,包括

    // 错误,会匹配包括在内的许多元素
    page.locator(":has-text(\"Playwright\")").click();
    // 正确,只匹配
    元素

    page.locator("article:has-text(\"Playwright\")").click();
  • #nav-bar :text("Home") - :text()伪类匹配包含指定文本的最小元素。匹配不区分大小写,会修剪空白并搜索子字符串。

    例如,这将在#nav-bar元素内找到包含"Home"文本的元素:

    page.locator("#nav-bar :text('Home')").click();
  • #nav-bar :text-is("Home") - :text-is()伪类会匹配具有完全一致文本的最小元素。精确匹配区分大小写,会修剪空白字符并搜索完整字符串。

    例如,:text-is("Log")不会匹配<button>Log in</button>,因为<button>包含的单个文本节点"Log in"不等于"Log"。但是,:text-is("Log")会匹配<button> Log <span>in</span></button>,因为<button>包含文本节点" Log "

    同理,:text-is("Download")不会匹配<button>download</button>,因为匹配区分大小写。

  • #nav-bar :text-matches("reg?ex", "i") - :text-matches() 伪类会匹配文本内容符合类JavaScript正则表达式的最小元素。

    例如,:text-matches("Log\s*in", "i") 可以匹配 <button>Login</button><button>log IN</button>

note

文本匹配总是会规范化空白字符。例如,它会将多个空格转换为一个,将换行符转换为空格,并忽略开头和结尾的空白字符。

note

类型为buttonsubmit的输入元素是通过它们的value值而非文本内容来匹配的。例如,:text("Log in")可以匹配<input type=button value="Log in">

CSS: 仅匹配可见元素

Playwright在CSS选择器中支持:visible伪类。例如,css=button会匹配页面上的所有按钮,而css=button:visible仅匹配可见按钮。这对于区分外观相似但可见性不同的元素非常有用。

考虑一个页面有两个按钮,第一个不可见而第二个可见。

<button style='display: none'>Invisible</button>
<button>Visible</button>
  • 这将找到两个按钮并抛出严格性违规错误:

    page.locator("button").click();
  • 这只会找到第二个按钮,因为它是可见的,然后点击它。

    page.locator("button:visible").click();

CSS: 包含其他元素的元素

:has()伪类是一个实验性CSS伪类。如果作为参数传递的任何选择器相对于给定元素的:scope匹配至少一个元素,它将返回该元素。

以下代码片段返回包含<div class=promo><article>元素的文本内容。

page.locator("article:has(div.promo)").textContent();

CSS: 匹配任一条件的元素

逗号分隔的CSS选择器列表将匹配该列表中任一选择器可以选中的所有元素。

// 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();

:is()伪类是一个实验性CSS伪类,可用于指定元素上的额外条件列表。

CSS:基于布局匹配元素

note

基于布局的匹配可能会产生意外结果。例如,当布局变化一个像素时,可能会匹配到不同的元素。

有时,当目标元素缺乏显著特征时,很难为其找到一个合适的选择器。在这种情况下,使用Playwright的布局CSS伪类可能会有所帮助。这些伪类可以与常规CSS结合使用,以从多个选项中精确定位一个元素。

例如,input:right-of(:text("Password")) 匹配位于文本"Password"右侧的输入字段 - 当页面有多个难以区分的输入时非常有用。

请注意,布局伪类通常需要与其他选择器(如input)结合使用。如果单独使用布局伪类,例如:right-of(:text("Password")),很可能不会获取到您期望的输入框,而是会选中文本和目标输入框之间的某个空元素。

布局伪类使用bounding client rect来计算元素的距离和相对位置。

  • :right-of(div > button) - 匹配位于内部选择器匹配的任何元素右侧的元素,垂直位置不限。
  • :left-of(div > button) - 匹配位于内部选择器匹配的任何元素左侧的元素,无论垂直位置如何。
  • :above(div > button) - 匹配位于内部选择器匹配的任何元素上方的元素,无论水平位置如何。
  • :below(div > button) - 匹配位于内部选择器匹配的任何元素下方的元素,无论水平位置如何。
  • :near(div > button) - 匹配靠近(50 CSS像素范围内)内部选择器匹配的任何元素的元素。

请注意,结果匹配项会按照它们与锚点元素的距离进行排序,因此您可以使用Locator.first()来选择最近的一个。这仅在您有一系列相似元素(其中最接近的显然是正确的元素)时才有用。然而,在其他情况下使用Locator.first()很可能不会按预期工作——它不会定位到您正在搜索的元素,而是定位到恰好最近的某个其他元素,比如一个随机的空

,或者一个已滚动出当前视图不可见的元素。

// 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();

所有布局伪类都支持将最大像素距离作为可选参数。例如button:near(:text("Username"), 120)会匹配距离文本为"Username"的元素最多120 CSS像素远的按钮。

CSS: 从查询结果中选择第n个匹配项

note

通常可以通过某些属性或文本内容来区分元素,这对页面变化更具弹性。

有时页面包含许多相似的元素,很难选择特定的某一个。例如:

<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开始的。

// Click the third "Buy" button
page.locator(":nth-match(:text('Buy'), 3)").click();

:nth-match() 也可用于等待指定数量的元素出现,使用 Locator.waitFor()

// Wait until all three buttons are visible
page.locator(":nth-match(:text('Buy'), 3)").waitFor();
note

:nth-child()不同,元素不必是同级元素,它们可以位于页面上的任何位置。在上面的代码片段中,所有三个按钮都匹配:text("Buy")选择器,而:nth-match()选择了第三个按钮。

第N个元素定位器

您可以通过传递基于零的索引,使用nth=定位器将查询范围缩小到第n个匹配项。

// Click first button
page.locator("button").locator("nth=0").click();

// Click last button
page.locator("button").locator("nth=-1").click();

父元素定位器

当您需要定位某个其他元素的父元素时,大多数情况下您应该通过子定位器使用Locator.filter()。例如,考虑以下DOM结构:

<li><label>Hello</label></li>
<li><label>World</label></li>

如果您想定位带有文本"Hello"的标签的父元素

  • ,使用Locator.filter()效果最佳:

    Locator child = page.getByText("Hello");
    Locator parent = page.getByRole(AriaRole.LISTITEM).filter(new Locator.FilterOptions().setHas(child));

    或者,如果您无法为父元素找到合适的定位器,可以使用xpath=..。请注意,这种方法不太可靠,因为对DOM结构的任何更改都会破坏您的测试。在可能的情况下,优先使用Locator.filter()

    Locator parent = page.getByText("Hello").locator("xpath=..");

    React定位器

    note

    React定位器目前处于实验阶段,并带有_前缀。其功能在未来可能会发生变化。

    React定位器允许通过组件名称和属性值查找元素。其语法与CSS属性选择器非常相似,并支持所有CSS属性选择器运算符。

    在React定位器中,组件名称使用驼峰式命名法进行转换。

    page.locator("_react=BookItem").click();

    更多示例:

    • 组件匹配:_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

    note

    React定位器支持React 15及以上版本。

    note

    React定位器以及React DevTools仅适用于未压缩的应用程序构建版本。

    Vue定位器

    note

    Vue定位器目前处于实验阶段,并带有_前缀。其功能在未来可能会发生变化。

    Vue定位器允许通过组件名称和属性值查找元素。其语法与CSS属性选择器非常相似,并支持所有CSS属性选择器运算符。

    在Vue定位器中,组件名称使用kebab-case格式书写。

    page.locator("_vue=book-item").click();

    更多示例:

    • 通过组件匹配:_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

    note

    Vue定位器支持Vue2及以上版本。

    note

    Vue定位器,以及Vue DevTools,仅适用于未压缩的应用程序构建版本。

    XPath定位器

    warning

    我们建议优先使用用户可见的定位器,如文本或可访问角色,而不是使用与实现紧密耦合且页面变更时容易失效的XPath。

    XPath定位器等同于调用Document.evaluate

    page.locator("xpath=//button").click();
    note

    Any selector string starting with // or .. are assumed to be an xpath selector. For example, Playwright converts '//html/body' to 'xpath=//html/body'.

    note

    XPath 不会穿透影子根节点。

    XPath 联合

    管道操作符 (|) 可用于在XPath中指定多个选择器。它将匹配列表中任一选择器能选中的所有元素。

    // Waits for either confirmation dialog or load spinner.
    page.locator("//span[contains(@class, 'spinner__loading')]|//div[@id='confirmation']").waitFor();

    标签到表单控件的重定向

    warning

    我们建议通过标签文本定位,而不是依赖标签到控件的重定向。

    Playwright中的目标输入操作会自动区分标签和控件,因此您可以针对标签执行关联控件的操作。

    例如,考虑以下DOM结构:。您可以使用Page.getByText()通过"Password"文本来定位该标签。但是,以下操作将在输入框上执行而不是标签上:

    // Fill the input by targeting the label.
    page.getByText("Password").fill("secret");

    然而,其他方法将针对标签本身,例如assertThat(locator).hasText()会断言标签的文本内容,而不是输入字段。

    // Fill the input by targeting the label.
    assertThat(page.locator("label")).hasText("Password");

    传统文本定位器

    warning

    我们推荐使用现代的文本定位器替代。

    传统文本定位器会匹配包含传入文本的元素。

    page.locator("text=Log in").click();

    传统文本定位器有几种变体:

    • text=Log in - 默认匹配不区分大小写,会去除空格并搜索子字符串。例如,text=Log 可以匹配

      page.locator("text=Log in").click();
    • text="Log in" - 文本内容可以用单引号或双引号转义,用于在去除空格后搜索具有精确内容的文本节点。

      例如,text="Log" 不匹配 ,因为 包含一个文本节点 "Log in",这与 "Log" 不相等。但是,text="Log" 匹配 ,因为 包含一个文本节点 " Log "。这种精确模式意味着区分大小写的匹配,因此 text="Download" 不会匹配

      引用的内容遵循通常的转义规则,例如使用 \" 来转义双引号字符串中的双引号:text="foo\"bar"

      page.locator("text='Log in'").click();
    • /Log\s*in/i - body 可以是一个类似 JavaScript 的正则表达式,用 / 符号包裹。例如,text=/Log\s*in/i 可以匹配

      page.locator("text=/Log\\s*in/i").click();
    note

    以引号("')开头和结尾的字符串选择器会被视为传统文本定位器。例如,"Log in" 在内部会被转换为 text="Log in"

    note

    匹配时始终会规范化空白字符。例如,它会将多个空格转换为一个,将换行符转换为空格,并忽略开头和结尾的空白字符。

    note

    类型为buttonsubmit的输入元素是通过它们的value值而非文本内容来匹配的。例如,text=Log in会匹配<input type=button value="Log in">

    id、data-testid、data-test-id、data-test选择器

    warning

    我们建议改用通过测试ID定位

    Playwright支持使用特定属性选择元素的简写方式。目前仅支持以下属性:

    • id
    • data-testid
    • data-test-id
    • data-test
    // 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();
    note

    属性选择器并非CSS选择器,因此不支持任何CSS特有的语法如:enabled。如需使用更多功能特性,请使用标准的css选择器,例如css=[data-test="login"]:enabled

    链式选择器

    warning

    我们建议改用链式定位器

    定义为engine=body或简写形式的selector可以与>>标记组合使用,例如selector1 >> selector2 >> selectors3。当selector被串联时,下一个selector会相对于前一个的结果进行查询。

    例如,

    css=article >> css=.bar > .baz >> css=span[attr=value]

    等同于

    document
    .querySelector('article')
    .querySelector('.bar > .baz')
    .querySelector('span[attr=value]');

    如果一个选择器需要在主体中包含>>,应该将其在字符串中转义以避免与链式分隔符混淆,例如text="some >> text"

    中间匹配项

    warning

    我们建议通过其他定位器进行过滤来定位包含其他元素的元素。

    默认情况下,链式选择器会解析为最后一个选择器查询的元素。可以在选择器前加上*前缀来捕获由中间选择器查询的元素。

    例如,css=article >> text=Hello 捕获带有文本 Hello 的元素,而 *css=article >> text=Hello(注意开头的 *)则捕获包含某个带有文本 Hello 元素的 article 元素。