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

本文详细介绍了Slack如何将自动化无障碍测试集成到Playwright端到端测试框架中,包括Axe工具的选择、技术实现方案、自定义配置和问题解决策略。

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

在Slack,客户喜爱是我们的首要任务,而无障碍性是客户信任的核心原则。我们制定了Slack无障碍标准,产品团队遵循这些标准以确保其功能符合Web内容无障碍指南(WCAG)。我们专门的无障碍团队在整个开发过程中支持开发人员遵循这些指南。

探索与限制

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

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

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

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

由于Jest被排除为Axe的候选方案,我们转向了Playwright,这是Slack使用的E2E测试框架。Playwright通过@axe-core/playwright包支持使用Axe进行无障碍测试。

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

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

自定义和变通方案

为了规避在框架中嵌入无障碍检查遇到的障碍,我们决定做出一些让步,同时仍然优先考虑简化的开发人员工作流程。

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

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

首先,我们设置了主要函数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
/**
* 基于严重性过滤违规,然后确保我们
* 在单个测试文件中删除任何重复的违规
* 请注意:这只删除单个测试中的重复项,而不是整个运行
*/
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助手审计我们的套件以确定无障碍检查的放置,进一步减少开发人员的手动工作。

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