forked from ember-cli/eslint-plugin-ember
-
Notifications
You must be signed in to change notification settings - Fork 0
BUGFIX: template-no-invalid-role — support DPUB/Graphics-ARIA and role-fallback lists #55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from 7 commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
0c1d701
fix(template-no-invalid-role): source valid roles from aria-query; su…
johanrd 8ec2054
fix: template-no-autofocus-attribute — value-aware + <dialog> exception
johanrd bcabf34
chore: drop temporal 'previously flagged' comment
johanrd 6588862
docs: document <dialog> and falsy-value exceptions
johanrd b99708a
test: add Phase 3 audit fixture translating aria-role peer cases
johanrd 823631f
fix(template-no-invalid-role): drop unsupported ARIA 1.3 allowlist to…
johanrd 1670293
fix(template-no-autofocus-attribute): align value-aware check with HT…
johanrd 6d4fcda
docs: cite Glimmer VM source verifying autofocus={{false}} omits attr…
johanrd d0844e1
fix: apply <dialog> exemption to mustache form + update comment (Copi…
johanrd 39d2d27
fix: add 3 missing ARIA 1.3 roles + report specific offending token (…
johanrd 7e45da3
docs: correct audit-fixture CI-run claim (Copilot review)
johanrd c2a4128
docs: address Copilot review wording (PR #32)
johanrd f4b5b49
fix(template-no-invalid-role): flag presentation/none only when it's …
johanrd 0a3d1da
lint: reorder test-case properties to [code, output, options, errors]
johanrd c97a131
fix(#32): address round-2 Copilot review (document hash-pair opt-out;…
johanrd a3a3884
fix(#55): address round-2 Copilot review (correct audit-fixture heade…
johanrd 57f55fc
fix(template-no-autofocus-attribute): narrow mustache check to native…
johanrd 7ca1edc
lint: normalize string quotes to single per quotes rule
johanrd 909e56d
fix(template-no-invalid-role): preserve author casing in invalid-role…
johanrd 5919767
test(template-no-invalid-role): absorb audit-fixture cases, drop audi…
johanrd 41087e0
fix(template-no-invalid-role): flag empty / whitespace-only role attr…
johanrd 30ce5df
Merge pull request #2743 from johanrd/fix/autofocus-value-aware-and-d…
NullVoxPopuli f25c34e
chore(deps): update node.js to v24.15.0 (#2740)
renovate[bot] e34533b
Merge branch 'master' into fix/invalid-role-aria-query
johanrd File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,159 @@ | ||
| // Audit fixture — translates peer-plugin test cases into assertions against | ||
| // our rule (`ember/template-no-invalid-role` + `ember/template-no-abstract-roles`). | ||
|
johanrd marked this conversation as resolved.
Outdated
|
||
| // Runs as part of the default Vitest suite (via the `tests/**/*.js` include | ||
| // glob) and serves double-duty: (1) auditable record of peer-parity | ||
| // divergences, (2) regression coverage pinning CURRENT behavior. Each case | ||
|
johanrd marked this conversation as resolved.
Outdated
|
||
| // encodes what OUR rule does today; divergences from upstream plugins are | ||
| // annotated as `DIVERGENCE —`. Peer-only constructs that can't be translated | ||
| // to Ember templates (JSX spread props, Vue v-bind, Angular `$event`, | ||
| // undefined-handler expression analysis) are marked `AUDIT-SKIP`. | ||
| // | ||
| // Peers covered: jsx-a11y/aria-role, vuejs-accessibility/aria-role, | ||
| // lit-a11y/aria-role. | ||
| // | ||
| // Source files (context/ checkouts): | ||
| // - eslint-plugin-jsx-a11y-main/__tests__/src/rules/aria-role-test.js | ||
| // - eslint-plugin-vuejs-accessibility-main/src/rules/__tests__/aria-role.test.ts | ||
| // - eslint-plugin-lit-a11y/tests/lib/rules/aria-role.js | ||
|
|
||
| 'use strict'; | ||
|
|
||
| const rule = require('../../../lib/rules/template-no-invalid-role'); | ||
| const RuleTester = require('eslint').RuleTester; | ||
|
|
||
| const ruleTester = new RuleTester({ | ||
| parser: require.resolve('ember-eslint-parser'), | ||
| parserOptions: { ecmaVersion: 2022, sourceType: 'module' }, | ||
| }); | ||
|
|
||
| ruleTester.run('audit:aria-role (gts)', rule, { | ||
| valid: [ | ||
| // === Upstream parity (valid in both jsx-a11y and us) === | ||
| // jsx-a11y: valid (base case, no role) | ||
| '<template><div /></template>', | ||
| '<template><div></div></template>', | ||
|
|
||
| // jsx-a11y / vue-a11y / lit-a11y: valid (concrete, non-abstract, single role) | ||
| '<template><div role="button"></div></template>', | ||
| '<template><div role="progressbar"></div></template>', | ||
| '<template><div role="navigation"></div></template>', | ||
| '<template><div role="alert"></div></template>', | ||
| '<template><div role="switch"></div></template>', | ||
|
|
||
| // Dynamic role — both plugins and we skip | ||
| '<template><div role={{this.role}}></div></template>', | ||
| '<template><div role="{{if @open "dialog" "contentinfo"}}"></div></template>', | ||
|
|
||
| // === DIVERGENCE — case-insensitivity === | ||
| // jsx-a11y: INVALID (`<div role="Button" />` is rejected, case-sensitive). | ||
| // Our rule lowercases the role before lookup; we allow this. Intentional: | ||
| // HTML attribute values are case-insensitive in many contexts, and the | ||
| // existing test suite encodes this as an explicit design choice. | ||
| '<template><div role="Button">Click</div></template>', | ||
| '<template><div role="NAVIGATION">Nav</div></template>', | ||
|
|
||
| // === Parity — space-separated multiple roles === | ||
| // jsx-a11y / vuejs-accessibility: VALID — splits on whitespace, each | ||
| // token must be a valid role. Our rule now does the same. | ||
| '<template><div role="tabpanel row"></div></template>', | ||
| '<template><section role="doc-appendix doc-bibliography"></section></template>', | ||
|
|
||
| // === Parity — DPUB-ARIA (doc-*) roles === | ||
| // jsx-a11y / vuejs-accessibility: VALID via aria-query. Our rule now | ||
| // derives VALID_ROLES from aria-query's concrete role keys, covering | ||
| // all 40+ doc-* roles. | ||
| '<template><div role="doc-abstract"></div></template>', | ||
| '<template><section role="doc-appendix"></section></template>', | ||
|
|
||
| // === Parity — Graphics-ARIA (graphics-*) roles on <svg> === | ||
| // jsx-a11y: VALID. Our rule: VALID via aria-query. | ||
| '<template><svg role="graphics-document"></svg></template>', | ||
| '<template><svg role="graphics-document document"></svg></template>', | ||
| ], | ||
|
|
||
| invalid: [ | ||
| // === Upstream parity (invalid in both jsx-a11y and us) === | ||
| { | ||
| code: '<template><div role="foobar"></div></template>', | ||
| output: null, | ||
| errors: [{ messageId: 'invalid' }], | ||
| }, | ||
| { | ||
| code: '<template><div role="datepicker"></div></template>', | ||
| output: null, | ||
| errors: [{ messageId: 'invalid' }], | ||
| }, | ||
| // jsx-a11y: invalid (`range` is an abstract role). | ||
| // Ours: `range` is not in VALID_ROLES so we flag it as "not a valid ARIA role". | ||
| // Upstream says "abstract role"; we conflate. Message wording differs. | ||
| { | ||
| code: '<template><div role="range"></div></template>', | ||
| output: null, | ||
| errors: [{ messageId: 'invalid' }], | ||
| }, | ||
|
|
||
| // === DIVERGENCE — empty role string === | ||
| // jsx-a11y: INVALID — `<div role="" />` flagged. | ||
| // vue-a11y: INVALID — same. | ||
| // Our rule: early-return on empty/whitespace role (line 229 of rule). NO FLAG. | ||
|
johanrd marked this conversation as resolved.
Outdated
|
||
| // So this case reflects OUR (non-flagging) behavior with an explicit note. | ||
| // (No invalid assertion possible here — we'd need to move this to valid, | ||
| // or fix the rule to flag.) | ||
|
|
||
| // === Parity — space-separated with at least one invalid token === | ||
| // jsx-a11y: INVALID — splits and flags the token `foobar`. | ||
| // Our rule: splits on whitespace and now names the offending token | ||
| // specifically (`'foobar'`) rather than the whole compound string. | ||
| { | ||
| code: '<template><div role="tabpanel row foobar"></div></template>', | ||
| output: null, | ||
| errors: [{ messageId: 'invalid' }], | ||
| }, | ||
| ], | ||
| }); | ||
|
|
||
| // === DIVERGENCE — empty role string (captured as valid because we don't flag) === | ||
| // Intentionally isolated so the intent is clear. | ||
| ruleTester.run('audit:aria-role empty string (gts)', rule, { | ||
| valid: [ | ||
| // jsx-a11y + vue-a11y both flag this. We don't. This captures OUR behavior. | ||
| '<template><div role=""></div></template>', | ||
| ], | ||
| invalid: [], | ||
| }); | ||
|
|
||
| const hbsRuleTester = new RuleTester({ | ||
| parser: require.resolve('ember-eslint-parser/hbs'), | ||
| parserOptions: { ecmaVersion: 2022, sourceType: 'module' }, | ||
| }); | ||
|
|
||
| hbsRuleTester.run('audit:aria-role (hbs)', rule, { | ||
| valid: [ | ||
| '<div></div>', | ||
| '<div role="button"></div>', | ||
| '<div role="navigation"></div>', | ||
| // DIVERGENCE case-insensitivity (see gts section). | ||
| '<div role="Button"></div>', | ||
| // DIVERGENCE empty string (we don't flag). | ||
| '<div role=""></div>', | ||
| // Parity — space-separated all-valid tokens. | ||
| '<div role="tabpanel row"></div>', | ||
| // Parity — DPUB-ARIA. | ||
| '<div role="doc-abstract"></div>', | ||
| // Parity — Graphics-ARIA on <svg>. | ||
| '<svg role="graphics-document"></svg>', | ||
| ], | ||
| invalid: [ | ||
| { | ||
| code: '<div role="foobar"></div>', | ||
| output: null, | ||
| errors: [{ messageId: 'invalid' }], | ||
| }, | ||
| // Parity — compound with at least one invalid token. | ||
| { | ||
| code: '<div role="tabpanel row foobar"></div>', | ||
| output: null, | ||
| errors: [{ messageId: 'invalid' }], | ||
| }, | ||
| ], | ||
| }); | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.