sts-sponsors team mailing list archive
-
sts-sponsors team
-
Mailing list archive
-
Message #07601
[Merge] ~petermakowski/maas-site-manager:add-a11y-tests into maas-site-manager:main
Peter Makowski has proposed merging ~petermakowski/maas-site-manager:add-a11y-tests into maas-site-manager:main.
Commit message:
add e2e accessibility tests
- add @axe-core/playwright
- add .u-visually-hidden class
- fix a11y issues on requests and tokens pages
- fix Pagination styles
Requested reviews:
MAAS Committers (maas-committers)
For more details, see:
https://code.launchpad.net/~petermakowski/maas-site-manager/+git/site-manager/+merge/441890
--
Your team MAAS Committers is requested to review the proposed merge of ~petermakowski/maas-site-manager:add-a11y-tests into maas-site-manager:main.
diff --git a/frontend/package.json b/frontend/package.json
index c4cc3ca..123987d 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -34,6 +34,7 @@
"yup": "1.0.2"
},
"devDependencies": {
+ "@axe-core/playwright": "4.6.1",
"@playwright/test": "1.32.3",
"@remix-run/web-fetch": "4.3.3",
"@testing-library/jest-dom": "5.16.5",
diff --git a/frontend/src/_utils.scss b/frontend/src/_utils.scss
index b666356..1cb04c8 100644
--- a/frontend/src/_utils.scss
+++ b/frontend/src/_utils.scss
@@ -50,3 +50,12 @@
.u-no-padding {
padding: 0 !important;
}
+// hide elements visually, but keep them accessible to screen readers
+.u-visually-hidden {
+ position: absolute !important;
+ height: 1px !important;
+ width: 1px !important;
+ overflow: hidden !important;
+ clip: rect(1px, 1px, 1px, 1px) !important;
+ white-space: nowrap !important;
+}
diff --git a/frontend/src/components/MainLayout/MainLayout.tsx b/frontend/src/components/MainLayout/MainLayout.tsx
index 93364ab..0737df1 100644
--- a/frontend/src/components/MainLayout/MainLayout.tsx
+++ b/frontend/src/components/MainLayout/MainLayout.tsx
@@ -89,7 +89,7 @@ const MainLayout: React.FC = () => {
<div className="l-application">
<Navigation />
<main className="l-main is-maas-site-manager">
- <h1 className="u-hide">{getPageTitle(pathname as RoutePath)}</h1>
+ <h1 className="u-visually-hidden">{getPageTitle(pathname as RoutePath)}</h1>
<div className={classNames("l-main__nav", { "is-open": isSideNavVisible })}>
<SecondaryNavigation isOpen={!!isSideNavVisible} />
</div>
diff --git a/frontend/src/components/TokensList/components/TokensTable/TokensTable.tsx b/frontend/src/components/TokensList/components/TokensTable/TokensTable.tsx
index a4c2b15..2c608ec 100644
--- a/frontend/src/components/TokensList/components/TokensTable/TokensTable.tsx
+++ b/frontend/src/components/TokensList/components/TokensTable/TokensTable.tsx
@@ -46,15 +46,20 @@ const TokensTable = ({
{
id: "select",
header: ({ table }) => <SelectAllCheckbox table={table} />,
- cell: ({ row }) => (
- <div>
- <Input
- checked={row.getIsSelected()}
- disabled={!row.getCanSelect()}
- onChange={row.getToggleSelectedHandler()}
+ cell: ({ row, getValue }) => (
+ <label className="p-checkbox--inline">
+ <input
+ aria-label={`select ${getValue()}`}
+ className="p-checkbox__input"
type="checkbox"
+ {...{
+ checked: row.getIsSelected(),
+ disabled: !row.getCanSelect(),
+ onChange: row.getToggleSelectedHandler(),
+ }}
/>
- </div>
+ <span className="p-checkbox__label" />
+ </label>
),
},
{
diff --git a/frontend/src/components/base/PaginationBar/_PaginationBar.scss b/frontend/src/components/base/PaginationBar/_PaginationBar.scss
index 2a76986..2dbd5c1 100644
--- a/frontend/src/components/base/PaginationBar/_PaginationBar.scss
+++ b/frontend/src/components/base/PaginationBar/_PaginationBar.scss
@@ -4,7 +4,6 @@
align-items: center;
padding: $spv--small 0;
margin-bottom: $spv--large;
- padding-bottom: $spv--large;
@media screen and (max-width: $breakpoint-small) {
padding-bottom: $spv--small;
diff --git a/frontend/src/components/base/TablePagination/TablePagination.tsx b/frontend/src/components/base/TablePagination/TablePagination.tsx
index a77f96c..c716638 100644
--- a/frontend/src/components/base/TablePagination/TablePagination.tsx
+++ b/frontend/src/components/base/TablePagination/TablePagination.tsx
@@ -61,43 +61,37 @@ const TablePagination = ({
return (
<nav aria-label="pagination" className="table-pagination">
- <ul>
- <li>
- <Button
- appearance="base"
- aria-label="previous page"
- disabled={currentPage === 1 || isLoading}
- hasIcon
- onClick={handlePreviousClick}
- >
- <Icon className="u__left-rotate" name="chevron-down" />
- </Button>
- </li>
- <strong>Page</strong>
- <Input
- aria-label="current page"
- className="current-page"
- disabled={isLoading}
- error={error}
- min={1}
- onBlur={handleInputBlur}
- onChange={handlePageInput}
- type="number"
- value={pageNumber}
- />
- <strong className="u-no-wrap"> of {totalPages}</strong>
- <li>
- <Button
- appearance="base"
- aria-label="next page"
- disabled={currentPage === totalPages || isLoading}
- hasIcon
- onClick={handleNextClick}
- >
- <Icon className="u__right-rotate" name="chevron-up" />
- </Button>
- </li>
- </ul>
+ <Button
+ appearance="base"
+ aria-label="previous page"
+ disabled={currentPage === 1 || isLoading}
+ hasIcon
+ onClick={handlePreviousClick}
+ >
+ <Icon className="u__left-rotate" name="chevron-down" />
+ </Button>
+ <strong>Page</strong>
+ <Input
+ aria-label="current page"
+ className="current-page"
+ disabled={isLoading}
+ error={error}
+ min={1}
+ onBlur={handleInputBlur}
+ onChange={handlePageInput}
+ type="number"
+ value={pageNumber}
+ />
+ <strong className="u-no-wrap"> of {totalPages}</strong>
+ <Button
+ appearance="base"
+ aria-label="next page"
+ disabled={currentPage === totalPages || isLoading}
+ hasIcon
+ onClick={handleNextClick}
+ >
+ <Icon className="u__right-rotate" name="chevron-up" />
+ </Button>
</nav>
);
};
diff --git a/frontend/src/components/base/TablePagination/_TablePagination.scss b/frontend/src/components/base/TablePagination/_TablePagination.scss
index 0375ec5..c663d8f 100644
--- a/frontend/src/components/base/TablePagination/_TablePagination.scss
+++ b/frontend/src/components/base/TablePagination/_TablePagination.scss
@@ -1,20 +1,16 @@
.table-pagination {
position: relative;
- margin-right: $sph--x-large;
+ margin: 0 $sph--x-large 0 0;
+ display: flex;
+ gap: $sph--small;
+ align-items: center;
+ list-style: none;
+ padding: 0;
@media screen and (max-width: $breakpoint-small) {
margin-bottom: $spv--large;
}
- ul {
- display: flex;
- gap: $sph--small;
- align-items: center;
- list-style: none;
- margin: 0;
- padding: 0;
- }
-
button {
margin: 0;
}
diff --git a/frontend/tests/a11y.spec.ts b/frontend/tests/a11y.spec.ts
new file mode 100644
index 0000000..8f3f8c1
--- /dev/null
+++ b/frontend/tests/a11y.spec.ts
@@ -0,0 +1,26 @@
+import { test, expect } from "@playwright/test";
+import AxeBuilder from "@axe-core/playwright"; // 1
+import { protectedRoutes, publicRoutes } from "@/base/routesConfig";
+import { adminAuthFile } from "./constants";
+
+const a11yTest = async ({ title, path }: { title: string; path: string }) =>
+ await test(`${title} page does not have any automatically detectable accessibility issues`, async ({ page }) => {
+ await page.goto(path, { waitUntil: "networkidle" });
+
+ const accessibilityScanResults = await new AxeBuilder({ page })
+ // @canonical/react-components Accordion is known to have accessibility issues
+ .exclude(".p-accordion")
+ .withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"])
+ .analyze();
+
+ expect(accessibilityScanResults.violations).toEqual([]);
+ });
+
+test.describe("protected routes", () => {
+ test.use({ storageState: adminAuthFile });
+ Object.values(protectedRoutes).forEach(a11yTest);
+});
+
+test.describe("public routes", () => {
+ Object.values(publicRoutes).forEach(a11yTest);
+});
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index 2fc181c..a554da0 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -20,6 +20,13 @@
resolved "https://registry.yarnpkg.com/@antfu/utils/-/utils-0.7.2.tgz#3bb6f37a6b188056fe9e2f363b6aa735ed65d7ca"
integrity sha512-vy9fM3pIxZmX07dL+VX1aZe7ynZ+YyB0jY+jE6r3hOK6GNY2t6W8rzpFC4tgpbXUYABkFQwgJq2XYXlxbXAI0g==
+"@axe-core/playwright@4.6.1":
+ version "4.6.1"
+ resolved "https://registry.yarnpkg.com/@axe-core/playwright/-/playwright-4.6.1.tgz#1740bc705972517d4331c520a341436ed44364fb"
+ integrity sha512-XMKP2OzGfGIYpU9G9FgI2ulyjEXQDP6qtZerOwdQ7YC1w4SFgofK3ogSk0qVoy0QI+q6XWLUJMfMMkUwdTR2dA==
+ dependencies:
+ axe-core "^4.6.3"
+
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.18.6":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a"
@@ -2448,6 +2455,11 @@ axe-core@^4.6.2:
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.6.3.tgz#fc0db6fdb65cc7a80ccf85286d91d64ababa3ece"
integrity sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg==
+axe-core@^4.6.3:
+ version "4.7.0"
+ resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf"
+ integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==
+
axios@*:
version "1.3.4"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.3.4.tgz#f5760cefd9cfb51fd2481acf88c05f67c4523024"
Follow ups
-
[Merge] ~petermakowski/maas-site-manager:add-a11y-tests into maas-site-manager:main
From: MAAS Lander, 2023-04-27
-
[Merge] ~petermakowski/maas-site-manager:add-a11y-tests into maas-site-manager:main
From: Peter Makowski, 2023-04-27
-
Re: [Merge] ~petermakowski/maas-site-manager:add-a11y-tests into maas-site-manager:main
From: Nick De Villiers, 2023-04-26
-
[Merge] ~petermakowski/maas-site-manager:add-a11y-tests into maas-site-manager:main
From: MAAS Lander, 2023-04-26
-
Re: [Merge] -b add-a11y-tests lp:~petermakowski/maas-site-manager/+git/site-manager into -b main lp:~maas-committers/maas-site-manager - LANDING FAILED
From: MAAS Lander, 2023-04-26
-
[Merge] ~petermakowski/maas-site-manager:add-a11y-tests into maas-site-manager:main
From: Peter Makowski, 2023-04-26
-
[Merge] ~petermakowski/maas-site-manager:add-a11y-tests into maas-site-manager:main
From: MAAS Lander, 2023-04-26
-
Re: [Merge] -b add-a11y-tests lp:~petermakowski/maas-site-manager/+git/site-manager into -b main lp:~maas-committers/maas-site-manager - LANDING FAILED
From: MAAS Lander, 2023-04-26
-
[Merge] ~petermakowski/maas-site-manager:add-a11y-tests into maas-site-manager:main
From: Peter Makowski, 2023-04-26
-
Re: [Merge] ~petermakowski/maas-site-manager:add-a11y-tests into maas-site-manager:main
From: Nick De Villiers, 2023-04-26
-
Re: [Merge] ~petermakowski/maas-site-manager:add-a11y-tests into maas-site-manager:main
From: Peter Makowski, 2023-04-26
-
Re: [Merge] ~petermakowski/maas-site-manager:add-a11y-tests into maas-site-manager:main
From: Nick De Villiers, 2023-04-26
-
Re: [Merge] ~petermakowski/maas-site-manager:add-a11y-tests into maas-site-manager:main
From: Peter Makowski, 2023-04-26
-
Re: [Merge] ~petermakowski/maas-site-manager:add-a11y-tests into maas-site-manager:main
From: Peter Makowski, 2023-04-26
-
Re: [UNITTESTS] -b add-a11y-tests lp:~petermakowski/maas-site-manager/+git/site-manager into -b main lp:~maas-committers/maas-site-manager - TESTS PASS
From: MAAS Lander, 2023-04-25
-
Re: [UNITTESTS] -b add-a11y-tests lp:~petermakowski/maas-site-manager/+git/site-manager into -b main lp:~maas-committers/maas-site-manager - TESTS FAILED
From: MAAS Lander, 2023-04-25
-
[Merge] ~petermakowski/maas-site-manager:add-a11y-tests into maas-site-manager:main
From: Peter Makowski, 2023-04-25