@@ -71,21 +71,20 @@ ruleTester.run('audit:role-has-required-aria (gts)', rule, {
7171 // jsx-a11y / angular / ours all flag these pairings (captured in the
7272 // `invalid` section below).
7373
74- // === DIVERGENCE — space-separated role tokens ===
75- // jsx-a11y + vue: split on whitespace, validate each token. If every token
76- // is a valid role, require attrs for each.
77- // Our rule: looks up the whole string in aria-query. `"combobox listbox"`
78- // is not a role → returns null → no missing attrs → NO FLAG.
79- // Net: jsx-a11y would flag `<div role= "combobox listbox">` ( missing attrs
80- // for both), we don't. Captured as valid below.
81- '<template><div role="combobox listbox" /></template>' ,
74+ // === Parity — space-separated role tokens ===
75+ // jsx-a11y + vue: split on whitespace, validate each token.
76+ // Our rule (post-PR): split on whitespace, walk for first RECOGNISED
77+ // (non-abstract) role per WAI-ARIA §4.1 fallback. Diverges slightly —
78+ // we validate only the PRIMARY (first recognised); peers validate
79+ // every token. For ` "combobox listbox"`, we flag missing aria-expanded
80+ // /aria-controls for combobox; jsx-a11y also flags listbox's required
81+ // aria-controls separately. Still: both flag. Captured below in invalid.
8282
83- // === DIVERGENCE — case-insensitivity on role value ===
83+ // === Parity — case-insensitivity on role value ===
8484 // jsx-a11y + vue + angular: lowercase the role value before lookup.
85- // `<div role="COMBOBOX" />` → INVALID (missing aria-expanded/controls).
86- // Our rule: passes the raw string; aria-query lookup misses → no flag.
87- '<template><div role="COMBOBOX" /></template>' ,
88- '<template><div role="SLIDER" /></template>' ,
85+ // Our rule (post-PR): same — splitRoleTokens() lowercases before
86+ // walking. `<div role="COMBOBOX" />` flags as combobox. Captured
87+ // below in invalid.
8988 ] ,
9089
9190 invalid : [
@@ -156,6 +155,24 @@ ruleTester.run('audit:role-has-required-aria (gts)', rule, {
156155 output : null ,
157156 errors : [ { messageId : 'missingAttributes' } ] ,
158157 } ,
158+ // Role-fallback list: split on whitespace, validate the first recognised
159+ // role (combobox). Matches jsx-a11y's detection on this case.
160+ {
161+ code : '<template><div role="combobox listbox" /></template>' ,
162+ output : null ,
163+ errors : [ { messageId : 'missingAttributes' } ] ,
164+ } ,
165+ // Case-insensitive role matching — uppercase values resolve the same.
166+ {
167+ code : '<template><div role="COMBOBOX" /></template>' ,
168+ output : null ,
169+ errors : [ { messageId : 'missingAttributes' } ] ,
170+ } ,
171+ {
172+ code : '<template><div role="SLIDER" /></template>' ,
173+ output : null ,
174+ errors : [ { messageId : 'missingAttributes' } ] ,
175+ } ,
159176 ] ,
160177} ) ;
161178
@@ -173,12 +190,7 @@ hbsRuleTester.run('audit:role-has-required-aria (hbs)', rule, {
173190 // Parity: axobject-query-backed semantic-role exemptions.
174191 '<input type="checkbox" role="switch" />' ,
175192 '<input type="range" role="slider" />' ,
176- // DIVERGENCES captured as valid-for-us:
177- // space-separated
178- '<div role="combobox listbox" />' ,
179- // case-insensitivity
180- '<div role="COMBOBOX" />' ,
181- // unknown role
193+ // Unknown role — both peers and ours allow (no required-attrs check).
182194 '<div role="foobar" />' ,
183195 ] ,
184196 invalid : [
@@ -211,5 +223,17 @@ hbsRuleTester.run('audit:role-has-required-aria (hbs)', rule, {
211223 output : null ,
212224 errors : [ { messageId : 'missingAttributes' } ] ,
213225 } ,
226+ // Role-fallback list — first recognised role (combobox) missing attrs.
227+ {
228+ code : '<div role="combobox listbox" />' ,
229+ output : null ,
230+ errors : [ { messageId : 'missingAttributes' } ] ,
231+ } ,
232+ // Case-insensitive role matching.
233+ {
234+ code : '<div role="COMBOBOX" />' ,
235+ output : null ,
236+ errors : [ { messageId : 'missingAttributes' } ] ,
237+ } ,
214238 ] ,
215239} ) ;
0 commit comments