Skip to content

Commit b99708a

Browse files
committed
test: add Phase 3 audit fixture translating aria-role peer cases
Translates 32 cases from peer-plugin rules: - jsx-a11y aria-role - vuejs-accessibility aria-role - lit-a11y aria-role Fixture documents parity after this fix: - DPUB-ARIA and Graphics-ARIA roles accepted (via aria-query). - Space-separated role tokens accepted when all are valid, and the invalid-token variant names the specific offending token. Remaining divergences (case-insensitive comparison, empty-string role not flagged) are annotated inline.
1 parent bcabf34 commit b99708a

1 file changed

Lines changed: 154 additions & 0 deletions

File tree

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// Audit fixture — translated test cases from peer plugins to measure
2+
// behavioral parity of `ember/template-no-invalid-role` (+ `ember/template-no-abstract-roles`)
3+
// against jsx-a11y/aria-role, vuejs-accessibility/aria-role, lit-a11y/aria-role.
4+
//
5+
// These tests are NOT part of the main suite and do not run in CI. They encode
6+
// the CURRENT behavior of our rule so that running this file reports pass.
7+
// Each divergence from an upstream plugin is annotated as "DIVERGENCE —".
8+
//
9+
// Source files (context/ checkouts):
10+
// - eslint-plugin-jsx-a11y-main/__tests__/src/rules/aria-role-test.js
11+
// - eslint-plugin-vuejs-accessibility-main/src/rules/__tests__/aria-role.test.ts
12+
// - eslint-plugin-lit-a11y/tests/lib/rules/aria-role.js
13+
14+
'use strict';
15+
16+
const rule = require('../../../lib/rules/template-no-invalid-role');
17+
const RuleTester = require('eslint').RuleTester;
18+
19+
const ruleTester = new RuleTester({
20+
parser: require.resolve('ember-eslint-parser'),
21+
parserOptions: { ecmaVersion: 2022, sourceType: 'module' },
22+
});
23+
24+
ruleTester.run('audit:aria-role (gts)', rule, {
25+
valid: [
26+
// === Upstream parity (valid in both jsx-a11y and us) ===
27+
// jsx-a11y: valid (base case, no role)
28+
'<template><div /></template>',
29+
'<template><div></div></template>',
30+
31+
// jsx-a11y / vue-a11y / lit-a11y: valid (concrete, non-abstract, single role)
32+
'<template><div role="button"></div></template>',
33+
'<template><div role="progressbar"></div></template>',
34+
'<template><div role="navigation"></div></template>',
35+
'<template><div role="alert"></div></template>',
36+
'<template><div role="switch"></div></template>',
37+
38+
// Dynamic role — both plugins and we skip
39+
'<template><div role={{this.role}}></div></template>',
40+
'<template><div role="{{if @open "dialog" "contentinfo"}}"></div></template>',
41+
42+
// === DIVERGENCE — case-insensitivity ===
43+
// jsx-a11y: INVALID (`<div role="Button" />` is rejected, case-sensitive).
44+
// Our rule lowercases the role before lookup; we allow this. Intentional:
45+
// HTML attribute values are case-insensitive in many contexts, and the
46+
// existing test suite encodes this as an explicit design choice.
47+
'<template><div role="Button">Click</div></template>',
48+
'<template><div role="NAVIGATION">Nav</div></template>',
49+
50+
// === Parity — space-separated multiple roles ===
51+
// jsx-a11y / vuejs-accessibility: VALID — splits on whitespace, each
52+
// token must be a valid role. Our rule now does the same.
53+
'<template><div role="tabpanel row"></div></template>',
54+
'<template><section role="doc-appendix doc-bibliography"></section></template>',
55+
56+
// === Parity — DPUB-ARIA (doc-*) roles ===
57+
// jsx-a11y / vuejs-accessibility: VALID via aria-query. Our rule now
58+
// derives VALID_ROLES from aria-query's concrete role keys, covering
59+
// all 40+ doc-* roles.
60+
'<template><div role="doc-abstract"></div></template>',
61+
'<template><section role="doc-appendix"></section></template>',
62+
63+
// === Parity — Graphics-ARIA (graphics-*) roles on <svg> ===
64+
// jsx-a11y: VALID. Our rule: VALID via aria-query.
65+
'<template><svg role="graphics-document"></svg></template>',
66+
'<template><svg role="graphics-document document"></svg></template>',
67+
],
68+
69+
invalid: [
70+
// === Upstream parity (invalid in both jsx-a11y and us) ===
71+
{
72+
code: '<template><div role="foobar"></div></template>',
73+
output: null,
74+
errors: [{ messageId: 'invalid' }],
75+
},
76+
{
77+
code: '<template><div role="datepicker"></div></template>',
78+
output: null,
79+
errors: [{ messageId: 'invalid' }],
80+
},
81+
// jsx-a11y: invalid (`range` is an abstract role).
82+
// Ours: `range` is not in VALID_ROLES so we flag it as "not a valid ARIA role".
83+
// Upstream says "abstract role"; we conflate. Message wording differs.
84+
{
85+
code: '<template><div role="range"></div></template>',
86+
output: null,
87+
errors: [{ messageId: 'invalid' }],
88+
},
89+
90+
// === DIVERGENCE — empty role string ===
91+
// jsx-a11y: INVALID — `<div role="" />` flagged.
92+
// vue-a11y: INVALID — same.
93+
// Our rule: early-return on empty/whitespace role (line 229 of rule). NO FLAG.
94+
// So this case reflects OUR (non-flagging) behavior with an explicit note.
95+
// (No invalid assertion possible here — we'd need to move this to valid,
96+
// or fix the rule to flag.)
97+
98+
// === Parity — space-separated with at least one invalid token ===
99+
// jsx-a11y: INVALID — splits and flags the token `foobar`.
100+
// Our rule: splits on whitespace and now names the offending token
101+
// specifically (`'foobar'`) rather than the whole compound string.
102+
{
103+
code: '<template><div role="tabpanel row foobar"></div></template>',
104+
output: null,
105+
errors: [{ messageId: 'invalid' }],
106+
},
107+
],
108+
});
109+
110+
// === DIVERGENCE — empty role string (captured as valid because we don't flag) ===
111+
// Intentionally isolated so the intent is clear.
112+
ruleTester.run('audit:aria-role empty string (gts)', rule, {
113+
valid: [
114+
// jsx-a11y + vue-a11y both flag this. We don't. This captures OUR behavior.
115+
'<template><div role=""></div></template>',
116+
],
117+
invalid: [],
118+
});
119+
120+
const hbsRuleTester = new RuleTester({
121+
parser: require.resolve('ember-eslint-parser/hbs'),
122+
parserOptions: { ecmaVersion: 2022, sourceType: 'module' },
123+
});
124+
125+
hbsRuleTester.run('audit:aria-role (hbs)', rule, {
126+
valid: [
127+
'<div></div>',
128+
'<div role="button"></div>',
129+
'<div role="navigation"></div>',
130+
// DIVERGENCE case-insensitivity (see gts section).
131+
'<div role="Button"></div>',
132+
// DIVERGENCE empty string (we don't flag).
133+
'<div role=""></div>',
134+
// Parity — space-separated all-valid tokens.
135+
'<div role="tabpanel row"></div>',
136+
// Parity — DPUB-ARIA.
137+
'<div role="doc-abstract"></div>',
138+
// Parity — Graphics-ARIA on <svg>.
139+
'<svg role="graphics-document"></svg>',
140+
],
141+
invalid: [
142+
{
143+
code: '<div role="foobar"></div>',
144+
output: null,
145+
errors: [{ messageId: 'invalid' }],
146+
},
147+
// Parity — compound with at least one invalid token.
148+
{
149+
code: '<div role="tabpanel row foobar"></div>',
150+
output: null,
151+
errors: [{ messageId: 'invalid' }],
152+
},
153+
],
154+
});

0 commit comments

Comments
 (0)