Skip to content

Commit

Permalink
Add label to Accordion (#2614)
Browse files Browse the repository at this point in the history
* add 'aria-label' and 'aria-labelledby' to Accordion

* cleanup a11y tests

* add mutationobserver-shim

* update Accordion a11y failing test

* improve Accordion expand/collapse tests
  • Loading branch information
katarzynatobis authored Jan 3, 2023
1 parent a78db77 commit 6c37f47
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 53 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"jest": "^24.0.0",
"jest-axe": "^5.0.1",
"mini-css-extract-plugin": "1.6.2",
"mutationobserver-shim": "^0.3.7",
"polished": "^4.0.3",
"postcss": "^8.4.5",
"postcss-loader": "^4.1.0",
Expand Down
2 changes: 2 additions & 0 deletions scripts/testsPolyfill.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'mutationobserver-shim';

global.requestAnimationFrame = callback => {
setTimeout(callback, 0);
};
75 changes: 54 additions & 21 deletions src/components/accordion/Accordion.a11y.spec.jsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,11 @@
import * as React from 'react';
import {render, waitForElementToBeRemoved} from '@testing-library/react';
import {render, waitFor, fireEvent} from '@testing-library/react';
import Accordion from './Accordion';
import AccordionItem from './AccordionItem';
import {testA11y} from '../../axe';
import userEvent from '@testing-library/user-event';

describe('Accordion a11y', () => {
it('renders accordion with expanded and collapsed items', async () => {
const accordionIds = ['id-1', 'id-2'];

await testA11y(
<Accordion defaultExpanded={accordionIds[0]}>
{accordionIds.map(id => (
<AccordionItem title={id} id={id} key={id}>
Accordion Item Description
</AccordionItem>
))}
</Accordion>
);
});

describe('Accordion', () => {
it('renders with named items', () => {
const title = 'Item_1';
const accordion = render(
Expand All @@ -40,7 +26,7 @@ describe('Accordion a11y', () => {
);
});

it('expands and collapses item on Enter/Space keydown', async () => {
it('expands and collapses item on click', async () => {
const accordionId = 'id-1';
const accordion = render(
<Accordion>
Expand All @@ -52,17 +38,64 @@ describe('Accordion a11y', () => {
const item = accordion.getByRole('button');

expect(item.getAttribute('aria-expanded')).toEqual('false');
expect(accordion.queryByRole('region')).toBeFalsy();
expect(accordion.queryByRole('region')).toBeNull();
accordion.getByRole('button').click();

expect(item.getAttribute('aria-expanded')).toEqual('true');
await waitFor(() => expect(accordion.getByRole('region')).toBeTruthy());

accordion.getByRole('button').click();

expect(item.getAttribute('aria-expanded')).toEqual('false');
fireEvent(accordion.queryByRole('region'), new Event('transitionend'));
await waitFor(() => expect(accordion.queryByRole('region')).toBeNull());
});

it('expands and collapses item on Enter/Space keydown when motion is reduced', async () => {
const accordionId = 'id-1';
const accordion = render(
<Accordion reduceMotion>
<AccordionItem title={accordionId} id={accordionId}>
Accordion Item Description
</AccordionItem>
</Accordion>
);
const item = accordion.getByRole('button');

expect(item.getAttribute('aria-expanded')).toEqual('false');
expect(accordion.queryByRole('region')).toBeNull();
accordion.getByRole('button').focus();
expect(item).toEqual(document.activeElement);
userEvent.keyboard('{enter}');

userEvent.keyboard('{enter}');
expect(item.getAttribute('aria-expanded')).toEqual('true');
expect(accordion.getByRole('region')).toBeTruthy();

userEvent.keyboard('{space}');

expect(item.getAttribute('aria-expanded')).toEqual('false');
waitForElementToBeRemoved(accordion.queryByRole('region'));
expect(accordion.queryByRole('region')).toBeNull();
});

it('has an accessible name', () => {
const label = 'Accordion name';
const accordion = render(<Accordion aria-label={label} />);

expect(accordion.getByLabelText(label)).toBeTruthy();
});
});

describe('Accordion a11y', () => {
it('should have no a11y violations when renders Accordion with expanded and collapsed items', async () => {
const accordionIds = ['id-1', 'id-2'];

await testA11y(
<Accordion defaultExpanded={accordionIds[0]}>
{accordionIds.map(id => (
<AccordionItem title={id} id={id} key={id}>
Accordion Item Description
</AccordionItem>
))}
</Accordion>
);
});
});
6 changes: 6 additions & 0 deletions src/components/accordion/Accordion.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ export type AccordionPropsType = $ReadOnly<{
expanded?: string | Array<string>,
defaultExpanded?: string | Array<string>,
onChange?: string => void,
'aria-label'?: string,
'aria-labelledby'?: string,
}>;

type ContextType = {
Expand All @@ -89,6 +91,8 @@ const Accordion = ({
defaultExpanded,
expanded,
onChange,
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledby,
}: AccordionPropsType) => {
const wrapperRef = useRef<HTMLDivElement | null>(null);
const isControlled = expanded !== undefined;
Expand Down Expand Up @@ -305,6 +309,8 @@ const Accordion = ({
),
className
)}
aria-label={ariaLabel}
aria-labelledby={ariaLabelledby}
>
{children}
</div>
Expand Down
6 changes: 4 additions & 2 deletions src/components/accordion/stories/rules.a11y.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
const rules = [
{
pattern: '<b>Can</b> have an accessible name.',
status: 'TO DO',
tests: 'TO DO',
comment: `Can be named by a label specified by <code>aria-label</code> prop or a value
(<code>IDREF</code>) set for the <code>aria-labelledby</code> prop that refers to an element.`,
status: 'DONE',
tests: 'DONE',
},
];

Expand Down
70 changes: 40 additions & 30 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
# yarn lockfile v1


"@adobe/css-tools@^4.0.1":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.0.1.tgz#b38b444ad3aa5fedbb15f2f746dcd934226a12dd"
integrity sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g==

"@ampproject/remapping@^2.0.0":
version "2.0.2"
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.0.2.tgz#f3d9760bf30588c51408dbe7c05ff2bb13069307"
Expand Down Expand Up @@ -4773,9 +4778,9 @@
resolve-from "^5.0.0"

"@testing-library/dom@^8.0.0", "@testing-library/dom@^8.11.1":
version "8.11.1"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.11.1.tgz#03fa2684aa09ade589b460db46b4c7be9fc69753"
integrity sha512-3KQDyx9r0RKYailW2MiYrSSKEfH0GTkI51UGEvJenvcoDoeRYs0PZpi2SXqtnMClQvCqdtTTpOfFETDTVADpAg==
version "8.19.0"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.19.0.tgz#bd3f83c217ebac16694329e413d9ad5fdcfd785f"
integrity sha512-6YWYPPpxG3e/xOo6HIWwB/58HukkwIVTOaZ0VwdMVjhRUX/01E4FtQbck9GazOOj7MXHc5RBzMrU86iBJHbI+A==
dependencies:
"@babel/code-frame" "^7.10.4"
"@babel/runtime" "^7.12.5"
Expand All @@ -4801,35 +4806,36 @@
pretty-format "^27.0.2"

"@testing-library/jest-dom@^5.16.4":
version "5.16.4"
resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.16.4.tgz#938302d7b8b483963a3ae821f1c0808f872245cd"
integrity sha512-Gy+IoFutbMQcky0k+bqqumXZ1cTGswLsFqmNLzNdSKkU9KGV2u9oXhukCbbJ9/LRPKiqwxEE8VpV/+YZlfkPUA==
version "5.16.5"
resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz#3912846af19a29b2dbf32a6ae9c31ef52580074e"
integrity sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==
dependencies:
"@adobe/css-tools" "^4.0.1"
"@babel/runtime" "^7.9.2"
"@types/testing-library__jest-dom" "^5.9.1"
aria-query "^5.0.0"
chalk "^3.0.0"
css "^3.0.0"
css.escape "^1.5.1"
dom-accessibility-api "^0.5.6"
lodash "^4.17.15"
redent "^3.0.0"

"@testing-library/react-hooks@^8.0.0":
version "8.0.0"
resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-8.0.0.tgz#7d0164bffce4647f506039de0a97f6fcbd20f4bf"
integrity sha512-uZqcgtcUUtw7Z9N32W13qQhVAD+Xki2hxbTR461MKax8T6Jr8nsUvZB+vcBTkzY2nFvsUet434CsgF0ncW2yFw==
version "8.0.1"
resolved "https://registry.yarnpkg.com/@testing-library/react-hooks/-/react-hooks-8.0.1.tgz#0924bbd5b55e0c0c0502d1754657ada66947ca12"
integrity sha512-Aqhl2IVmLt8IovEVarNDFuJDVWVvhnr9/GCU6UUnrYXwgDFF9h2L2o2P9KBni1AST5sT6riAyoukFLyjQUgD/g==
dependencies:
"@babel/runtime" "^7.12.5"
react-error-boundary "^3.1.0"

"@testing-library/react@^12.1.2":
version "12.1.2"
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-12.1.2.tgz#f1bc9a45943461fa2a598bb4597df1ae044cfc76"
integrity sha512-ihQiEOklNyHIpo2Y8FREkyD1QAea054U0MVbwH1m8N9TxeFz+KoJ9LkqoKqJlzx2JDm56DVwaJ1r36JYxZM05g==
version "12.1.5"
resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-12.1.5.tgz#bb248f72f02a5ac9d949dea07279095fa577963b"
integrity sha512-OfTXCJUFgjd/digLUuPxa0+/3ZxsQmE7ub9kcbW/wi96Bh3o/p5vrETcBGfP17NWPGqeYYl5LTRpwyGoMC4ysg==
dependencies:
"@babel/runtime" "^7.12.5"
"@testing-library/dom" "^8.0.0"
"@types/react-dom" "<18.0.0"

"@testing-library/user-event@^13.2.1", "@testing-library/user-event@^13.5.0":
version "13.5.0"
Expand Down Expand Up @@ -5079,6 +5085,13 @@
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb"
integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==

"@types/react-dom@<18.0.0":
version "17.0.18"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.18.tgz#8f7af38f5d9b42f79162eea7492e5a1caff70dc2"
integrity sha512-rLVtIfbwyur2iFKykP2w0pl/1unw26b5td16d5xMgp7/yjTHomkyxPYChFoCr/FtEX1lN9wY6lFj1qvKdS5kDw==
dependencies:
"@types/react" "^17"

"@types/react-dom@^16.2.0":
version "16.9.17"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.17.tgz#29100cbcc422d7b7dba7de24bb906de56680dd34"
Expand All @@ -5095,6 +5108,15 @@
"@types/scheduler" "*"
csstype "^3.0.2"

"@types/react@^17":
version "17.0.52"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.52.tgz#10d8b907b5c563ac014a541f289ae8eaa9bf2e9b"
integrity sha512-vwk8QqVODi0VaZZpDXQCmEmiOuyjEFPY7Ttaw5vjM112LOq37yz1CDJGrRJwA1fYEq4Iitd5rnjd1yWAc/bT+A==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"

"@types/scheduler@*":
version "0.16.2"
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
Expand Down Expand Up @@ -8258,15 +8280,6 @@ [email protected], css@^2.2.1:
source-map-resolve "^0.5.2"
urix "^0.1.0"

css@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/css/-/css-3.0.0.tgz#4447a4d58fdd03367c516ca9f64ae365cee4aa5d"
integrity sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==
dependencies:
inherits "^2.0.4"
source-map "^0.6.1"
source-map-resolve "^0.6.0"

cssesc@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
Expand Down Expand Up @@ -14517,6 +14530,11 @@ mustache@^2.3.0:
resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.2.tgz#a6d4d9c3f91d13359ab889a812954f9230a3d0c5"
integrity sha512-KpMNwdQsYz3O/SBS1qJ/o3sqUJ5wSb8gb0pul8CO0S56b9Y2ALm8zCfsjPXsqGFfoNBkDwZuZIAjhsZI03gYVQ==

mutationobserver-shim@^0.3.7:
version "0.3.7"
resolved "https://registry.yarnpkg.com/mutationobserver-shim/-/mutationobserver-shim-0.3.7.tgz#8bf633b0c0b0291a1107255ed32c13088a8c5bf3"
integrity sha512-oRIDTyZQU96nAiz2AQyngwx1e89iApl2hN5AOYwyxLUB47UYsU3Wv9lJWqH5y/QdiYkc5HQLi23ZNB3fELdHcQ==

mute-stdout@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mute-stdout/-/mute-stdout-1.0.1.tgz#acb0300eb4de23a7ddeec014e3e96044b3472331"
Expand Down Expand Up @@ -17909,14 +17927,6 @@ source-map-resolve@^0.5.0, source-map-resolve@^0.5.2:
source-map-url "^0.4.0"
urix "^0.1.0"

source-map-resolve@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.6.0.tgz#3d9df87e236b53f16d01e58150fc7711138e5ed2"
integrity sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==
dependencies:
atob "^2.1.2"
decode-uri-component "^0.2.0"

source-map-support@^0.4.15:
version "0.4.18"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f"
Expand Down

0 comments on commit 6c37f47

Please sign in to comment.