按角色
getByRole、queryByRole、getAllByRole、queryAllByRole、findByRole、findAllByRole
API
getByRole(
// If you're using `screen`, then skip the container argument:
container: HTMLElement,
role: string,
options?: {
hidden?: boolean = false,
name?: TextMatch,
description?: TextMatch,
selected?: boolean,
busy?: boolean,
checked?: boolean,
pressed?: boolean,
suggest?: boolean,
current?: boolean | string,
expanded?: boolean,
queryFallbacks?: boolean,
level?: number,
value?: {
min?: number,
max?: number,
now?: number,
text?: TextMatch,
}
}): HTMLElement
查询具有给定角色的元素(它还接受一个 TextMatch
)。默认角色会被考虑在内,例如 <button />
具有 button
角色,而无需显式设置 role
属性。您可以在 HTML 元素及其默认角色和预期角色的表格 中看到这一点。
请注意,设置与隐式 ARIA 语义匹配的 role
和/或 aria-*
属性是不必要的,并且**不推荐**,因为这些属性已由浏览器设置,并且我们不应以与描述的语义冲突的方式使用 role
和 aria-*
属性。例如,button
元素不能具有 heading
的 role
属性,因为 button
元素具有与 heading
角色冲突的默认特性。
角色通过字符串相等进行逐字匹配,不从 ARIA 角色层次结构继承。因此,查询像
checkbox
这样的超类角色不会包含像switch
这样的子类角色的元素。
您可以通过其 可访问名称或描述 查询返回的元素。对于简单情况,可访问名称等于例如表单元素的标签、按钮的文本内容或 aria-label
属性的值。如果渲染的内容中存在多个具有相同角色的元素,它可以用来查询特定元素。有关深入指南,请查看 TPGi 的“什么是可访问名称?”。如果您只查询单个元素,例如 getByText('The name')
,那么通常最好使用 getByRole(expectedRole, { name: 'The name' })
。可访问名称查询不会替代其他查询,例如 *ByAlt
或 *ByTitle
。虽然可访问名称可能等于这些属性,但它不会替代这些属性的功能。例如 <img aria-label="fancy image" src="fancy.jpg" />
将返回 getByRole('img', { name: 'fancy image' })
。但是,如果无法加载 fancy.jpg
,则图像不会显示其描述。您是否要在测试中断言此功能由您决定。
不幸的是,规范定义了 <input type="password" />
没有隐式角色。这意味着为了查询此类型的元素,我们必须回退到不太强大的查询,例如 ByLabelText
。
选项
hidden
如果您将 hidden
设置为 true
,则通常从无障碍树中排除的元素也会被视为查询对象。默认行为遵循 https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion,但 role="none"
和 role="presentation"
除外,它们在任何情况下都会被视为查询对象。例如在
<body>
<main aria-hidden="true">
<button>Open dialog</button>
</main>
<div role="dialog">
<button>Close dialog</button>
</div>
</body>
getByRole('button')
仅返回 Close dialog
按钮。要对 Open dialog
按钮进行断言,您需要使用 getAllByRole('button', { hidden: true })
。
hidden
的默认值可以 配置。
selected
您可以通过设置 selected: true
或 selected: false
来根据其选中状态筛选返回的元素。
例如在
<body>
<div role="tablist">
<button role="tab" aria-selected="true">Native</button>
<button role="tab" aria-selected="false">React</button>
<button role="tab" aria-selected="false">Cypress</button>
</div>
</body>
您可以通过调用 getByRole('tab', { selected: true })
获取 "Native" 选项卡。要了解有关选中状态以及哪些元素可以具有此状态的更多信息,请参阅 ARIA aria-selected
。
busy
您可以通过设置 busy: true
或 busy: false
来根据其忙碌状态筛选返回的元素。
例如在
<body>
<section>
<div role="alert" aria-busy="false">Login failed</div>
<div role="alert" aria-busy="true">Error: Loading message...</div>
</section>
</body>
您可以通过调用 getByRole('alert', { busy: false })
获取 "Login failed" 警报。要了解有关忙碌状态的更多信息,请参阅 ARIA aria-busy
和 MDN aria-busy
属性。
checked
您可以通过设置 checked: true
或 checked: false
来根据其选中状态筛选返回的元素。
例如在
<body>
<section>
<button role="checkbox" aria-checked="true">Sugar</button>
<button role="checkbox" aria-checked="false">Gummy bears</button>
<button role="checkbox" aria-checked="false">Whipped cream</button>
</section>
</body>
您可以通过调用 getByRole('checkbox', { checked: true })
获取 "Sugar" 选项。要了解有关选中状态以及哪些元素可以具有此状态的更多信息,请参阅 ARIA aria-checked
。
注意
复选框具有 "mixed" 状态,它既不被认为是选中,也不被认为是未选中(详细信息 在此)。
current
您可以通过设置 current: boolean | string
来根据其当前状态筛选返回的元素。请注意,没有 aria-current
属性会匹配 current: false
,因为 false
是 aria-current
的默认值。
例如在
<body>
<nav>
<a href="current/page" aria-current="page">👍</a>
<a href="another/page">👎</a>
</nav>
</body>
您可以通过调用 getByRole('link', { current: 'page' })
获取 "👍" 链接,通过调用 getByRole('link', { current: false })
获取 "👎"。要了解有关当前状态的更多信息,请参阅 ARIA aria-current
。
pressed
按钮可以具有按下状态。您可以通过设置 pressed: true
或 pressed: false
来根据其按下状态筛选返回的元素。
例如在
<body>
<section>
<button aria-pressed="true">👍</button>
<button aria-pressed="false">👎</button>
</section>
</body>
您可以通过调用 getByRole('button', { pressed: true })
获取 "👍" 按钮。要了解有关按下状态的更多信息,请参阅 ARIA aria-pressed
。
suggest
您可以通过将此值设置为 false
来禁用对特定查询 抛出建议 的功能。
将此值设置为 true
将对特定查询抛出建议。
expanded
您可以通过设置 expanded: true
或 expanded: false
来根据其展开状态筛选返回的元素。
例如在
<body>
<nav>
<ul>
<li>
<a aria-expanded="false" aria-haspopup="true" href="..."
>Expandable Menu Item</a
>
<ul>
<li><a href="#">Submenu Item 1</a></li>
<li><a href="#">Submenu Item 1</a></li>
</ul>
</li>
<li><a href="#">Regular Menu Item</a></li>
</ul>
</nav>
</body>
您可以通过调用 getByRole('link', { expanded: false })
获取 "Expandable Menu Item" 链接。要了解有关展开状态以及哪些元素可以具有此状态的更多信息,请参阅 ARIA aria-expanded
。
<div role="dialog">...</div>
- 原生
- React
- Angular
- Cypress
import {screen} from '@testing-library/dom'
const dialogContainer = screen.getByRole('dialog')
import {render, screen} from '@testing-library/react'
render(<MyComponent />)
const dialogContainer = screen.getByRole('dialog')
import {render, screen} from '@testing-library/angular'
await render(MyComponent)
const dialogContainer = screen.getByRole('dialog')
cy.findByRole('dialog').should('exist')
queryFallbacks
默认情况下,假定每个元素的第一个角色都受支持,因此只有第一个角色可以被查询。如果您需要根据元素的任何备用角色来查询元素,可以使用 queryFallbacks: true
。
例如,getByRole('switch')
始终匹配 <div role="switch checkbox" />
,因为它是第一个角色,而 getByRole('checkbox')
则不会。但是,getByRole('checkbox', { queryFallbacks: true })
将启用所有备用角色,因此将匹配同一个元素。
元素在给定环境中没有多个角色。它只有一个。属性中的多个角色会从左到右进行评估,直到环境找到它理解的第一个角色为止。当引入新角色,并且您希望开始支持这些角色以及尚未理解该角色的旧环境时,这很有用。
level
具有 heading
角色的元素可以通过任何标题级别 getByRole('heading')
查询,也可以通过使用 level
选项 getByRole('heading', { level: 2 })
查询特定标题级别。
level
选项查询与由语义 HTML 标题元素 <h1>-<h6>
确定的指示级别匹配或与 aria-level
属性匹配的具有 heading
角色的元素。
鉴于以下示例,
<body>
<section>
<h1>Heading Level One</h1>
<h2>First Heading Level Two</h2>
<h3>Heading Level Three</h3>
<div role="heading" aria-level="2">Second Heading Level Two</div>
</section>
</body>
您可以使用 getByRole('heading', { level: 3 })
查询 Heading Level Three
标题。
getByRole('heading', {level: 1})
// <h1>Heading Level One</h1>
getAllByRole('heading', {level: 2})
// [
// <h2>First Heading Level Two</h2>,
// <div role="heading" aria-level="2">Second Heading Level Two</div>
// ]
虽然可以在元素上显式设置 role="heading"
和 aria-level
属性,但**强烈建议**使用语义 HTML 标题 <h1>-<h6>
。
要了解有关 aria-level
属性的更多信息,请参阅 ARIA aria-level
。
level
选项仅适用于heading
角色。与任何其他角色一起使用时,会抛出错误。
value
范围小部件可以通过任何值 getByRole('spinbutton')
查询,也可以通过使用 level
选项 getByRole('spinbutton', { value: { now: 5, min: 0, max: 10, text: 'medium' } })
查询特定值。
请注意,您不必在 value
中指定所有属性。子集就足够了,例如 getByRole('spinbutton', { value: { now: 5, text: 'medium' } })
。
鉴于以下示例,
<body>
<section>
<button
role="spinbutton"
aria-valuenow="5"
aria-valuemin="0"
aria-valuemax="10"
aria-valuetext="medium"
>
Volume
</button>
<button
role="spinbutton"
aria-valuenow="3"
aria-valuemin="0"
aria-valuemax="10"
aria-valuetext="medium"
>
Pitch
</button>
</section>
</body>
您可以使用以下查询查询特定旋钮:
getByRole('spinbutton', {value: {now: 5}})
// <button>Volume</button>
getAllByRole('spinbutton', {value: {min: 0}})
// [
// <button>Volume</button>,
// <button>Pitch</button>
// ]
value
中的每个指定属性都必须匹配。例如,如果您查询{value: {min: 0, now: 3}}
,则aria-valuemin
必须等于 0,**并且**aria-valuenow
必须等于 3。
value
选项仅适用于某些角色(请查看下面链接的 MDN 页面以了解适用的角色)。与任何其他角色一起使用时,会抛出错误。
要了解更多关于 aria-value*
属性的信息,请参阅 MDN aria-valuemin
、MDN aria-valuemax
、MDN aria-valuenow
、MDN aria-valuetext
。
description
您可以通过其 可访问描述 过滤返回的元素,在您有多个具有相同角色的元素且它们没有可访问名称但有描述的情况下使用。
对于具有 alertdialog 角色的元素,这种情况会发生,其中 aria-describedby
属性用于描述元素的内容。
例如在
<body>
<ul>
<li role="alertdialog" aria-describedby="notification-id-1">
<div><button>Close</button></div>
<div id="notification-id-1">You have unread emails</div>
</li>
<li role="alertdialog" aria-describedby="notification-id-2">
<div><button>Close</button></div>
<div id="notification-id-2">Your session is about to expire</div>
</li>
</ul>
</body>
您可以像这样查询特定元素
getByRole('alertdialog', {description: 'Your session is about to expire'})
性能
getByRole
是最推荐使用的查询,因为它最接近用户体验,但是它必须执行的计算才能提供这种置信度可能会很昂贵(尤其是在大型 DOM 树中)。
如果测试性能是一个问题,您可能希望为了提高性能而牺牲一些置信度。
可以通过将选项 hidden
设置为 true
来提高 getByRole
的性能,从而避免昂贵的可见性检查。请注意,这样做会导致不可访问的元素现在包含在结果中。
另一个选择可能是用更简单的 getByLabelText
和 getByText
查询替换 getByRole
,这些查询速度可能快得多,但鲁棒性更低。