diff --git a/package-lock.json b/package-lock.json
index b0b2f7323..2bfc7d70d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -67,7 +67,8 @@
"rollup-plugin-visualizer": "^5.9.0",
"string_decoder": "^1.3.0",
"vite": "^4.5.0",
- "vitest": "^0.34.6"
+ "vitest": "^0.34.6",
+ "vitest-axe": "^0.1.0"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -10457,6 +10458,12 @@
"version": "4.17.21",
"license": "MIT"
},
+ "node_modules/lodash-es": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
+ "dev": true
+ },
"node_modules/lodash.clonedeep": {
"version": "4.5.0",
"license": "MIT"
@@ -13939,6 +13946,35 @@
}
}
},
+ "node_modules/vitest-axe": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/vitest-axe/-/vitest-axe-0.1.0.tgz",
+ "integrity": "sha512-jvtXxeQPg8R/2ANTY8QicA5pvvdRP4F0FsVUAHANJ46YCDASie/cuhlSzu0DGcLmZvGBSBNsNuK3HqfaeknyvA==",
+ "dev": true,
+ "dependencies": {
+ "aria-query": "^5.0.0",
+ "axe-core": "^4.4.2",
+ "chalk": "^5.0.1",
+ "dom-accessibility-api": "^0.5.14",
+ "lodash-es": "^4.17.21",
+ "redent": "^3.0.0"
+ },
+ "peerDependencies": {
+ "vitest": ">=0.16.0"
+ }
+ },
+ "node_modules/vitest-axe/node_modules/chalk": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
+ "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
+ "dev": true,
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
"node_modules/vitest/node_modules/acorn": {
"version": "8.11.2",
"dev": true,
@@ -21695,6 +21731,12 @@
"lodash": {
"version": "4.17.21"
},
+ "lodash-es": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
+ "dev": true
+ },
"lodash.clonedeep": {
"version": "4.5.0"
},
@@ -23867,6 +23909,28 @@
}
}
},
+ "vitest-axe": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/vitest-axe/-/vitest-axe-0.1.0.tgz",
+ "integrity": "sha512-jvtXxeQPg8R/2ANTY8QicA5pvvdRP4F0FsVUAHANJ46YCDASie/cuhlSzu0DGcLmZvGBSBNsNuK3HqfaeknyvA==",
+ "dev": true,
+ "requires": {
+ "aria-query": "^5.0.0",
+ "axe-core": "^4.4.2",
+ "chalk": "^5.0.1",
+ "dom-accessibility-api": "^0.5.14",
+ "lodash-es": "^4.17.21",
+ "redent": "^3.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
+ "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
+ "dev": true
+ }
+ }
+ },
"w3c-xmlserializer": {
"version": "4.0.0",
"dev": true,
diff --git a/package.json b/package.json
index 9942e12c4..aee2055e0 100644
--- a/package.json
+++ b/package.json
@@ -91,7 +91,8 @@
"rollup-plugin-visualizer": "^5.9.0",
"string_decoder": "^1.3.0",
"vite": "^4.5.0",
- "vitest": "^0.34.6"
+ "vitest": "^0.34.6",
+ "vitest-axe": "^0.1.0"
},
"lint-staged": {
"*.{js,css,ts,tsx,jsx}": [
diff --git a/test/components/CivicProfileForms/BasicInfo.test.jsx b/test/components/CivicProfileForms/BasicInfo.test.jsx
index bc70244c7..73d4a1083 100644
--- a/test/components/CivicProfileForms/BasicInfo.test.jsx
+++ b/test/components/CivicProfileForms/BasicInfo.test.jsx
@@ -2,10 +2,15 @@ import React from 'react';
import { render } from '@testing-library/react';
import { expect, it, describe } from 'vitest';
import { BasicInfo } from '@components/CivicProfileForms';
+import isAccessible from '../../utils/axe';
describe('Basic Info Form', () => {
it('renders', () => {
const { getByText } = render();
expect(getByText('Basic Info')).not.toBeNull();
});
+
+ it('should be accessible', () => {
+ isAccessible(render());
+ });
});
diff --git a/test/components/CivicProfileForms/FinancialInfo.test.jsx b/test/components/CivicProfileForms/FinancialInfo.test.jsx
index a4adf2e4d..f79334772 100644
--- a/test/components/CivicProfileForms/FinancialInfo.test.jsx
+++ b/test/components/CivicProfileForms/FinancialInfo.test.jsx
@@ -2,10 +2,15 @@ import React from 'react';
import { render } from '@testing-library/react';
import { expect, it, describe } from 'vitest';
import { FinancialInfo } from '@components/CivicProfileForms';
+import isAccessible from '../../utils/axe';
describe('Financial Info Form', () => {
it('renders', () => {
const { getByText } = render();
expect(getByText('Financial Info')).not.toBeNull();
});
+
+ it('should be accessible', () => {
+ isAccessible(render());
+ });
});
diff --git a/test/components/CivicProfileForms/FormLayout.test.jsx b/test/components/CivicProfileForms/FormLayout.test.jsx
index 269072529..cfbf0b588 100644
--- a/test/components/CivicProfileForms/FormLayout.test.jsx
+++ b/test/components/CivicProfileForms/FormLayout.test.jsx
@@ -3,6 +3,7 @@ import { render } from '@testing-library/react';
import { MemoryRouter as Router } from 'react-router-dom';
import { expect, it, describe } from 'vitest';
import { FormLayout, CIVIC_FORM_LIST } from '@components/CivicProfileForms';
+import isAccessible from '../../utils/axe';
const renderLayout = (route) =>
render(
@@ -37,3 +38,7 @@ describe('Civic Form Layout', () => {
expect(queryAllByRole('link')[0].getAttribute('href')).toBe(`/${prevRoute.path}`);
});
});
+
+it('should be accessible', () => {
+ isAccessible(renderLayout(CIVIC_FORM_LIST[0].path));
+});
diff --git a/test/components/CivicProfileForms/HousingInfo.test.jsx b/test/components/CivicProfileForms/HousingInfo.test.jsx
index 6bbf85adb..845844d26 100644
--- a/test/components/CivicProfileForms/HousingInfo.test.jsx
+++ b/test/components/CivicProfileForms/HousingInfo.test.jsx
@@ -4,6 +4,7 @@ import { vi, expect, it, describe } from 'vitest';
import { HousingInfo } from '@components/CivicProfileForms';
import { useCivicProfile } from '@hooks';
import userEvent from '@testing-library/user-event';
+import isAccessible from '../../utils/axe';
vi.mock('@hooks', async () => {
const actual = await vi.importActual('@hooks');
@@ -22,6 +23,11 @@ describe('Housing info form', () => {
expect(cityField).not.toBeNull();
});
+ it('should be accessible', () => {
+ useCivicProfile.mockReturnValue({ data: {}, isSuccess: true });
+ isAccessible(render());
+ });
+
it('submits an address update when you click the submit button', async () => {
const user = userEvent.setup();
const mockAdd = vi.fn();
diff --git a/test/components/Contacts/ContactsListTable.test.jsx b/test/components/Contacts/ContactsListTable.test.jsx
index 840334563..dfd4ce846 100644
--- a/test/components/Contacts/ContactsListTable.test.jsx
+++ b/test/components/Contacts/ContactsListTable.test.jsx
@@ -4,6 +4,7 @@ import { expect, it } from 'vitest';
import { BrowserRouter } from 'react-router-dom';
import { ContactListTable } from '@components/Contacts';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
+import isAccessible from '../../utils/axe';
const queryClient = new QueryClient();
@@ -15,6 +16,25 @@ const MockTableComponent = ({ contacts }) => (
);
+// TODO: Fix accessibility issues within this component
+it.skip('should be accessible', () => {
+ const contacts = [
+ {
+ familyName: 'Abby',
+ givenName: 'Aaron',
+ person: 'Aaron Abby',
+ webId: 'https://example.com/Abby'
+ },
+ {
+ familyName: 'Builder',
+ givenName: 'Bob',
+ person: 'Bob Builder',
+ webId: 'https://example.com/Builder'
+ }
+ ];
+ isAccessible(render());
+});
+
it('renders all clients from client context', () => {
const contacts = [
{
diff --git a/test/components/Documents/DocumentTable.test.jsx b/test/components/Documents/DocumentTable.test.jsx
index 675d8bca0..e747ef800 100644
--- a/test/components/Documents/DocumentTable.test.jsx
+++ b/test/components/Documents/DocumentTable.test.jsx
@@ -3,8 +3,8 @@ import { render } from '@testing-library/react';
import { describe, expect, it } from 'vitest';
import { BrowserRouter } from 'react-router-dom';
import DocumentTable from '@components/Documents';
-
import { DocumentListContext } from '@contexts';
+import isAccessible from '../../utils/axe';
const mockedDocumentContext = {
documentListObject: {
@@ -60,4 +60,9 @@ describe('DocumentTable Component', () => {
expect(row2FileType).not.toBeNull();
expect(row2Description).not.toBeNull();
});
+
+ // TODO: Fix accessibility issues with this component
+ it.skip('should be accessible', () => {
+ isAccessible(render());
+ });
});
diff --git a/test/components/Footer/Footer.test.jsx b/test/components/Footer/Footer.test.jsx
index eed56209d..479649069 100644
--- a/test/components/Footer/Footer.test.jsx
+++ b/test/components/Footer/Footer.test.jsx
@@ -6,6 +6,7 @@ import { SessionContext } from '@contexts';
import { ThemeProvider } from '@mui/material/styles';
import theme from '../../../src/theme';
import Footer from '../../../src/components/Footer/Footer';
+import isAccessible from '../../utils/axe';
// clear created dom after each test, to start fresh for next
afterEach(() => {
@@ -28,4 +29,18 @@ describe('Footer', () => {
expect(headings.length).toBe(2);
});
+
+ it('should be accessible', () => {
+ isAccessible(
+ render(
+
+
+
+
+
+
+
+ )
+ );
+ });
});
diff --git a/test/components/Form/FormSection.test.jsx b/test/components/Form/FormSection.test.jsx
index 636301a97..212a911b1 100644
--- a/test/components/Form/FormSection.test.jsx
+++ b/test/components/Form/FormSection.test.jsx
@@ -3,6 +3,7 @@ import { render } from '@testing-library/react';
import { expect, it } from 'vitest';
import { FormSection } from '@components/Form';
import createMatchMedia from '../../helpers/createMatchMedia';
+import isAccessible from '../../utils/axe';
const MockChildrenComponent = () =>
;
@@ -12,6 +13,10 @@ const MockFormSection = () => (
);
+it('should be accessible', () => {
+ isAccessible(render());
+});
+
it('renders 20px padding by default', () => {
const component = render();
const adjustableBox = getComputedStyle(component.container.firstChild);
diff --git a/test/components/Home/HomeSection.test.jsx b/test/components/Home/HomeSection.test.jsx
index b2723ded6..386421613 100644
--- a/test/components/Home/HomeSection.test.jsx
+++ b/test/components/Home/HomeSection.test.jsx
@@ -3,6 +3,7 @@ import { render } from '@testing-library/react';
import { expect, it, describe } from 'vitest';
import { HomeSection } from '@components/Home';
import createMatchMedia from '../../helpers/createMatchMedia';
+import isAccessible from '../../utils/axe';
const MockSection = () => ;
const MockSectionDescription = () => ;
@@ -82,3 +83,30 @@ describe('Image rendering', () => {
expect(image.width).toBe('80%');
});
});
+
+describe('Accessibility', () => {
+ // TODO: Fix accessibility issues with this component
+ it.skip('should have basic rendering be accessible', () => {
+ isAccessible(render());
+ });
+
+ // TODO: Fix accessibility issues with this component
+ it.skip('should have description rendering be accessible', () => {
+ isAccessible(render());
+ });
+
+ // TODO: Fix accessibility issues with this component
+ it.skip('should have description mobile rendering be accessible', () => {
+ isAccessible(render());
+ });
+
+ // TODO: Fix accessibility issues with this component
+ it.skip('should have button rendering be accessible', () => {
+ isAccessible(render());
+ });
+
+ // TODO: Fix accessibility issues with this component
+ it.skip('should have button mobile rendering be accessible', () => {
+ isAccessible(render());
+ });
+});
diff --git a/test/components/Home/KeyFeatures.test.jsx b/test/components/Home/KeyFeatures.test.jsx
index b83a5e2c0..53989c41f 100644
--- a/test/components/Home/KeyFeatures.test.jsx
+++ b/test/components/Home/KeyFeatures.test.jsx
@@ -1,12 +1,25 @@
import React from 'react';
import { render } from '@testing-library/react';
-import { expect, it } from 'vitest';
+import { describe, expect, it } from 'vitest';
import { KeyFeatures } from '@components/Home';
import createMatchMedia from '../../helpers/createMatchMedia';
+import isAccessible from '../../utils/axe';
const MockKeyFeaturesDefault = () => ;
const MockKeyFeaturesMobile = () => ;
+describe('Accessibility', () => {
+ // TODO: Fix accessibility issues with this component
+ it.skip('should be accessible', async () => {
+ await isAccessible(render());
+ });
+
+ // TODO: Fix accessibility issues with this component
+ it.skip('should be accessible on mobile', async () => {
+ await isAccessible(render());
+ });
+});
+
it('renders less width by default', () => {
const { getByText } = render();
const description = getByText('Example Text');
diff --git a/test/components/Messages/Inbox.test.jsx b/test/components/Messages/Inbox.test.jsx
index c57842317..a92d17a26 100644
--- a/test/components/Messages/Inbox.test.jsx
+++ b/test/components/Messages/Inbox.test.jsx
@@ -9,6 +9,7 @@ import Badge from '@mui/material/Badge';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useMessageList } from '@hooks';
import { Inbox, MessagesLayout } from '@components/Messages';
+import isAccessible from '../../utils/axe';
vi.mock('@inrupt/solid-client');
@@ -109,6 +110,12 @@ describe('Messages Page', () => {
}
}
};
+
+ // TODO: Fix accessibility issues with this component
+ it.skip('should be accessible', () => {
+ isAccessible(render());
+ });
+
it('renders', () => {
const { getByText } = render();
expect(getByText('Inbox', { exact: true })).not.toBeNull();
diff --git a/test/components/Messages/MessageButtonGroup.test.jsx b/test/components/Messages/MessageButtonGroup.test.jsx
index d8d373dd9..40d82e83f 100644
--- a/test/components/Messages/MessageButtonGroup.test.jsx
+++ b/test/components/Messages/MessageButtonGroup.test.jsx
@@ -4,12 +4,18 @@ import { render } from '@testing-library/react';
import { expect, it } from 'vitest';
import { MessageButtonGroup } from '@components/Messages';
import createMatchMedia from '../../helpers/createMatchMedia';
+import isAccessible from '../../utils/axe';
const MockMessageButtonGroup = () => (
);
+
+it('should be accessible', () => {
+ isAccessible(render());
+});
+
it('renders button group as a row default', () => {
const { getByRole } = render();
const newMessageButton = getByRole('button', { name: 'New Message' });
diff --git a/test/components/Messages/MessageFolder.test.jsx b/test/components/Messages/MessageFolder.test.jsx
index cdfce2d67..bb4120a62 100644
--- a/test/components/Messages/MessageFolder.test.jsx
+++ b/test/components/Messages/MessageFolder.test.jsx
@@ -3,6 +3,7 @@ import { render } from '@testing-library/react';
import { describe, expect, it } from 'vitest';
import { MessageFolder } from '@components/Messages';
import createMatchMedia from '../../helpers/createMatchMedia';
+import isAccessible from '../../utils/axe';
const MockMessageFolder = () => ;
@@ -43,3 +44,16 @@ describe('Mobile screen', () => {
expect(cssProperty.margin).toBe('10px 20px');
});
});
+
+describe('Accessibility', () => {
+ // TODO: Fix accessibility issues with this component
+ it.skip('should be accessible', () => {
+ isAccessible(render());
+ });
+
+ // TODO: Fix accessibility issues with this component
+ it.skip('should be accessible on mobile', () => {
+ window.matchMedia = createMatchMedia(599);
+ isAccessible(render());
+ });
+});
diff --git a/test/components/Messages/MessagePreview.test.jsx b/test/components/Messages/MessagePreview.test.jsx
index 3b4bdc247..1b7d93aa9 100644
--- a/test/components/Messages/MessagePreview.test.jsx
+++ b/test/components/Messages/MessagePreview.test.jsx
@@ -4,6 +4,7 @@ import { describe, expect, it } from 'vitest';
import { MessagePreview } from '@components/Messages';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import createMatchMedia from '../../helpers/createMatchMedia';
+import isAccessible from '../../utils/axe';
const queryClient = new QueryClient();
@@ -14,6 +15,10 @@ const MockMessagePreview = () => (
);
+it('should be accessible', () => {
+ isAccessible(render());
+});
+
describe('Grid sizes', () => {
it('renders grid values 5, 5, 2 default', () => {
const { getByText } = render();
diff --git a/test/components/Messages/Outbox.test.jsx b/test/components/Messages/Outbox.test.jsx
index f715d7a13..460eb25cc 100644
--- a/test/components/Messages/Outbox.test.jsx
+++ b/test/components/Messages/Outbox.test.jsx
@@ -9,6 +9,7 @@ import Badge from '@mui/material/Badge';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useMessageList } from '@hooks';
import { Outbox, MessagesLayout } from '@components/Messages';
+import isAccessible from '../../utils/axe';
vi.mock('@inrupt/solid-client');
@@ -115,6 +116,11 @@ describe('Messages Page', () => {
expect(getByText('Outbox', { exact: true })).not.toBeNull();
});
+ // TODO: Fix accessibility issues with this component
+ it.skip('should be accessible', () => {
+ isAccessible(render());
+ });
+
it('should render messages', async () => {
const { queryByText } = render();
expect(queryByText('RE:test-inbox')).toBeNull();
diff --git a/test/components/Modals/AddContactModal.test.jsx b/test/components/Modals/AddContactModal.test.jsx
index c35b5c8f0..b68e450b8 100644
--- a/test/components/Modals/AddContactModal.test.jsx
+++ b/test/components/Modals/AddContactModal.test.jsx
@@ -5,9 +5,14 @@ import { describe, expect, it, vi } from 'vitest';
import { AddContactModal } from '@components/Modals';
import * as solidClient from '@inrupt/solid-client';
import createMatchMedia from '../../helpers/createMatchMedia';
+import isAccessible from '../../utils/axe';
const MockAddContactModal = () => ;
+it('should be accessible', () => {
+ isAccessible(render());
+});
+
it('renders button container flex-direction row default', () => {
const { getByRole } = render();
const cancelButton = getByRole('button', { name: 'Cancel' });
diff --git a/test/components/Modals/ConfirmationModal.test.jsx b/test/components/Modals/ConfirmationModal.test.jsx
index 5f80b97da..69275421d 100644
--- a/test/components/Modals/ConfirmationModal.test.jsx
+++ b/test/components/Modals/ConfirmationModal.test.jsx
@@ -4,6 +4,7 @@ import { describe, expect, it, vi } from 'vitest';
import { render } from '@testing-library/react';
import createMatchMedia from '../../helpers/createMatchMedia';
import '@testing-library/jest-dom/extend-expect';
+import isAccessible from '../../utils/axe';
const MockConfirmationModalBasic = () => (
@@ -53,6 +54,20 @@ describe('Mobile screen', () => {
});
});
+describe('Accessibility', () => {
+ // These are set to async/await so that they don't conflict with each other.
+ // `axe` requires synchronous execution, so if multiple are running at once,
+ // it can give false positives.
+ it('should be accessible', async () => {
+ await isAccessible(render());
+ });
+
+ it('should be accessible on mobile', async () => {
+ window.matchMedia = createMatchMedia(599);
+ await isAccessible(render());
+ });
+});
+
describe('Renders correct text for: ', () => {
it('title', () => {
const customTitle = 'CUSTOM TITLE';
diff --git a/test/components/Modals/NewMessageModal.test.jsx b/test/components/Modals/NewMessageModal.test.jsx
index 5146bc444..e98efd99f 100644
--- a/test/components/Modals/NewMessageModal.test.jsx
+++ b/test/components/Modals/NewMessageModal.test.jsx
@@ -7,6 +7,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
// For testing
import { sendMessageTTL } from '@utils';
import createMatchMedia from '../../helpers/createMatchMedia';
+import isAccessible from '../../utils/axe';
const queryClient = new QueryClient();
@@ -16,6 +17,10 @@ const MockNewMessageModal = () => (
);
+it('should be accessible', () => {
+ isAccessible(render());
+});
+
it('renders button group flex-direction as row default', () => {
const { getByRole } = render();
const cancelButton = getByRole('button', { name: 'Cancel' });
diff --git a/test/components/Modals/UploadButtonGroup.test.jsx b/test/components/Modals/UploadButtonGroup.test.jsx
index 869a59df3..c7a4cf0d7 100644
--- a/test/components/Modals/UploadButtonGroup.test.jsx
+++ b/test/components/Modals/UploadButtonGroup.test.jsx
@@ -3,9 +3,15 @@ import { expect, it } from 'vitest';
import { render } from '@testing-library/react';
import UploadButtonGroup from '../../../src/components/Modals/UploadButtonGroup';
import createMatchMedia from '../../helpers/createMatchMedia';
+import isAccessible from '../../utils/axe';
const MockUploadButtonGroup = () => ;
+// TODO: Fix accessibility issues with this component
+it.skip('should be accessible', () => {
+ isAccessible(render());
+});
+
it('renders only one button above 768px', () => {
const { getAllByRole } = render();
const buttons = getAllByRole('button');
diff --git a/test/components/Modals/UploadDocumentModal.test.jsx b/test/components/Modals/UploadDocumentModal.test.jsx
index 2180cb705..088013e3d 100644
--- a/test/components/Modals/UploadDocumentModal.test.jsx
+++ b/test/components/Modals/UploadDocumentModal.test.jsx
@@ -4,9 +4,14 @@ import { render } from '@testing-library/react';
import { UploadDocumentModal } from '@components/Modals';
import createMatchMedia from '../../helpers/createMatchMedia';
import '@testing-library/jest-dom/extend-expect';
+import isAccessible from '../../utils/axe';
const MockUploadDocumentModal = () => ;
+it('should be accessible', () => {
+ isAccessible(render());
+});
+
it('renders cancel/upload group as row default', () => {
const { getByRole } = render();
const cancelButton = getByRole('button', { name: 'Cancel' });
diff --git a/test/components/NavBar/NavBar.test.jsx b/test/components/NavBar/NavBar.test.jsx
index 020e17f08..a58505ccb 100644
--- a/test/components/NavBar/NavBar.test.jsx
+++ b/test/components/NavBar/NavBar.test.jsx
@@ -6,6 +6,7 @@ import { SessionContext } from '@contexts';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import createMatchMedia from '../../helpers/createMatchMedia';
import NavBar from '../../../src/components/NavBar/NavBar';
+import isAccessible from '../../utils/axe';
// clear created dom after each test, to start fresh for next
afterEach(() => {
@@ -14,6 +15,31 @@ afterEach(() => {
const queryClient = new QueryClient();
+describe('Accessibility', () => {
+ const renderExample = () =>
+ render(
+
+
+
+
+
+
+
+ );
+
+ // These are set to async/await so that they don't conflict with each other.
+ // `axe` requires synchronous execution, so if multiple are running at once,
+ // it can give false positives.
+ it('should be accessible', async () => {
+ await isAccessible(renderExample());
+ });
+
+ it('should be accessible on mobile', async () => {
+ window.matchMedia = createMatchMedia(1200);
+ await isAccessible(renderExample());
+ });
+});
+
describe('login tests', () => {
it('renders NavbarLoggedOut when user is not logged in', () => {
const { getByRole } = render(
diff --git a/test/components/NavBar/NavBarSkipLink.test.jsx b/test/components/NavBar/NavBarSkipLink.test.jsx
index 4847477b3..d2457e080 100644
--- a/test/components/NavBar/NavBarSkipLink.test.jsx
+++ b/test/components/NavBar/NavBarSkipLink.test.jsx
@@ -4,8 +4,19 @@ import { fireEvent, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { expect, describe, it } from 'vitest';
import { NavBarSkipLink } from '@components/NavBar';
+import isAccessible from '../../utils/axe';
describe('NavBarSkipLink', () => {
+ it('should be accessible', () => {
+ isAccessible(
+ render(
+
+
+
+ )
+ );
+ });
+
it('renders', () => {
render(
diff --git a/test/components/NavBar/NavMenu.test.jsx b/test/components/NavBar/NavMenu.test.jsx
index 44d0e7ab6..f59b4fa25 100644
--- a/test/components/NavBar/NavMenu.test.jsx
+++ b/test/components/NavBar/NavMenu.test.jsx
@@ -5,6 +5,7 @@ import { NavMenu } from '@components/NavBar';
import { render } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import createMatchMedia from '../../helpers/createMatchMedia';
+import isAccessible from '../../utils/axe';
const queryClient = new QueryClient();
@@ -16,6 +17,13 @@ const MockNavMenu = () => (
);
+// These are set to async/await so that they don't conflict with each other.
+// `axe` requires synchronous execution, so if multiple are running at once,
+// it can give false positives.
+it('should be accessible', async () => {
+ await isAccessible(render());
+});
+
it('does not render contacts and civic profile links above 600px', () => {
const { queryByText } = render();
@@ -26,6 +34,11 @@ it('does not render contacts and civic profile links above 600px', () => {
expect(civicProfileLink).toBeNull();
});
+it('should be accessible on mobile', async () => {
+ window.matchMedia = createMatchMedia(599);
+ await isAccessible(render());
+});
+
it('renders contacts and civic profile links below 600px', () => {
window.matchMedia = createMatchMedia(599);
const { queryByText } = render();
diff --git a/test/components/NavBar/NavbarDesktop.test.jsx b/test/components/NavBar/NavbarDesktop.test.jsx
index 72fe2de0f..537f70b2c 100644
--- a/test/components/NavBar/NavbarDesktop.test.jsx
+++ b/test/components/NavBar/NavbarDesktop.test.jsx
@@ -4,9 +4,23 @@ import { render } from '@testing-library/react';
import { expect, it } from 'vitest';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import NavbarDesktop from '../../../src/components/NavBar/NavbarDesktop';
+import isAccessible from '../../utils/axe';
const queryClient = new QueryClient();
+// TODO: Fix accessibility issues with this component
+it.skip('should be accessible', () => {
+ isAccessible(
+ render(
+
+
+
+
+
+ )
+ );
+});
+
it('renders icon menu when on screen larger than mobile', () => {
const { queryByRole } = render(
diff --git a/test/components/NavBar/NavbarLoggedOut.test.jsx b/test/components/NavBar/NavbarLoggedOut.test.jsx
index 257d0035d..25bfc2c0a 100644
--- a/test/components/NavBar/NavbarLoggedOut.test.jsx
+++ b/test/components/NavBar/NavbarLoggedOut.test.jsx
@@ -1,11 +1,38 @@
import React from 'react';
import { render } from '@testing-library/react';
-import { expect, it } from 'vitest';
+import { describe, expect, it } from 'vitest';
import { BrowserRouter } from 'react-router-dom';
import { ThemeProvider } from '@mui/material/styles';
import { NavbarLoggedOut } from '@components/NavBar';
import theme from '../../../src/theme';
import createMatchMedia from '../../helpers/createMatchMedia';
+import isAccessible from '../../utils/axe';
+
+describe('Accessibility', () => {
+ // These are set to async/await so that they don't conflict with each other.
+ // `axe` requires synchronous execution, so if multiple are running at once,
+ // it can give false positives.
+ it('should be accessible', async () => {
+ await isAccessible(
+ render(
+
+
+
+ )
+ );
+ });
+
+ it('should be accessible on mobile', async () => {
+ window.matchMedia = createMatchMedia(599);
+ await isAccessible(
+ render(
+
+
+
+ )
+ );
+ });
+});
it('renders login button when user is logged out', () => {
const { queryByRole } = render(
diff --git a/test/components/NavBar/NavbarMobile.test.jsx b/test/components/NavBar/NavbarMobile.test.jsx
index 38078c6bc..ade3b04c5 100644
--- a/test/components/NavBar/NavbarMobile.test.jsx
+++ b/test/components/NavBar/NavbarMobile.test.jsx
@@ -4,6 +4,18 @@ import { render } from '@testing-library/react';
import { expect, it } from 'vitest';
import NavbarMobile from '../../../src/components/NavBar/NavbarMobile';
import createMatchMedia from '../../helpers/createMatchMedia';
+import isAccessible from '../../utils/axe';
+
+// TODO: Fix accessibility issues with this component
+it.skip('should be accessible', () => {
+ isAccessible(
+ render(
+
+
+
+ )
+ );
+});
it('renders hamburger menu when on mobile', () => {
const { queryByRole } = render(
diff --git a/test/components/NavBar/OidcLoginComponent.test.jsx b/test/components/NavBar/OidcLoginComponent.test.jsx
index 06ee832f0..1d8f86a82 100644
--- a/test/components/NavBar/OidcLoginComponent.test.jsx
+++ b/test/components/NavBar/OidcLoginComponent.test.jsx
@@ -5,6 +5,7 @@ import React from 'react';
import { expect, it, vi, afterEach } from 'vitest';
import OidcLoginComponent from '../../../src/components/NavBar/OidcLoginComponent';
import createMatchMedia from '../../helpers/createMatchMedia';
+import isAccessible from '../../utils/axe';
vi.mock('@inrupt/solid-client-authn-browser');
@@ -26,6 +27,10 @@ vi.mock('../../../src/constants/', async () => {
};
});
+it('should be accessible', () => {
+ isAccessible(render());
+});
+
it('sets OIDC provider on login', async () => {
const user = userEvent.setup();
const { getByRole } = render();
@@ -64,6 +69,11 @@ it('renders container items as row default', () => {
expect(cssProperty.flexDirection).toBe('row');
});
+it('should be accessible on mobile', () => {
+ window.matchMedia = createMatchMedia(599);
+ isAccessible(render());
+});
+
it('renders container items as column mobile', () => {
window.matchMedia = createMatchMedia(599);
const component = render();
diff --git a/test/components/Notification/BasicNotification.test.jsx b/test/components/Notification/BasicNotification.test.jsx
index ba0aaab0e..c0ebcd527 100644
--- a/test/components/Notification/BasicNotification.test.jsx
+++ b/test/components/Notification/BasicNotification.test.jsx
@@ -4,6 +4,19 @@ import { expect, it, beforeEach, afterEach, vi } from 'vitest';
import { act } from 'react-dom/test-utils';
import BasicNotification from '../../../src/components/Notification/BasicNotification';
import { NotificationContext } from '../../../src/contexts/NotificationContext';
+import isAccessible from '../../utils/axe';
+
+beforeEach(() => {
+ vi.useFakeTimers();
+});
+
+afterEach(() => {
+ vi.useRealTimers();
+});
+
+it('should be accessible', () => {
+ isAccessible(render());
+});
it('renders correctly', () => {
const message = 'my test message';
@@ -15,14 +28,6 @@ it('renders correctly', () => {
expect(notification.textContent).toBe(message);
});
-beforeEach(() => {
- vi.useFakeTimers();
-});
-
-afterEach(() => {
- vi.useRealTimers();
-});
-
it('calls remove after 8 seconds', () => {
const remove = vi.fn();
diff --git a/test/components/Notification/NotificationContainer.test.jsx b/test/components/Notification/NotificationContainer.test.jsx
index 72472129b..e09330f4f 100644
--- a/test/components/Notification/NotificationContainer.test.jsx
+++ b/test/components/Notification/NotificationContainer.test.jsx
@@ -3,6 +3,7 @@ import { render, screen } from '@testing-library/react';
import { expect, it } from 'vitest';
import { BrowserRouter } from 'react-router-dom';
import { NotificationContainer } from '../../../src/components/Notification';
+import isAccessible from '../../utils/axe';
const MockNotificationContainer = ({ notifications }) => (
@@ -10,6 +11,15 @@ const MockNotificationContainer = ({ notifications }) => (
);
+it('should be accessible', () => {
+ const notifications = [
+ { id: 34345, message: 'this is a success', severity: 'success' },
+ { id: 45555, message: 'this is and error test', severity: 'error' },
+ { id: 32235, message: 'this is an info test', severity: 'info' }
+ ];
+ isAccessible(render());
+});
+
it('renders all the notifications from notification context', () => {
const notifications = [
{ id: 34345, message: 'this is a success', severity: 'success' },
diff --git a/test/components/Profile/ProfileComponent.test.jsx b/test/components/Profile/ProfileComponent.test.jsx
index 964f63a53..b076cb69e 100644
--- a/test/components/Profile/ProfileComponent.test.jsx
+++ b/test/components/Profile/ProfileComponent.test.jsx
@@ -7,6 +7,7 @@ import { SignedInUserContext } from '@contexts';
import * as profileHelper from '../../../src/model-helpers/Profile';
import '@testing-library/jest-dom/extend-expect';
import createMatchMedia from '../../helpers/createMatchMedia';
+import isAccessible from '../../utils/axe';
const profileInfo = {
profileName: null,
@@ -32,6 +33,20 @@ const mockSignedInUserContextMemo = {
describe('ProfileComponent', () => {
afterEach(() => cleanup());
+ // These are set to async/await so that they don't conflict with each other.
+ // `axe` requires synchronous execution, so if multiple are running at once,
+ // it can give false positives.
+ // TODO: Fix accessibility issues with this component
+ it.skip('should be accessible', async () => {
+ await isAccessible(
+ render(
+
+
+
+ )
+ );
+ });
+
it('renders cancel and update buttons after clicking on edit button from initial render', async () => {
const { queryByRole } = render(
@@ -106,6 +121,18 @@ it('renders profile component as row default', () => {
expect(cssProperty.flexDirection).toBe('row');
});
+// TODO: Fix accessibility issues with this component
+it.skip('should be accessible on mobile', async () => {
+ window.matchMedia = createMatchMedia(599);
+ await isAccessible(
+ render(
+
+
+
+ )
+ );
+});
+
it('renders profile component as column mobile', () => {
window.matchMedia = createMatchMedia(599);
const component = render(
diff --git a/test/components/Profile/ProfileImageField.test.jsx b/test/components/Profile/ProfileImageField.test.jsx
index 8a7d9e64e..adc22dddd 100644
--- a/test/components/Profile/ProfileImageField.test.jsx
+++ b/test/components/Profile/ProfileImageField.test.jsx
@@ -3,6 +3,7 @@ import { render } from '@testing-library/react';
import { describe, expect, it } from 'vitest';
import { ProfileImageField } from '../../../src/components/Profile';
import '@testing-library/jest-dom/extend-expect';
+import isAccessible from '../../utils/axe';
const MockProfileComponent = ({ noUserImage, mockContactProfile }) => {
if (!noUserImage) {
@@ -12,6 +13,11 @@ const MockProfileComponent = ({ noUserImage, mockContactProfile }) => {
};
describe('ProfileImageField', () => {
+ // TODO: Fix accessibility issues with this component
+ it.skip('should be accessible', () => {
+ isAccessible(render());
+ });
+
it('renders Choose Img button and PersonIcon if contactProfile is null and user has no profile img', () => {
const { queryByRole, queryByTestId } = render(
diff --git a/test/components/Profile/ProfileInputField.test.jsx b/test/components/Profile/ProfileInputField.test.jsx
index 99eb8d65e..638ed9408 100644
--- a/test/components/Profile/ProfileInputField.test.jsx
+++ b/test/components/Profile/ProfileInputField.test.jsx
@@ -3,6 +3,7 @@ import { render } from '@testing-library/react';
import { describe, expect, it } from 'vitest';
import { ProfileInputField } from '../../../src/components/Profile';
import '@testing-library/jest-dom/extend-expect';
+import isAccessible from '../../utils/axe';
const MockProfileComponent = ({ name }) => {
const mockInputName = 'Name';
@@ -20,6 +21,10 @@ const MockProfileComponent = ({ name }) => {
};
describe('ProfileInputField', () => {
+ it('should be accessible', () => {
+ isAccessible(render());
+ });
+
it('renders ProfileInputField with name Alice', () => {
const mockInputValue = 'Alice';
const { queryByRole } = render();
diff --git a/test/components/Signup/PodRegistrationForm.test.jsx b/test/components/Signup/PodRegistrationForm.test.jsx
index f86e816f0..7d39cfc1d 100644
--- a/test/components/Signup/PodRegistrationForm.test.jsx
+++ b/test/components/Signup/PodRegistrationForm.test.jsx
@@ -8,8 +8,19 @@ import { expect, it, describe } from 'vitest';
// Component being tested
import { PodRegistrationForm } from '@components/Signup';
+import isAccessible from '../../utils/axe';
describe('PodRegistrationForm', () => {
+ it('should be accessible', () => {
+ isAccessible(
+ render(
+
+
+
+ )
+ );
+ });
+
it('renders', () => {
render(
diff --git a/test/components/Signup/ShowNewPod.test.jsx b/test/components/Signup/ShowNewPod.test.jsx
index a5609f248..3a39760fc 100644
--- a/test/components/Signup/ShowNewPod.test.jsx
+++ b/test/components/Signup/ShowNewPod.test.jsx
@@ -4,6 +4,7 @@ import { expect, it, describe, vi } from 'vitest';
import { BrowserRouter as Router } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ShowNewPod } from '@components/Signup';
+import isAccessible from '../../utils/axe';
vi.mock('@inrupt/solid-client');
@@ -19,6 +20,18 @@ vi.mock('react-router-dom', async () => {
const queryClient = new QueryClient();
describe('ShowNewPod', () => {
+ it('should be accessible', () => {
+ isAccessible(
+ render(
+
+
+
+
+
+ )
+ );
+ });
+
it('renders', () => {
render(
diff --git a/test/helpers/test-setup.js b/test/helpers/test-setup.js
new file mode 100644
index 000000000..7a94cff0f
--- /dev/null
+++ b/test/helpers/test-setup.js
@@ -0,0 +1,4 @@
+import * as matchers from 'vitest-axe/matchers';
+import { expect } from 'vitest';
+
+expect.extend(matchers);
diff --git a/test/layouts/Breadcrumbs.test.jsx b/test/layouts/Breadcrumbs.test.jsx
index c58badaa8..f16d4a76d 100644
--- a/test/layouts/Breadcrumbs.test.jsx
+++ b/test/layouts/Breadcrumbs.test.jsx
@@ -2,6 +2,7 @@ import React from 'react';
import { expect, it, vi } from 'vitest';
import { render } from '@testing-library/react';
import Breadcrumbs from '../../src/layouts/Breadcrumbs';
+import isAccessible from '../utils/axe';
vi.mock('react-router-dom', async () => {
const actual = vi.importActual('react-router-dom');
@@ -14,6 +15,10 @@ vi.mock('react-router-dom', async () => {
};
});
+it('should be accessible', () => {
+ isAccessible(render());
+});
+
it('Renders correct routes and links', () => {
const { queryByText } = render();
diff --git a/test/layouts/Layout.test.jsx b/test/layouts/Layout.test.jsx
index caaea7198..655f09546 100644
--- a/test/layouts/Layout.test.jsx
+++ b/test/layouts/Layout.test.jsx
@@ -9,6 +9,7 @@ import { NavBar } from '@components/NavBar';
import Layout from '../../src/layouts/Layout';
import theme from '../../src/theme';
import createMatchMedia from '../helpers/createMatchMedia';
+import isAccessible from '../utils/axe';
const MockLayout = () => (
@@ -21,6 +22,29 @@ const MockLayout = () => (
);
describe('Desktop view', () => {
+ // TODO: Fix accessibility issues with this component
+ it.skip('should be accessible', () => {
+ vi.spyOn(hooks, 'useNotification').mockReturnValue({
+ state: { notifications: [] }
+ });
+ isAccessible(
+ render(
+
+
+
+ )
+ );
+ });
+
it('Renders breadcrumb when logged in, layout grid-template-rows as 64px 64px 1fr 280px', () => {
vi.spyOn(hooks, 'useNotification').mockReturnValue({
state: { notifications: [] }
diff --git a/test/layouts/Main.test.jsx b/test/layouts/Main.test.jsx
index 961c107ff..645e4a99a 100644
--- a/test/layouts/Main.test.jsx
+++ b/test/layouts/Main.test.jsx
@@ -2,8 +2,13 @@ import React from 'react';
import { describe, expect, it } from 'vitest';
import { render } from '@testing-library/react';
import Main from '../../src/layouts/Main';
+import isAccessible from '../utils/axe';
describe('Main Component', () => {
+ it('should be accessible', () => {
+ isAccessible(render(Text));
+ });
+
it('renders', () => {
render();
});
diff --git a/test/pages/CivicProfile.test.jsx b/test/pages/CivicProfile.test.jsx
index cc729e24b..bd42881df 100644
--- a/test/pages/CivicProfile.test.jsx
+++ b/test/pages/CivicProfile.test.jsx
@@ -4,6 +4,18 @@ import { render } from '@testing-library/react';
import { expect, it } from 'vitest';
import { CivicProfile } from '@pages';
import createMatchMedia from '../helpers/createMatchMedia';
+import isAccessible from '../utils/axe';
+
+// TODO: Fix accessibility issues with this component
+it.skip('should be accessible', () => {
+ isAccessible(
+ render(
+
+
+
+ )
+ );
+});
it('renders page container flex direction as row and nav container width as 25% by default', () => {
const component = render(
diff --git a/test/pages/Contacts.test.jsx b/test/pages/Contacts.test.jsx
index eeefcf308..532a89f3b 100644
--- a/test/pages/Contacts.test.jsx
+++ b/test/pages/Contacts.test.jsx
@@ -5,6 +5,7 @@ import { render } from '@testing-library/react';
import { useContactsList } from '@hooks';
import { BrowserRouter } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
+import isAccessible from '../utils/axe';
vi.mock('@hooks', async () => {
const actual = await vi.importActual('@hooks');
@@ -22,6 +23,32 @@ describe('Contacts Page', () => {
vi.clearAllMocks();
});
+ // TODO: Fix accessibility issues with this component
+ it.skip('should be accessible', () => {
+ const firstContact = {
+ person: 'Peter Parker',
+ familyName: 'Parker',
+ givenName: 'Peter',
+ webId: 'http://peter.com'
+ };
+ const secondContact = {
+ person: 'Batman',
+ familyName: 'Batman',
+ givenName: 'Batman',
+ webId: 'http://batman.com'
+ };
+ useContactsList.mockReturnValue({ data: [firstContact, secondContact] });
+ isAccessible(
+ render(
+
+
+
+
+
+ )
+ );
+ });
+
it('displays Loading message while loading', () => {
useContactsList.mockReturnValue({ isLoading: true });
const { getByRole } = render(
diff --git a/test/pages/Home.test.jsx b/test/pages/Home.test.jsx
index 042ea2ec9..1aef64128 100644
--- a/test/pages/Home.test.jsx
+++ b/test/pages/Home.test.jsx
@@ -3,10 +3,15 @@ import { render, cleanup, screen } from '@testing-library/react';
import { expect, describe, it, afterEach } from 'vitest';
import { Home } from '@pages';
import createMatchMedia from '../helpers/createMatchMedia';
+import isAccessible from '../utils/axe';
describe('Home Page', () => {
afterEach(cleanup);
+ it('should be accessible', () => {
+ isAccessible(render());
+ });
+
it('renders with correct order of logoSection on mobile', () => {
window.matchMedia = createMatchMedia(599);
render();
diff --git a/test/pages/PersonalProfile.test.jsx b/test/pages/PersonalProfile.test.jsx
index 876a10f16..67c3d26ce 100644
--- a/test/pages/PersonalProfile.test.jsx
+++ b/test/pages/PersonalProfile.test.jsx
@@ -4,10 +4,22 @@ import { BrowserRouter } from 'react-router-dom';
import { expect, it, describe } from 'vitest';
import { CivicProfile } from '@pages';
import { CIVIC_FORM_LIST } from '@components/CivicProfileForms';
+import isAccessible from '../utils/axe';
describe('Civic Profile', () => {
const numLinks = CIVIC_FORM_LIST.length;
+ // TODO: Fix accessibility issues with this component
+ it.skip('should be accessible', () => {
+ isAccessible(
+ render(
+
+
+
+ )
+ );
+ });
+
it('renders buttons for all forms in CIVIC_FORM_LIST', () => {
const { getByRole, getAllByRole } = render(
diff --git a/test/pages/Signup.test.jsx b/test/pages/Signup.test.jsx
index 230ef3cf8..3b4a4f9be 100644
--- a/test/pages/Signup.test.jsx
+++ b/test/pages/Signup.test.jsx
@@ -6,6 +6,7 @@ import { BrowserRouter } from 'react-router-dom';
import { Signup } from '@pages';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { SessionContext } from '@contexts';
+import isAccessible from '../utils/axe';
vi.mock('@inrupt/solid-client');
@@ -37,6 +38,21 @@ const MockSignupContexts = ({ session }) => (
);
describe('Signup Page', () => {
+ it('should be accessible', () => {
+ const sessionObj = {
+ login: vi.fn(),
+ fetch: vi.fn(),
+ podUrl: 'https://example.com',
+ session: {
+ info: {
+ webId: 'https://example.com/profile/',
+ isLoggedIn: false
+ }
+ }
+ };
+ isAccessible(render());
+ });
+
it('renders', () => {
const sessionObj = {
login: vi.fn(),
diff --git a/test/utils/axe.js b/test/utils/axe.js
new file mode 100644
index 000000000..2b0628931
--- /dev/null
+++ b/test/utils/axe.js
@@ -0,0 +1,8 @@
+import { axe } from 'vitest-axe';
+import { expect } from 'vitest';
+
+const isAccessible = async (renderResult) => {
+ expect(await axe(renderResult.container)).toHaveNoViolations();
+};
+
+export default isAccessible;
diff --git a/vitest.config.js b/vitest.config.js
index 6163fb135..fe9399b7a 100644
--- a/vitest.config.js
+++ b/vitest.config.js
@@ -1,12 +1,18 @@
// vitest.config.ts
-import {mergeConfig} from 'vite'
-import {defineConfig} from 'vitest/config'
-import viteConfig from './vite.config'
+/* eslint-disable import/no-extraneous-dependencies */
+import { mergeConfig } from 'vite';
+import { defineConfig } from 'vitest/config';
+/* eslint-enable import/no-extraneous-dependencies */
+import viteConfig from './vite.config';
-export default mergeConfig(viteConfig, defineConfig({
- test: {
- globals: true,
- environment: 'jsdom',
- globalSetup: './test/helpers/test-globals.js'
- },
-}))
\ No newline at end of file
+export default mergeConfig(
+ viteConfig,
+ defineConfig({
+ test: {
+ globals: true,
+ environment: 'jsdom',
+ setupFiles: './test/helpers/test-setup.js',
+ globalSetup: './test/helpers/test-globals.js'
+ }
+ })
+);