Conversation
…aria-labelledby/alt Before: for <input type="image">, <object>, and <area>, the rule checked only for the PRESENCE of an accessible-name fallback attribute (aria-label / aria-labelledby / alt / title). An empty-string value provides no accessible name but slipped past. Fix: add hasNonEmptyTextAttr() that requires the attribute's static value to be non-whitespace. Dynamic values (mustache, concat) remain accepted — we can't tell at lint time whether they resolve to empty. <img>'s alt handling is unchanged — alt="" is still valid there (spec-defined marker for decorative images). Nine new invalid tests cover the three elements × three fallback attrs.
Translates 41 cases from peer-plugin rules:
- jsx-a11y alt-text
- vuejs-accessibility alt-text
- lit-a11y alt-text
Fixture documents parity after this fix:
- Empty-string aria-label/aria-labelledby on <object>, <area>, and
<input type=image> is now flagged (reusing existing objectMissing /
areaMissing / inputImage messageIds).
Remaining divergences (<img alt role=presentation> accepting non-empty
alt in jsx-a11y, <img aria-label> without alt) are annotated inline.
🏎️ Benchmark Comparison
Full mitata output |
There was a problem hiding this comment.
Pull request overview
This PR tightens template-require-valid-alt-text so that empty/whitespace-only static accessible-name fallback attributes no longer satisfy the rule for elements that require an accessible name (<input type="image">, <object>, <area>), and adds regression tests (plus an audit parity fixture).
Changes:
- Add
hasNonEmptyTextAttr()/hasAnyNonEmptyTextAttr()to treat empty/whitespace-only static values as missing while still accepting dynamic values. - Update rule logic for
<input type="image">,<object>, and<area>to use the non-empty attribute checks. - Add invalid test cases for empty-string fallbacks and introduce a peer-parity audit fixture.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
lib/rules/template-require-valid-alt-text.js |
Adds non-empty fallback attribute detection and applies it to input[type=image], object, and area checks. |
tests/lib/rules/template-require-valid-alt-text.js |
Adds invalid tests asserting empty-string fallbacks are rejected for affected elements. |
tests/audit/alt-text/peer-parity.js |
Adds an audit fixture intended to track parity/divergence with peer plugins’ alt-text rules. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…verage (Copilot review) - JSDoc for hasNonEmptyTextAttr() rewritten: no longer overstates the guarantee for dynamic values, and notes that aria-labelledby IDREFs are not validated. - Added invalid-case coverage for whitespace-only aria-label / aria-labelledby / title — ACCNAME 1.2 §4.3.2 step 2D. - hasNonEmptyTextAttr() already trims static values, so the new whitespace-only cases flag without further rule changes.
There was a problem hiding this comment.
Pull request overview
Updates the template-require-valid-alt-text accessibility rule to treat empty/whitespace-only static fallback attributes as missing accessible names for elements that require one, aligning behavior more closely with ACCNAME expectations.
Changes:
- Add
hasNonEmptyTextAttr()/hasAnyNonEmptyTextAttr()and use them for<input type="image">,<object>, and<area>fallback checks. - Add new invalid test cases covering empty/whitespace-only fallbacks.
- Add an “audit fixture” test file translating peer-plugin fixtures into assertions against this rule.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
lib/rules/template-require-valid-alt-text.js |
Implements non-empty static attribute checks and applies them to relevant elements. |
tests/lib/rules/template-require-valid-alt-text.js |
Adds new invalid cases for empty/whitespace-only fallback attributes. |
tests/audit/alt-text/peer-parity.js |
Adds an audit/regression fixture that runs RuleTester against peer-parity cases. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
c4885d4 to
82022bb
Compare
…scope, area fallback test, HBS parity
There was a problem hiding this comment.
Pull request overview
This PR tightens template-require-valid-alt-text so that “accessible-name-required” elements (<input type="image">, <object>, <area>) no longer treat empty/whitespace-only static fallback attributes (e.g. aria-label="") as satisfying the rule.
Changes:
- Add
hasNonEmptyTextAttr()/hasAnyNonEmptyTextAttr()and use them for<input type="image">,<object>, and<area>fallback checks. - Expand rule test coverage (GTS + HBS) to include empty-string and whitespace-only cases.
- Add an audit fixture translating peer plugin tests into RuleTester assertions for parity/regression tracking.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| lib/rules/template-require-valid-alt-text.js | Enforces non-empty static fallback attributes for accessible-name-required elements. |
| tests/lib/rules/template-require-valid-alt-text.js | Adds invalid cases for empty/whitespace-only fallback attributes (GTS + HBS parity). |
| tests/audit/alt-text/peer-parity.js | Adds a peer-parity audit fixture executed by the Vitest glob. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Fixes an accessibility false-negative in ember/template-require-valid-alt-text by ensuring “accessible-name-required” elements are not considered valid when their fallback naming attributes are present but empty/whitespace.
Changes:
- Add a helper to treat static empty/whitespace
alt/aria-label/aria-labelledby/titleas “missing” (while still accepting dynamic values). - Expand rule tests to cover empty-string and whitespace-only fallbacks in both GJS/GTS and HBS modes.
- Add a Vitest “peer parity” audit fixture capturing current behavior and divergences vs peer plugins.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| lib/rules/template-require-valid-alt-text.js | Enforces non-empty static accessible-name fallbacks for <input type="image">, <object>, and <area>. |
| tests/lib/rules/template-require-valid-alt-text.js | Adds invalid test cases for empty/whitespace fallbacks (GJS/GTS + HBS parity). |
| tests/audit/alt-text/peer-parity.js | Introduces an audit/regression fixture translating peer-plugin cases into assertions against this rule. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…t-a11y-behavior.md (Copilot review) That doc was never checked in. Remove the dangling reference and note that divergences are captured inline (grep for 'DIVERGENCE —') plus in PR descriptions — matches how the other peer-parity fixtures describe their own divergence records.
…ared helper (Copilot review)
Extract a new `getStaticAttrValue` util that resolves literal-valued
mustaches (`{{"foo"}}`, `{{true}}`, `{{-1}}`) and single-part concat
statements (`"{{true}}"`) to their static string value. `hasNonEmptyTextAttr`
now delegates to the helper — `aria-label={{""}}` / `aria-label="{{""}}"`
normalise to the empty string and flag the same as the text-node equivalent;
genuinely dynamic values (PathExpressions, multi-part concat) still
short-circuit to "assume truthy". Closes the bypass where authors wrapped
an empty accessible name in mustaches.
Byte-identical carrier of lib/utils/static-attr-value.js across all PRs
that land it.
…op audit fixture Upstream maintainers don't want the per-PR `tests/audit/peer-parity` pattern. Port one case that pinned distinct behavior: - `<img alt=" " />` as VALID — whitespace-only alt is currently treated as decorative; jsx-a11y agrees. All other audit cases were already covered by the regular tests on this branch (extensive existing coverage of object/area/input variants, empty aria-label/labelledby, presentation-role conflicts, etc).
Note
This is part of a series where Claude has audited
eslint-plugin-emberagainst jsx-a11y, vuejs-accessibility, angular-eslint, lit-a11y and html-validate,ember-template-lint, and the HTML and WCAG specs.[Mirror of ember-cli#2730 for Copilot review]
Summary
aria-label=""contributes no accessible name per ACCNAME 1.2 §4.3.2 step 2D: "…has an aria-label attribute whose value is not undefined, not the empty string, nor, when trimmed of whitespace, is not the empty string." Emptyaria-labelledby=""likewise contributes no name per ACCNAME 1.2 §4.3.2 step 2B, which requires the attribute to "contain at least one valid IDREF" — an empty value references none. Emptytitle=""provides no useful accessible name. ACCNAME 1.2 step 2I (Tooltip) literally says "if the current node has a Tooltip attribute, return its value" — there is no emptiness check at this step, so an empty title returns the empty string as a candidate name. That empty name does not satisfy the host-language conformance requirements that follow. For<input type="image">,<object>, and<area>, an accessible name is required per their HTML spec / HTML-AAM conformance requirements.<input type="image" aria-label="" />,<object aria-labelledby="" />, and<area title="" />are accepted.aria-label,aria-labelledby, andtitleon<input type="image">,<object>, and<area>. Dynamic values (mustache, concat) stay accepted — we can't know at lint time whether they resolve to empty.Fix: add
hasNonEmptyTextAttr()that requires a static value to be non-whitespace.<img>'salt=""is unchanged — an emptyalton<img>is spec-defined as a marker for decorative images.Nine new invalid tests (3 elements × 3 fallback attrs) cover the fix.
Prior art
Verified each peer in source:
alt-textariaLabelHasValue(lines 37-46) rejectsundefinedandlength === 0. Called forobject,area, andinput[type="image"]. Does NOT trim whitespace (differs from our rule which does).alt-texthasAriaLabel(node)+getElementAttributeValuetruthiness. Empty strings are falsy → flagged.alt-textisValidObjectNode/isValidAreaNode/isValidInputNodeall return true on mere attribute-name presence (same bug class this PR fixes).alt-text!elementHasAttribute(...). Also: no<object>or<area>handler — rule only checksimg,input[type=image],role="img".Audit fixture
Translated peer-plugin test fixture at
tests/audit/alt-text/peer-parity.js. Runs as part of the default Vitest suite (included via thetests/**/*.jsglob) and serves double-duty as an auditable peer-parity record and as regression coverage pinning current behavior.