测试【免费下载链接】axe-coreAccessibility engine for automated Web UI testing项目地址https://gitcode.com/gh_mirrors/ax/axe-core点击查看免费下载导读本文围绕 axe-core自动化的 Web UI 可访问性检测引擎中的Generic Check通用检查机制展开讲解如何让一段 evaluate 逻辑被多个 Check 安全复用、如何通过 metadata 文件传入 options以及从 Generic Check 到规则Rule的完整调用链。阅读本文后你将掌握 axe-core 内置的 6 类通用 evaluate 函数attr-non-space-content、has-text-content、has-descendant、matches-definition、page-no-duplicate等的参数语义与真实使用案例并能直接动手编写自己的自定义 Check。文中所有结论均以本仓库 lib/checks/generic/README.md 与对应源码为依据。什么是 Generic Checkaxe-core 的 Check检查是规则Rule中的最小判定单元每个 Check 通常拥有独立的 metadata 文件如*.json来描述其id、evaluate函数与消息模板。然而很多 Check 的判定逻辑本质上是相同的——例如某个属性存在且不为空白、元素是否拥有可见文本、页面中是否存在匹配某选择器的元素这些逻辑会被数十个不同的 Check 反复使用。为了避免重复实现axe-core 将这些可复用的 evaluate 函数集中放在 lib/checks/generic 目录中统称为Generic Check。官方文档 lib/checks/generic/README.md 对它们给出了三条关键定义Generic Check 是被多个 Check 复用的 evaluate 函数它们不能被规则Rule直接使用——因此没有与之关联的 Check metadata 文件lib/checks/generic/目录下只有*-evaluate.js与*-after.js源码没有*.json它们必须由另一个 Check 传入所需 options 后间接使用。也就是说Generic Check 位于可执行逻辑这一层真正接入 axe-core 规则体系的是那些在 lib/checks 各子目录下引用它们的普通 Check。如何复用 Generic Check复用方式非常直接找到该 Generic Check 的 ID从 metadata-function-map 中获取把它作为自定义 Check metadata 文件中evaluate属性的值同时按需传入options。原文档给出的最小配置如下{ id: my-check, evaluate: generic-check-id, options: { required: true } }这里id是自定义 Check 的名字会被规则在all/any/none中引用evaluate指向 Generic Check 的函数标识符options则是透传给该函数第三参options的配置对象。关于从 metadata-function-map 获取 ID这一点可以参见 lib/checks/index.js 的文档注释自定义 Check 可以通过在 metadata 文件的evaluate属性中使用内部 Check 的 ID 来复用 axe-core 的任何内部 Check所有 Check ID 都能在 metadata-function-map 中找到。metadata-function-map 是 axe-core 构建时自动生成的Check ID → evaluate 函数映射它在 lib/core/base/check.js 的 Check 解析流程中被消费因此你只需要在evaluate中写出与函数导出名一致的字符串即可无需直接 import 源码。内置 Generic Check 逐个解析当前仓库 lib/checks/generic 目录下共有 7 个源码文件对应 5 组可复用的判定逻辑其中两组还配有after聚合函数。下面结合源码逐一说明它们的参数契约与行为。1. attr-non-space-content-evaluate属性存在且非空白源码attr-non-space-content-evaluate.jsfunction attrNonSpaceContentEvaluate(node, options {}, vNode) { if (!options.attribute || typeof options.attribute ! string) { throw new TypeError( attr-non-space-content requires options.attribute to be a string ); } if (!vNode.hasAttr(options.attribute)) { this.data({ messageKey: noAttr }); return false; } const attribute vNode.attr(options.attribute); const attributeIsEmpty !sanitize(attribute); if (attributeIsEmpty) { this.data({ messageKey: emptyAttr }); return false; } return true; }核心行为必传参数options.attribute必须是非空字符串否则直接抛出TypeError这是所有 Generic Check 统一的参数校验风格防止配置错误被静默吞掉判定流程先通过vNode.hasAttr检查属性是否存在不存在则写入messageKey: noAttr并返回false存在但经过 commons/text 的 sanitize 处理后为空全空白字符时写入messageKey: emptyAttr并返回false否则返回true失败消息分流通过this.data()写入不同的messageKey让 metadata 中的messages.fail可以根据不同失败原因展示不同文案。仓库内真实使用案例均位于 lib/checks/sharednon-empty-alt.jsonevaluate为attr-non-space-content-evaluateoptions.attribute为alt其 metadata 中messages.fail明确区分了noAttr元素没有 alt 属性与emptyAttralt 属性为空两种文案non-empty-placeholder.json、non-empty-title.json、non-empty-value.json 结构相同只是把options.attribute分别换成placeholder、title、value。可见这套一个函数 一个 attribute 参数的组合被 4 个 Check 复用正是 Generic Check 减少重复代码的直接证据。2. has-text-content-evaluate元素拥有非空文本内容源码has-text-content-evaluate.jsexport default function hasTextContentEvaluate(node, options, virtualNode) { try { return sanitize(subtreeText(virtualNode)) ! ; } catch { return undefined; } }核心行为对虚拟节点调用 commons/text 的 subtreeText 提取整棵子树的可访问文本再用sanitize去掉首尾空白文本非空返回true为空返回false若计算过程中抛错例如遇到无法处理的节点结构返回undefined此时该 Check 的结果会被 axe-core 视为不完整incomplete而非直接判失败。仓库内真实使用案例button-has-visible-text.json 与 has-visible-text.json 均以has-text-content-evaluate作为evaluate用于判断按钮/元素是否有可见文本。3. has-descendant-evaluate has-descendant-after元素是否包含特定后代evaluate 源码has-descendant-evaluate.jsfunction hasDescendant(node, options, virtualNode) { if (!options || !options.selector || typeof options.selector ! string) { throw new TypeError( has-descendant requires options.selector to be a string ); } if (options.passForModal isModalOpen()) { return true; } const matchingElms querySelectorAllFilter( virtualNode, options.selector, vNode isVisibleToScreenReaders(vNode) ); this.relatedNodes(matchingElms.map(vNode vNode.actualNode)); return matchingElms.length 0; }after 源码has-descendant-after.jsfunction pageHasElmAfter(results) { const elmUsedAnywhere results.some( frameResult frameResult.result true ); if (elmUsedAnywhere) { results.forEach(result { result.result true; }); } return results; }核心行为必传参数options.selector必须是非空字符串CSS 选择器可选参数options.passForModal为true时若当前有模态对话框打开isModalOpen()直接判定通过——这是为了兼容焦点/可访问性树被模态框接管的页面场景匹配过滤通过 core/utils 的 querySelectorAllFilter 在虚拟节点子树内查找匹配选择器的元素并额外要求候选元素对屏幕阅读器可见commons/dom 的 isVisibleToScreenReaders避免把隐藏元素算作有效后代关联节点把命中的实际 DOM 节点通过this.relatedNodes()上报便于报告器展示证据after 聚合has-descendant-after负责跨 iframe 汇总——只要任一 frame 内判定为true就把所有 frame 的结果统一改写为true实现整页只要有一处满足即通过的语义。仓库内真实使用案例page-has-main.jsonevaluate: has-descendant-evaluate、after: has-descendant-afteroptions.selector为main:not([role]), [rolemain]passForModal为truepage-has-heading-one.json判断页面有 h1、header-present.json判断存在 header 地标、landmark.json 均复用has-descendant-evaluate只是更换了selector。4. matches-definition-evaluate按 matcher 对象判定元素是否匹配源码matches-definition-evaluate.jsfunction matchesDefinitionEvaluate(_, options, virtualNode) { return matches(virtualNode, options.matcher); }核心行为必传参数options.matcher是一个 axe-core 匹配器matcher对象直接交给 commons/matches 的matches()函数解析用途它本质上是把元素是否匹配某种角色/属性组合这一套 commons 匹配能力暴露成可复用的 Check通常用于判断元素是否具有某个 ARIA 角色等语义特征。仓库内真实使用案例role-none.json 与 role-presentation.json 均以matches-definition-evaluate为evaluate通过options.matcher描述应视为rolenone/rolepresentation的元素集合。5. page-no-duplicate-evaluate page-no-duplicate-after页面级去重判定evaluate 源码page-no-duplicate-evaluate.jsfunction pageNoDuplicateEvaluate(node, options, virtualNode) { if (!options || !options.selector || typeof options.selector ! string) { throw new TypeError( page-no-duplicate requires options.selector to be a string ); } const key page-no-duplicate; options.selector; if (cache.get(key)) { this.data(ignored); return; } cache.set(key, true); let elms querySelectorAllFilter(axe._tree[0], options.selector, elm isVisibleToScreenReaders(elm) ); // deprecated options.nativeScopeFilter if (typeof options.nativeScopeFilter string) { elms elms.filter(elm { return elm.hasAttr(role) || !findUpVirtual(elm, options.nativeScopeFilter); }); } if (typeof options.role string) { elms elms.filter(elm getRole(elm) options.role); } this.relatedNodes( elms.filter(elm elm ! virtualNode).map(elm elm.actualNode) ); return elms.length 1; }after 源码page-no-duplicate-after.jsfunction pageNoDuplicateAfter(results) { return results.filter(checkResult checkResult.data ! ignored); }核心行为必传参数options.selector非空字符串跨节点缓存由于该 Check 会被应用到多个候选节点它利用 core/base/cache 以page-no-duplicate; selector为键做全局去重——只有第一个节点真正执行扫描其余节点写入data: ignored后直接返回避免对整页重复扫描整页扫描通过axe._tree[0]从根节点开始用querySelectorAllFilter找出所有匹配选择器且对屏幕阅读器可见的元素可选过滤options.role为字符串时用 commons/aria 的 getRole 进一步筛选出指定 ARIA 角色的元素例如只统计rolebanner的地标options.nativeScopeFilter为已废弃的旧参数用于排除在特定原生上下文内不映射角色的元素如main内的footer不构成 banner 地标源码注释明确标注了deprecated新代码不应再依赖它判定结果把其他匹配节点排除自身登记为关联节点返回elms.length 1——即整页同类元素至多一个才算通过after 聚合page-no-duplicate-after过滤掉所有data ignored的冗余结果只保留真正执行过扫描的判定保证报告干净。仓库内真实使用案例均位于 lib/checks/keyboardpage-no-duplicate-banner.json、page-no-duplicate-contentinfo.json、page-no-duplicate-main.json 均以page-no-duplicate-evaluate为evaluate通过不同的selector与role组合实现页面不得存在多个 banner / contentinfo / main 地标的判定。完整调用链从 Generic Check 到 RuleGeneric Check 本身不挂规则它需要经过两层包装Generic Check → 普通 Check普通 Check 的 metadata 文件如 non-empty-alt.json在evaluate中引用 Generic Check 的函数 ID并在options中提供参数普通 Check → Rule规则Rule的 metadata 文件通过all/any/none数组引用普通 Check 的id。以页面必须有且仅有一个 main 地标为例链路如下规则 landmark-one-main.json 中all: [page-has-main]引用普通 Checkpage-has-main普通 Check page-has-main.json 的evaluate指向has-descendant-evaluateafter指向has-descendant-after并配置selector: main:not([role]), [rolemain]与passForModal: true。运行规则时axe-core 先按普通 Check 的配置实例化检查对象再通过 metadata-function-map 定位并调用对应的 Generic Check 函数传入节点、options以及this上下文提供data()、relatedNodes()等 API。如果你想验证这些行为可以在 test/checks/shared 等测试目录中找到对non-empty-*、has-visible-text等 Check 的用例它们间接覆盖了 Generic Check 的判定逻辑。实战基于 Generic Check 编写自定义 Check假设你的页面需要自定义一条检查视频元素必须存在非空标题title可以直接复用attr-non-space-content-evaluate新建一个 metadata 文件如lib/checks/media/video-title.json{ id: video-title, evaluate: attr-non-space-content-evaluate, options: { attribute: title }, metadata: { impact: serious, messages: { pass: Element has a non-empty title attribute, fail: { noAttr: Element has no title attribute, emptyAttr: Element has an empty title attribute } } } }随后在自定义规则如video-caption.json同目录风格中引用它{ id: video-title-rule, impact: serious, selector: video, tags: [cat.text-alternatives], metadata: { description: Ensure video elements have a non-empty title, help: Video elements should have a non-empty title }, all: [video-title], any: [], none: [] }再看一个更复杂的例子如果你要判断导航栏必须包含至少一个链接可以复用has-descendant-evaluate{ id: nav-has-link, evaluate: has-descendant-evaluate, after: has-descendant-after, options: { selector: a[href], passForModal: false }, metadata: { impact: moderate, messages: { pass: Navigation contains at least one link, fail: Navigation does not contain any links } } }编写时请牢记以下契约evaluate中填写的字符串必须与目标 Generic Check 的函数导出名一致且该 ID 必须在 metadata-function-map 中可解析每个 Generic Check 都有各自的必填options字段attribute/selector/matcher等遗漏或类型错误会抛出TypeError若判定结果需要区分布失败原因用messageKey配合 metadata 中messages.fail的映射对象输出差异化文案参考 non-empty-alt.json需要跨 iframe 聚合语义时如任一 frame 满足即通过忽略被忽略的重复扫描结果务必同时配置对应的after函数。小结Generic Check 的设计价值从仓库源码可以清晰看到Generic Check 机制是 axe-core配置驱动、逻辑复用架构的基石一份逻辑多处复用attr-non-space-content-evaluate一个函数服务了alt、title、placeholder、value四类属性的非空校验has-descendant-evaluate支撑了 main 地标、h1、header、landmark 等多个检查逻辑与元数据彻底分离Generic Check 目录下没有 JSON metadata 文件所有消息文案、影响级别、规则归属都由引用它的普通 Check 自行声明这让新增检查通常只需要新建一个 JSON 选一个 evaluate而不需要写任何判定代码参数化保证通用性每个函数都通过options接收 selector、attribute、matcher 等抽象参数并在入口处做严格的类型校验避免配置错误在运行时被掩盖。如果你希望深入编写自定义检查与规则的更多细节仓库文档 doc/check-options.md、doc/rule-check-templates.md 以及 doc/rule-development.md 提供了完整的模板与规范可以作为下一步阅读材料。赞分享测试【免费下载链接】axe-coreAccessibility engine for automated Web UI testing项目地址https://gitcode.com/gh_mirrors/ax/axe-core点击查看免费下载相关推荐axe-core 规则与检查开发速查Rule Check JSON 模板实战指南axe core 规则与检查开发速查Rule Check JSON 模板实战指南 axe core 的规则rule与检查check体系是自动可访问测试Bash 函数Funktionen实战指南从定义、传参到脚本复用的完整解析Bash 函数Funktionen实战指南从定义、传参到脚本复用的完整解析 本指南基于开源项目 introduction to bash scriptin文档教程axe-core Check 选项配置完全指南基于 check-options 定制无障碍检测规则axe core Check 选项配置完全指南基于 check options 定制无障碍检测规则 导读 本文围绕 axe core 的官方文档 doc/ch测试上一篇3 步保存任意在线流媒体免费流媒体下载器 N_m3u8DL-RE 零基础实操手册下一篇如何快速上手sniffer5分钟学会这款高效网络流量分析工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考