From 8c40a218a244cbbfcb4b9bfcbf8f276ee02bdac3 Mon Sep 17 00:00:00 2001 From: Sebastian Silbermann Date: Fri, 24 Mar 2023 19:04:00 +0100 Subject: [PATCH] feat(ByRole): Allow filter by busy state (#1222) --- src/__tests__/ariaAttributes.js | 22 ++++++++++++++++++++++ src/queries/role.ts | 15 +++++++++++++++ src/role-helpers.js | 10 ++++++++++ types/queries.d.ts | 5 +++++ 4 files changed, 52 insertions(+) diff --git a/src/__tests__/ariaAttributes.js b/src/__tests__/ariaAttributes.js index 1ceb210d..498f21b3 100644 --- a/src/__tests__/ariaAttributes.js +++ b/src/__tests__/ariaAttributes.js @@ -36,6 +36,28 @@ test('`expanded` throws on unsupported roles', () => { ) }) +test('`busy` throws on unsupported roles', () => { + const {getByRole} = render( + `
Hello, Dave!
`, + ) + expect(() => + getByRole('none', {busy: true}), + ).toThrowErrorMatchingInlineSnapshot( + `"aria-busy" is not supported on role "none".`, + ) +}) + +test('`busy: true|false` matches `busy` regions', () => { + const {getByRole} = renderIntoDocument( + `
+
+
+
`, + ) + expect(getByRole('log', {busy: true})).toBeInTheDocument() + expect(getByRole('log', {busy: false})).toBeInTheDocument() +}) + test('`checked: true|false` matches `checked` checkboxes', () => { const {getByRole} = renderIntoDocument( `
diff --git a/src/queries/role.ts b/src/queries/role.ts index f8e976a4..5655e2ba 100644 --- a/src/queries/role.ts +++ b/src/queries/role.ts @@ -9,6 +9,7 @@ import { } from 'aria-query' import { computeAriaSelected, + computeAriaBusy, computeAriaChecked, computeAriaPressed, computeAriaCurrent, @@ -42,6 +43,7 @@ const queryAllByRole: AllByRole = ( description, queryFallbacks = false, selected, + busy, checked, pressed, current, @@ -61,6 +63,16 @@ const queryAllByRole: AllByRole = ( } } + if (busy !== undefined) { + // guard against unknown roles + if ( + allRoles.get(role as ARIARoleDefinitionKey)?.props['aria-busy'] === + undefined + ) { + throw new Error(`"aria-busy" is not supported on role "${role}".`) + } + } + if (checked !== undefined) { // guard against unknown roles if ( @@ -152,6 +164,9 @@ const queryAllByRole: AllByRole = ( if (selected !== undefined) { return selected === computeAriaSelected(element) } + if (busy !== undefined) { + return busy === computeAriaBusy(element) + } if (checked !== undefined) { return checked === computeAriaChecked(element) } diff --git a/src/role-helpers.js b/src/role-helpers.js index 500bcdd2..7a8f3c82 100644 --- a/src/role-helpers.js +++ b/src/role-helpers.js @@ -240,6 +240,15 @@ function computeAriaSelected(element) { return checkBooleanAttribute(element, 'aria-selected') } +/** + * @param {Element} element - + * @returns {boolean} - + */ +function computeAriaBusy(element) { + // https://www.w3.org/TR/wai-aria-1.1/#aria-busy + return element.getAttribute('aria-busy') === 'true' +} + /** * @param {Element} element - * @returns {boolean | undefined} - false/true if (not)checked, undefined if not checked-able @@ -333,6 +342,7 @@ export { prettyRoles, isInaccessible, computeAriaSelected, + computeAriaBusy, computeAriaChecked, computeAriaPressed, computeAriaCurrent, diff --git a/types/queries.d.ts b/types/queries.d.ts index cea02365..c6568abf 100644 --- a/types/queries.d.ts +++ b/types/queries.d.ts @@ -80,6 +80,11 @@ export interface ByRoleOptions { * selected in the accessibility tree, i.e., `aria-selected="true"` */ selected?: boolean + /** + * If true only includes elements in the query set that are marked as + * busy in the accessibility tree, i.e., `aria-busy="true"` + */ + busy?: boolean /** * If true only includes elements in the query set that are marked as * checked in the accessibility tree, i.e., `aria-checked="true"`