Skip to content

Commit fbbb29a

Browse files
savcni01eps1lon
andauthored
feat(ByRole): Allow filter by aria-current state (#943)
Co-authored-by: eps1lon <[email protected]>
1 parent d03f4f6 commit fbbb29a

File tree

4 files changed

+58
-0
lines changed

4 files changed

+58
-0
lines changed

src/__tests__/ariaAttributes.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,31 @@ test('`pressed: true|false` matches `pressed` elements with proper role', () =>
177177
expect(getByRole('button', {pressed: false})).toBeInTheDocument()
178178
})
179179

180+
test.each([
181+
['true', true],
182+
['false', false],
183+
['date', 'date'],
184+
['location', 'location'],
185+
['page', 'page'],
186+
['step', 'step'],
187+
['time', 'time'],
188+
])(
189+
'`aria-current="%s"` matches `current: %j` elements with proper role',
190+
(ariaCurrentValue, filterByValue) => {
191+
const {getByRole} = renderIntoDocument(
192+
` <a href="/" aria-current="${ariaCurrentValue}"></a>`,
193+
)
194+
expect(getByRole('link', {current: filterByValue})).toBeInTheDocument()
195+
},
196+
)
197+
198+
test('Missing `aria-current` matches `current: false`', () => {
199+
const {getByRole} = renderIntoDocument(
200+
`<a aria-current="true" href="/">Start</a><a href="/about">About</a>`,
201+
)
202+
expect(getByRole('link', {current: false})).toBeInTheDocument()
203+
})
204+
180205
test('`level` matches elements with `heading` role', () => {
181206
const {getAllByRole, queryByRole} = renderIntoDocument(
182207
`<div>

src/queries/role.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
computeAriaSelected,
55
computeAriaChecked,
66
computeAriaPressed,
7+
computeAriaCurrent,
78
computeAriaExpanded,
89
computeHeadingLevel,
910
getImplicitAriaRoles,
@@ -35,6 +36,7 @@ function queryAllByRole(
3536
selected,
3637
checked,
3738
pressed,
39+
current,
3840
level,
3941
expanded,
4042
} = {},
@@ -64,6 +66,16 @@ function queryAllByRole(
6466
}
6567
}
6668

69+
if (current !== undefined) {
70+
/* istanbul ignore next */
71+
// guard against unknown roles
72+
// All currently released ARIA versions support `aria-current` on all roles.
73+
// Leaving this for symetry and forward compatibility
74+
if (allRoles.get(role)?.props['aria-current'] === undefined) {
75+
throw new Error(`"aria-current" is not supported on role "${role}".`)
76+
}
77+
}
78+
6779
if (level !== undefined) {
6880
// guard against using `level` option with any role other than `heading`
6981
if (role !== 'heading') {
@@ -124,6 +136,9 @@ function queryAllByRole(
124136
if (pressed !== undefined) {
125137
return pressed === computeAriaPressed(element)
126138
}
139+
if (current !== undefined) {
140+
return current === computeAriaCurrent(element)
141+
}
127142
if (expanded !== undefined) {
128143
return expanded === computeAriaExpanded(element)
129144
}

src/role-helpers.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,19 @@ function computeAriaPressed(element) {
247247
return checkBooleanAttribute(element, 'aria-pressed')
248248
}
249249

250+
/**
251+
* @param {Element} element -
252+
* @returns {boolean | string | null} -
253+
*/
254+
function computeAriaCurrent(element) {
255+
// https://www.w3.org/TR/wai-aria-1.1/#aria-current
256+
return (
257+
checkBooleanAttribute(element, 'aria-current') ??
258+
element.getAttribute('aria-current') ??
259+
false
260+
)
261+
}
262+
250263
/**
251264
* @param {Element} element -
252265
* @returns {boolean | undefined} - false/true if (not)expanded, undefined if not expand-able
@@ -301,6 +314,7 @@ export {
301314
computeAriaSelected,
302315
computeAriaChecked,
303316
computeAriaPressed,
317+
computeAriaCurrent,
304318
computeAriaExpanded,
305319
computeHeadingLevel,
306320
}

types/queries.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ export interface ByRoleOptions extends MatcherOptions {
8888
* pressed in the accessibility tree, i.e., `aria-pressed="true"`
8989
*/
9090
pressed?: boolean
91+
/**
92+
* Filters elements by their `aria-current` state. `true` and `false` match `aria-current="true"` and `aria-current="false"` (as well as a missing `aria-current` attribute) respectively.
93+
*/
94+
current?: boolean | string
9195
/**
9296
* If true only includes elements in the query set that are marked as
9397
* expanded in the accessibility tree, i.e., `aria-expanded="true"`

0 commit comments

Comments
 (0)