diff --git a/jest.setup.ts b/jest.setup.ts
index 2bda4ca..6c7a1b9 100644
--- a/jest.setup.ts
+++ b/jest.setup.ts
@@ -1,6 +1,9 @@
import '@testing-library/jest-dom';
+import { toHaveNoViolations } from 'jest-axe';
jest.mock('./src/providers/RedbackUiThemeProvider/GlobalStyle.tsx', () => ({
GlobalStyle: () => null
}));
+// Ref: https://github.com/NickColley/jest-axe?tab=readme-ov-file#testing-react-with-react-testing-library
+expect.extend(toHaveNoViolations);
\ No newline at end of file
diff --git a/jest.utils.tsx b/jest.utils.tsx
index ff69b5f..56793b4 100644
--- a/jest.utils.tsx
+++ b/jest.utils.tsx
@@ -20,3 +20,4 @@ export const renderWithDeps = (component: ReactNode) => {
);
};
+
diff --git a/package-lock.json b/package-lock.json
index 49e805c..6c54475 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -36,6 +36,7 @@
"@testing-library/jest-dom": "^6.4.2",
"@testing-library/react": "^14.2.2",
"@types/jest": "^29.5.12",
+ "@types/jest-axe": "^3.5.9",
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@typescript-eslint/eslint-plugin": "^7.2.0",
@@ -49,6 +50,7 @@
"eslint-plugin-react-refresh": "^0.4.6",
"eslint-plugin-storybook": "^0.8.0",
"jest": "^29.7.0",
+ "jest-axe": "^9.0.0",
"jest-environment-jsdom": "^29.7.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
@@ -5047,6 +5049,25 @@
"pretty-format": "^29.0.0"
}
},
+ "node_modules/@types/jest-axe": {
+ "version": "3.5.9",
+ "resolved": "https://registry.npmjs.org/@types/jest-axe/-/jest-axe-3.5.9.tgz",
+ "integrity": "sha512-z98CzR0yVDalCEuhGXXO4/zN4HHuSebAukXDjTLJyjEAgoUf1H1i+sr7SUB/mz8CRS/03/XChsx0dcLjHkndoQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/jest": "*",
+ "axe-core": "^3.5.5"
+ }
+ },
+ "node_modules/@types/jest-axe/node_modules/axe-core": {
+ "version": "3.5.6",
+ "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-3.5.6.tgz",
+ "integrity": "sha512-LEUDjgmdJoA3LqklSTwKYqkjcZ4HKc4ddIYGSAiSkr46NTjzg2L9RNB+lekO9P7Dlpa87+hBtzc2Fzn/+GUWMQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/@types/jest/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
@@ -9886,6 +9907,129 @@
}
}
},
+ "node_modules/jest-axe": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/jest-axe/-/jest-axe-9.0.0.tgz",
+ "integrity": "sha512-Xt7O0+wIpW31lv0SO1wQZUTyJE7DEmnDEZeTt9/S9L5WUywxrv8BrgvTuQEqujtfaQOcJ70p4wg7UUgK1E2F5g==",
+ "dev": true,
+ "dependencies": {
+ "axe-core": "4.9.1",
+ "chalk": "4.1.2",
+ "jest-matcher-utils": "29.2.2",
+ "lodash.merge": "4.6.2"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ }
+ },
+ "node_modules/jest-axe/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/jest-axe/node_modules/axe-core": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.9.1.tgz",
+ "integrity": "sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/jest-axe/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/jest-axe/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-axe/node_modules/jest-matcher-utils": {
+ "version": "29.2.2",
+ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.2.2.tgz",
+ "integrity": "sha512-4DkJ1sDPT+UX2MR7Y3od6KtvRi9Im1ZGLGgdLFLm4lPexbTaCgJW5NN3IOXlQHF7NSHY/VHhflQ+WoKtD/vyCw==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.0.0",
+ "jest-diff": "^29.2.1",
+ "jest-get-type": "^29.2.0",
+ "pretty-format": "^29.2.1"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-axe/node_modules/pretty-format": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
+ "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
+ "dev": true,
+ "dependencies": {
+ "@jest/schemas": "^29.6.3",
+ "ansi-styles": "^5.0.0",
+ "react-is": "^18.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-axe/node_modules/pretty-format/node_modules/ansi-styles": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/jest-axe/node_modules/react-is": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
+ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
+ "dev": true
+ },
+ "node_modules/jest-axe/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/jest-changed-files": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz",
diff --git a/package.json b/package.json
index baf771b..16a1fec 100644
--- a/package.json
+++ b/package.json
@@ -50,6 +50,7 @@
"@testing-library/jest-dom": "^6.4.2",
"@testing-library/react": "^14.2.2",
"@types/jest": "^29.5.12",
+ "@types/jest-axe": "^3.5.9",
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@typescript-eslint/eslint-plugin": "^7.2.0",
@@ -63,6 +64,7 @@
"eslint-plugin-react-refresh": "^0.4.6",
"eslint-plugin-storybook": "^0.8.0",
"jest": "^29.7.0",
+ "jest-axe": "^9.0.0",
"jest-environment-jsdom": "^29.7.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/src/components/Alert/Alert.test.tsx b/src/components/Alert/Alert.test.tsx
index f5630fb..02868d9 100644
--- a/src/components/Alert/Alert.test.tsx
+++ b/src/components/Alert/Alert.test.tsx
@@ -1,6 +1,7 @@
import { screen } from '@testing-library/react';
import { renderWithDeps } from '../../../jest.utils';
import { Alert } from './Alert';
+import { axe } from 'jest-axe';
describe('', () => {
it('renders', () => {
@@ -8,4 +9,23 @@ describe('', () => {
expect( screen.getByText('Example alert')).toBeInTheDocument();
});
+
+ it('has no accessibility violations', async () => {
+ const { container } = renderWithDeps(Example alert);
+ const results = await axe(container);
+
+ expect(results).toHaveNoViolations();
+ });
+
+ describe('default theme accessibility', () => {
+ ['success', 'info', 'warning', 'error'].forEach(type => {
+ it(`has no accessibility violations for type "${type}" in default theme`, async () => {
+ // @ts-expect-error TS2322: Type string is not assignable to type 'success' | 'info' | 'warning' | 'error' | undefined
+ const { container } = renderWithDeps(Example alert);
+ const results = await axe(container);
+
+ expect(results).toHaveNoViolations();
+ });
+ });
+ });
});
diff --git a/src/components/Button/Button.test.tsx b/src/components/Button/Button.test.tsx
index cabf915..219bbdf 100644
--- a/src/components/Button/Button.test.tsx
+++ b/src/components/Button/Button.test.tsx
@@ -1,6 +1,9 @@
import { screen, fireEvent } from '@testing-library/react';
import { renderWithDeps } from '../../../jest.utils';
import { Button } from './Button';
+import { axe } from 'jest-axe';
+import { themes } from '../../themes';
+import { ThemeColor } from '../../types';
const mockClick = jest.fn();
@@ -11,6 +14,33 @@ describe('', () => {
expect(screen.getByRole('button', { name: 'Test button' })).toBeVisible();
});
+ it('has no accessibility violations (default props)', async () => {
+ const { container } = renderWithDeps(