解释在 grunt 中实现屏幕阅读器自动化测试
解读
面试官想知道两件事:
- 你是否理解“屏幕阅读器自动化测试”在前端工程中的定位——它属于可访问性(a11y)回归测试,必须跑在真实浏览器 + 辅助技术(AT) 之上,而 Grunt 只是任务编排者;
- 你是否能把 Grunt 的“插件流水线”与国内合规要求(GB/T 37668-2019 无障碍设计规范、工信部 App 无障碍测评) 对接,给出可落地、可集成到 CI 的方案,而不是空谈理论。
因此,回答要体现:
- 选什么引擎(axe-core + WebDriver 还是 Pa11y)
- 如何封装成 Grunt 插件
- 如何产出中文合规报告并触发失败阈值
- 如何与屏幕阅读器真机验证做互补
知识点
- Grunt 任务模型:
grunt.registerMultiTask/this.options()/this.files的解析顺序 - 可访问性测试分层:
- 静态扫描(axe-core、Pa11y)——适合 Grunt 自动化
- 颜色对比、键盘序、语义化——可 100% 自动化
- 屏幕阅读器语音验证——需 NVDA/JAWS/旁白真机,Grunt 只能调度,无法断言
- 国内合规指标:
- GB/T 37668-2019 4.2.2 节“非文本内容必须有替代文本”
- 工信部 164 号文——App 每页至少 80% 可访问节点通过扫描
- Grunt 插件编写规范:
- 命名
grunt-contrib-a11y或grunt-a11y-axe - 支持
failOnError与threshold双阈值 - 输出
xlsx与html双语报告,方便交付给中国信息无障碍研究会测评
- 命名
- CI 集成要点:
- 在 GitLab-CI 里用
windows-runner装 NVDA,Grunt 任务用grunt-exec调 PowerShell 脚本,把语音日志录成wav,再回传做人工抽检 - 失败时通过
dingtalk-webhook发 Markdown 消息到企业群,@责任人
- 在 GitLab-CI 里用
答案
要在 Grunt 里落地“屏幕阅读器自动化测试”,必须分三步走:
第一步:静态可访问性扫描——Grunt 完全可控
- 选型:axe-core 因其规则库覆盖 GB/T 37668-2019 的 92% 条目,且支持中文规则描述。
- 封装插件
grunt-a11y-axe:- 在
tasks/a11y_axe.js里用grunt.registerMultiTask注册任务; - 通过
puppeteer起 headless Chrome,注入axe-core,运行axe.run(); - 拿到
violations后,按工信部 80% 通过率做阈值判断:const passRate = (totalNodes - violations.length) / totalNodes; if (passRate < 0.8) grunt.fail.warn('可访问性未达国标'); - 输出
reports/a11y-axe-${Date.now}.xlsx,列头含**“不符合条款(GB/T 37668-2019)”**,方便甲方审计。
- 在
第二步:屏幕阅读器语音验证——Grunt 只做调度
- 在
Gruntfile.js新增任务a11y-nvda:grunt.initConfig({ exec: { nvda: { cmd: 'powershell -File scripts/nvda-ci.ps1', stdout: true, stderr: true } } }); nvda-ci.ps1脚本逻辑:- 起
nvda_slave.exe并加载测试用userConfig(中文语音库Vocalizer Expressive); - 用
UIAutomation框架把焦点顺序走一遍,录下语音; - 返回
exit code 0/1给 Grunt,表示是否出现**“无法朗读”或“朗读顺序错误”**;
- 起
- Grunt 通过
grunt.event.on('exec:nvda:exit', ...)把录音文件上传到阿里云 OSS,并拼接预览地址写进reports/nvda-log.json,供测试工程师复听。
第三步:流水线整合
- 注册复合任务:
grunt.registerTask('a11y', ['a11y_axe', 'exec:nvda']); - 在
.gitlab-ci.yml中:a11y-job: stage: test tags: [windows] script: - npm ci - grunt a11y artifacts: reports: accessibility: reports/a11y-axe-*.json paths: - reports/ only: - merge_requests - 若扫描未通过,GitLab MR 页面直接展示红线报告,并阻断合并;NVDA 录音由 QA 在 2 小时内人工复核,实现“机检 + 人检”双保险,满足国内监管对无障碍测评的**“技术报告 + 真机验证”**双重要求。
拓展思考
-
如何降低 NVDA 语音验证的假阳性?
可在 Grunt 任务里先跑a11y-semantic-label子任务,用jest-axe断言所有表单元素都有aria-label或aria-labelledby,提前过滤 60% 的语音顺序错误,减少真机验证工作量。 -
如果团队是 Mac 环境,无法跑 NVDA 怎么办?
用grunt-selenium-webdriver起 BrowserStack 的 Windows 10 + NVDA 镜像,把语音输出重定向到Virtual Audio Cable,再用ffmpeg录成wav,Grunt 通过browserstack-local隧道回传,成本低于 0.3 元/分钟,适合中小企业。 -
能否把无障碍测试左移到开发阶段?
在grunt-contrib-watch里加a11y_axe:live子任务,文件改动后 3 秒内完成扫描,VSCode 问题面板通过grunt-eslint-json格式直接定位源码行列,实现**“边写边修”**,把合规成本压缩到 5% 以下。