diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 77c0b70e..be4c1680 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -1,4 +1,4 @@ -name: Links +name: Valid Links on: repository_dispatch: diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 349a4069..b5bc8c76 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -4,7 +4,8 @@ "yzhang.markdown-all-in-one", "jsynowiec.vscode-insertdatestring", "esbenp.prettier-vscode", - "vunguyentuan.vscode-css-variables" + "vunguyentuan.vscode-css-variables", + "deque-systems.vscode-axe-linter" ], "unwantedRecommendations": [] } diff --git a/package.json b/package.json index 45d96148..4c4ad953 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "simplex-noise": "^4.0.1" }, "devDependencies": { + "@axe-core/playwright": "^4.9.1", "@playwright/test": "^1.44.1", "@radix-ui/colors": "^3.0.0", "@types/howler": "^2.2.11", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1faf6d1c..8aa117fe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -115,6 +115,9 @@ dependencies: version: 4.0.1 devDependencies: + '@axe-core/playwright': + specifier: ^4.9.1 + version: 4.9.1(playwright-core@1.44.1) '@playwright/test': specifier: ^1.44.1 version: 1.44.1 @@ -466,6 +469,15 @@ packages: - supports-color dev: false + /@axe-core/playwright@4.9.1(playwright-core@1.44.1): + resolution: {integrity: sha512-8m4WZbZq7/aq7ZY5IG8GqV+ZdvtGn/iJdom+wBg+iv/3BAOBIfNQtIu697a41438DzEEyptXWmC3Xl5Kx/o9/g==} + peerDependencies: + playwright-core: '>= 1.0.0' + dependencies: + axe-core: 4.9.1 + playwright-core: 1.44.1 + dev: true + /@babel/code-frame@7.24.2: resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} engines: {node: '>=6.9.0'} @@ -2825,6 +2837,11 @@ packages: possible-typed-array-names: 1.0.0 dev: true + /axe-core@4.9.1: + resolution: {integrity: sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==} + engines: {node: '>=4'} + dev: true + /axobject-query@4.0.0: resolution: {integrity: sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==} dependencies: diff --git a/src/components/Notecard/NotecardComposer.tsx b/src/components/Notecard/NotecardComposer.tsx index 484969f5..17c4194a 100644 --- a/src/components/Notecard/NotecardComposer.tsx +++ b/src/components/Notecard/NotecardComposer.tsx @@ -103,7 +103,7 @@ export const NotecardComposer = () => { data-1p-ignore />
@@ -115,6 +115,7 @@ export const NotecardComposer = () => { viewBox="0 0 24 24" width="24" fill="currentColor" + aria-label="Previous theme" > @@ -127,6 +128,7 @@ export const NotecardComposer = () => { width="24" viewBox="0 0 24 24" fill="currentColor" + aria-label="Next theme" > diff --git a/src/components/Webring.astro b/src/components/Webring.astro index 8c680151..7c4011ee 100644 --- a/src/components/Webring.astro +++ b/src/components/Webring.astro @@ -15,7 +15,7 @@ const { title, description, url, prev, next, color } = data; style={`--webring-bg: var(--${color}-3); --webring-text: var(--${color}-12); --webring-hover: var(--${color}-4); --webring-border: var(--${color}-5)`} > -

{title}

+

{title}

{description}
+

Guestbook

{ diff --git a/src/styles/base.css b/src/styles/base.css index 6cb48d6a..01f2cec2 100644 --- a/src/styles/base.css +++ b/src/styles/base.css @@ -108,3 +108,13 @@ a { left: 0; right: 0; } + +.visually-hidden { + clip: rect(0 0 0 0); + clip-path: inset(50%); + height: 1px; + overflow: hidden; + position: absolute; + white-space: nowrap; + width: 1px; +} diff --git a/tests/accessibility.spec.ts b/tests/accessibility.spec.ts new file mode 100644 index 00000000..727cc636 --- /dev/null +++ b/tests/accessibility.spec.ts @@ -0,0 +1,33 @@ +import AxeBuilder from "@axe-core/playwright"; +import { expect, test } from "@playwright/test"; + +const paths = [ + "/", + "/garden", + "/about", + "/now", + "/guestbook", + "/webrings", + "/colophon", +]; + +test.describe("all pages", () => { + for (const path of paths) { + test(`${path} page should not have any automatically detectable accessibility issues`, async ({ + page, + }, testInfo) => { + await page.goto(path); + + const accessibilityScanResults = await new AxeBuilder({ + page, + }).analyze(); + + await testInfo.attach("accessibility-scan-results", { + body: JSON.stringify(accessibilityScanResults, null, 2), + contentType: "application/json", + }); + + expect(accessibilityScanResults.violations).toHaveLength(0); + }); + } +});