快照测试
概述
通过 Playwright 的快照测试,你可以将页面的可访问性树与预定义的快照模板进行断言。
- 同步
- 异步
page.goto('https://playwright.dev/')
expect(page.query_selector('banner')).to_match_aria_snapshot("""
- banner:
- heading /Playwright enables reliable end-to-end/ [level=1]
- link "Get started"
- link "Star microsoft/playwright on GitHub"
- link /[\\d]+k\\+ stargazers on GitHub/
""")
await page.goto('https://playwright.dev/')
await expect(page.query_selector('banner')).to_match_aria_snapshot("""
- banner:
- heading /Playwright enables reliable end-to-end/ [level=1]
- link "Get started"
- link "Star microsoft/playwright on GitHub"
- link /[\\d]+k\\+ stargazers on GitHub/
""")
断言测试 vs 快照测试
快照测试和断言测试在自动化测试中有不同的作用:
断言测试
断言测试是一种有针对性的方法,你可以断言元素或组件的特定值或条件。例如,在 Playwright 中,expect(locator).to_have_text() 用于验证元素包含期望的文本,expect(locator).to_have_value() 用于确认输入框具有期望的值。断言测试具有针对性,通常将元素或属性的当前状态与预期的、预定义的状态进行比较。它适用于可预测的、单值的检查,但在测试更广泛的结构或变化时有局限性。
优点
- 清晰:测试意图明确,易于理解。
- 针对性强:测试聚焦于功能的特定方面,对无关更改更具鲁棒性。
- 易于调试:失败时能提供有针对性的反馈,直接指出问题所在。
缺点
- 复杂输出时冗长:对复杂数据结构或大输出编写断言会很繁琐且容易出错。
- 维护成本高:随着代码演进,手动更新断言可能很耗时。
快照测试
快照测试会捕获某一时刻元素、组件或数据的“快照”或表示,并将其保存以供将来比较。重新运行测试时,会将当前状态与快照进行比较,如果有差异,测试就会失败。这种方式特别适用于复杂或动态结构,手动断言每个细节会非常耗时。快照测试比断言测试更广泛、更整体,便于跟踪复杂变化。
优点
- 简化复杂输出:例如,测试 UI 组件的渲染输出,用传统断言很繁琐,快照可以一次性捕获全部输出,便于比较。
- 快速反馈:开发者可以轻松发现输出中的非预期变化。
- 促进一致性:帮助代码演进过程中保持输出一致。
缺点
- 过度依赖:可能会在不了解变更的情况下接受快照更新,从而隐藏 bug。
- 粒度问题:快照过大时,出现差异时难以解读,尤其是小变动影响大范围输出时。
- 适用性:不适合输出经常或不可预测变化的高度动态内容。
适用场景
- 快照测试 适用于:
- 整个页面和组件的 UI 测试。
- 复杂 UI 组件的结构性检查。
- 结构很少变化的输出的回归测试。
- 断言测试 适用于:
- 核心逻辑校验。
- 计算值测试。
- 需要精确条件的细粒度测试。
结合快照测试(用于结构性检查)和断言测试(用于具体功能),可以实现更全面的测试策略。
Aria 快照
在 Playwright 中,aria 快照以 YAML 格式表示页面的可访问性树。这些快照可以保存并在后续进行比较,以验证页面结构是否保持一致或符合预期。
YAML 格式描述了页面上可访问元素的层级结构,详细说明了角色、属性、值和文本内容。结构采用树形语法,每个节点代表一个可访问元素,缩进表示嵌套关系。
树中的每个可访问元素都用 YAML 节点表示:
- role "name" [attribute=value]
- role:指定元素的 ARIA 或 HTML 角色(如
heading
、list
、listitem
、button
)。 - "name":元素的可访问名称。用引号括起来的字符串表示精确值,
/patterns/
用于正则表达式。 - [attribute=value]:方括号内的属性和值,表示特定的 ARIA 属性,如
checked
、disabled
、expanded
、level
、pressed
或selected
。
这些值来源于 ARIA 属性或根据 HTML 语义计算得出。要检查页面的可访问性树结构,可以使用 Chrome DevTools 可访问性标签页。
快照匹配
Playwright 中的 expect(locator).to_match_aria_snapshot() 断言方法会将定位器范围内的可访问结构与预定义的 aria 快照模板进行比较,帮助验证页面状态是否符合测试要求。
对于如下 DOM:
<h1>title</h1>
你可以用如下快照模板进行匹配:
- 同步
- 异步
expect(page.locator("body")).to_match_aria_snapshot("""
- heading "title"
""")
await expect(page.locator("body")).to_match_aria_snapshot("""
- heading "title"
""")
匹配时,快照模板会与页面当前的可访问性树进行比较:
- 如果树结构与模板匹配,测试通过;否则测试失败,提示期望与实际可访问状态不符。
- 比较区分大小写并会折叠空白字符,因此缩进和换行会被忽略。
- 比较对顺序敏感,快照模板中元素的顺序必须与页面可访问性树中的顺序一致。
部分匹配
你可以通过省略属性或可访问名称,对节点进行部分匹配,从而验证可访问性树的特定部分,而无需完全匹配。这对于动态或不相关的属性非常有用。
<button>Submit</button>
aria 快照
- button
在此示例中,只匹配了 button 角色,没有指定可访问名称("Submit"),因此无论按钮标签是什么,测试都能通过。
对于带有 checked
或 disabled
等 ARIA 属性的元素,省略这些属性可以实现部分匹配,仅关注角色和层级结构。
<input type="checkbox" checked>
部分匹配的 aria 快照
- checkbox
在这个部分匹配中,checked
属性被忽略,因此无论复选框状态如何,测试都能通过。
同样,你可以通过省略特定列表项或嵌套元素,对列表或分组的子元素进行部分匹配。
<ul>
<li>Feature A</li>
<li>Feature B</li>
<li>Feature C</li>
</ul>
部分匹配的 aria 快照
- list
- listitem: Feature B
部分匹配让你可以灵活地编写快照测试,验证页面的核心结构,而不强制要求具体内容或属性。
严格匹配
默认情况下,模板只要包含子元素的子集即可匹配:
<ul>
<li>Feature A</li>
<li>Feature B</li>
<li>Feature C</li>
</ul>
部分匹配的 aria 快照
- list
- listitem: Feature B
可以通过 /children
属性控制子元素的匹配方式:
contain
(默认):只要指定的子元素按顺序都存在即可匹配equal
:子元素必须与指定列表完全一致且顺序相同deep-equal
:子元素及其嵌套子元素必须与指定列表完全一致且顺序相同
<ul>
<li>Feature A</li>
<li>Feature B</li>
<li>Feature C</li>
</ul>
由于模板中没有 Feature C,aria 快照匹配会失败
- list
- /children: equal
- listitem: Feature A
- listitem: Feature B
正则表达式匹配
正则表达式允许对具有动态或可变文本的元素进行灵活匹配。可访问名称和文本内容都支持正则表达式模式。
<h1>Issues 12</h1>
带正则表达式的 aria 快照
- heading /Issues \d+/
快照生成
在 Playwright 中创建 aria 快照有助于确保和维护应用的结构。你可以根据测试环境和工作流,通过多种方式生成快照。
使用 Playwright 代码生成器生成快照
如果你在使用 Playwright 的代码生成器,可以通过其交互式界面轻松生成 aria 快照:
- “断言快照”操作:在代码生成器中,可以使用“断言快照”操作为选中的元素自动创建快照断言。这是将 aria 快照捕获为录制测试流程一部分的快捷方式。
- “Aria 快照”标签页:代码生成器界面中的“Aria 快照”标签页会以可视化方式展示所选定位器的 aria 快照,方便你探索、检查和验证元素角色、属性和可访问名称,辅助快照的创建和审查。
使用 Locator.ariaSnapshot
方法
locator.aria_snapshot() 方法允许你以编程方式生成定位器范围内可访问元素的 YAML 表示,特别适合在测试执行过程中动态生成快照。
示例:
- 同步
- 异步
snapshot = page.locator("body").aria_snapshot()
print(snapshot)
snapshot = await page.locator("body").aria_snapshot()
print(snapshot)
该命令会输出指定定位器范围内的 aria 快照(YAML 格式),你可以根据需要进行校验或保存。
可访问性树示例
带 level 属性的标题
标题可以包含 level
属性,表示其标题级别。
<h1>Title</h1>
<h2>Subtitle</h2>
aria 快照
- heading "Title" [level=1]
- heading "Subtitle" [level=2]
文本节点
独立或描述性文本元素会作为文本节点出现。
<div>Sample accessible name</div>
aria 快照
- text: Sample accessible name
内联多行文本
多行文本(如段落)会在 aria 快照中被标准化。
<p>Line 1<br>Line 2</p>
aria 快照
- paragraph: Line 1 Line 2
链接
链接会显示其文本或由伪元素组成的内容。
<a href="#more-info">Read more about Accessibility</a>
aria 快照
- link "Read more about Accessibility"
文本框
text
类型的输入元素会显示其 value
属性内容。
<input type="text" value="Enter your name">
aria 快照
- textbox: Enter your name
带列表项的列表
有序和无序列表会包含其列表项。
<ul aria-label="Main Features">
<li>Feature 1</li>
<li>Feature 2</li>
</ul>
aria 快照
- list "Main Features":
- listitem: Feature 1
- listitem: Feature 2
分组元素
分组会捕获嵌套元素,例如带有 summary 内容的 <details>
元素。
<details>
<summary>Summary</summary>
<p>Detail content here</p>
</details>
aria 快照
- group: Summary
属性与状态
常用的 ARIA 属性,如 checked
、disabled
、expanded
、level
、pressed
和 selected
,用于表示控件状态。
带 checked
属性的复选框
<input type="checkbox" checked>
aria 快照
- checkbox [checked]
带 pressed
属性的按钮
<button aria-pressed="true">Toggle</button>
aria 快照
- button "Toggle" [pressed=true]