Slack自动化无障碍测试技术实践

本文详细介绍了Slack如何将Axe无障碍测试工具集成到Playwright端到端测试框架中,包括技术选型考量、自定义实现方案、违规报告机制和环境配置策略,为大型项目的自动化无障碍测试提供了完整的技术实践参考。

Slack自动化无障碍测试

在Slack,客户喜爱是我们的首要任务,而无障碍性是客户信任的核心原则。我们拥有自己的Slack无障碍标准,产品团队遵循这些标准来确保其功能符合Web内容无障碍指南(WCAG)。我们专门的无障碍团队在整个开发过程中支持开发人员遵循这些指南。我们还经常与专门从事无障碍性的外部手动测试人员合作。

2022年,我们开始通过为桌面端设置自动化无障碍测试来补充Slack的无障碍策略,以在整个开发过程中捕获一部分无障碍违规行为。在Slack,我们将自动化无障碍测试视为对我们更广泛测试策略的宝贵补充。

探索与限制

意外的复杂性:Axe、Jest和React Testing Library(RTL)

我们选择使用Axe,这是一个流行且易于配置的无障碍测试工具,因为它具有广泛的功能且与我们当前的端到端(E2E)测试框架兼容。Axe检查各种无障碍指南,其中大多数对应于WCAG的特定成功标准,并且它以一种最小化误报的方式进行。

最初我们探索了将Axe无障碍检查直接嵌入到React Testing Library(RTL)框架中的可能性。通过使用包含Axe检查的自定义渲染函数包装RTL的渲染方法,我们可以消除开发人员工作流程中的许多摩擦。然而,我们立即遇到了一个与我们如何在Slack定制Jest设置相关的问题。

Axe检查的最佳解决方案:Playwright

由于Jest被排除为Axe的候选方案,我们转向了Playwright,这是Slack使用的E2E测试框架。Playwright通过@axe-core/playwright包支持使用Axe进行无障碍测试。Axe Core提供了过滤和自定义无障碍检查所需的大部分功能。

我们最初的目标是将无障碍检查直接"烘焙"到Playwright的交互方法中,例如点击和导航,以自动运行Axe,而不需要测试作者显式调用它。

在朝着这个目标努力的过程中,我们发现这种方法的主要挑战源于Playwright的Locator对象。Locator对象旨在通过管理自动等待、加载和确保元素在执行任何操作之前完全可交互来简化与页面元素的交互。

自定义和变通方案

为了规避在框架中嵌入无障碍检查遇到的障碍,我们决定做出一些让步,同时仍然优先考虑简化的开发人员工作流程。我们继续专注于Playwright,因为它在如何选择性地隐藏或应用无障碍检查方面提供了更大的灵活性,使我们能够更轻松地管理这些检查的运行时间和位置。

使用@axe-core/playwright包,我们可以描述无障碍检查的流程:

  • Playwright测试登陆页面/视图
  • Axe分析页面
  • 预定义的排除项被过滤掉
  • 违规和工件保存到文件

首先,我们设置主要函数runAxeAndSaveViolations,并使用AxeBuilder类提供的功能自定义范围。

我们想要检查是否符合WCAG 2.1,A级和AA级。

1
2
3
4
5
6
7
constructor(page: Page) { 
     this.page = page; 
     this.defaultTags = ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa']; 
     this.bodyText = ''; 
     this.baseFileName = `${test.info().title}-violations`.replace(/\//g, '-'); 
     A11y.filenameCounter = 0; 
}

我们创建了一个选择器列表,从违规报告中排除。这些主要分为两类:

  • 已知的无障碍问题 - 我们已经意识到并已经创建工单的问题
  • 不适用的规则 - 超出Slack无障碍设计范围的Axe规则
1
2
3
4

constants.ACCESSIBILITY.AXE_EXCLUDED_SELECTORS.forEach((excludedSelector) => {
     axe.exclude(excludedSelector);
});

我们还想要过滤重复项和严重级别。我们创建了检查每个违规唯一性并过滤掉重复项的方法。我们选择仅报告根据WCAG被视为严重的违规。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
/**
* Filter violations based on criticality, then ensure we
* are removing any duplicate violations within a single test file
* Please note: this only removes duplicates on a single test, not the entire run
*/
private filterAndRemoveDuplicateViolations(violations: Violation[]) {
   return violations
	.filter((violation) => ['critical'].includes(violation.impact))
	.map(this.mapViolation)
	.filter(this.isUniqueViolation.bind(this));
}

端到端测试中的无障碍检查放置

为了启动项目,我们设置了一个测试套件,镜像了我们测试Slack关键功能的套件。我们重命名了该套件以明确其用于无障碍测试,并将其设置为非阻塞运行。

在策略上,我们考虑了在这些关键流程测试中无障碍检查的放置位置。通常,我们的目标是为测试中涵盖的每个新视图、页面或流程添加无障碍检查。

违规报告

我们花了一些时间迭代我们的无障碍违规报告。最初,我们创建了一个简单的文本文件来保存本地运行的结果,将其存储在工件文件夹中。

为了使我们的报告更加连贯和可读,我们利用了Playwright HTML Reporter。该工具不仅聚合测试结果,还允许我们将工件(如屏幕截图和违规报告)附加到HTML输出中。

环境设置和运行测试

一旦我们集成了Axe检查并设置了测试套件,我们需要确定开发人员应如何以及何时运行它们。为了简化开发人员的流程,我们引入了一个环境标志A11Y_ENABLE,以控制我们框架内无障碍检查的激活。

这种设置使我们能够为开发人员提供以下选项:

  • 按需测试:开发人员可以在需要在其分支上本地运行无障碍检查时手动启用该标志
  • 计划运行:开发人员可以在非高峰时段配置定期运行
  • CI集成:可选地,可以在持续集成管道中启用该标志,以便在合并重大更改之前进行彻底测试

分类和所有权

一旦我们将Axe调用添加到Playwright E2E测试中的关键流程,我们需要决定谁将负责分类通过自动化发现的无障碍问题,以及谁将拥有现有测试的测试维护。

在Slack,我们使开发人员能够拥有其测试的测试创建和维护。为了支持开发人员更好地理解框架更改和新的无障碍自动化,我们创建了文档,并与内部Slack无障碍团队合作,制定了一个全面的分类流程,该流程将适应他们现有的无障碍问题分类工作流程。

进行审计

我们定期对无障碍Playwright调用进行审计,以检查Axe调用的重复情况,并确保测试和测试套件中无障碍检查的适当覆盖。

我们开发了一个脚本和一个专门的环境标志来促进审计过程。审计可以通过沙盒测试运行(适用于套件范围的审计)或本地(适用于特定测试或子集)执行。

下一步计划

我们计划继续与Slack内部无障碍团队合作,设计一个小型阻塞测试套件。这些测试将专门用于Slack核心功能的流程,重点关注键盘导航。

我们还希望探索AI驱动的方法来处理无障碍测试结果的后处理,并研究让AI助手审计我们的套件以确定无障碍检查的放置位置,进一步减少开发人员的手动工作。

结束思考

在这个项目中,我们不得不做出一些意外的权衡,在自动化测试工具的实际限制与减轻开发人员负担的目标之间取得平衡。虽然我们无法将无障碍检查完全集成到我们的前端框架中,但我们在实现该目标方面取得了重大进展。

我们自动化的Axe检查减少了对手动测试的依赖,现在补充了其他基本形式的测试 - 如手动测试和可用性研究。目前,开发人员需要手动添加检查,但我们已经为尽可能简化流程奠定了基础,并有可能实现AI驱动的无障碍测试创建。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计