From 057da85178fc1b1a5b77628314f8e87ca424d2c1 Mon Sep 17 00:00:00 2001 From: Ned Zimmerman Date: Tue, 9 Jul 2024 11:09:06 -0300 Subject: [PATCH 01/18] test: test new issue URL --- src/_layouts/report.njk | 3 ++- src/_utils/new-issue-url.js | 6 +++--- test/issue-url.test.js | 10 ++++++++++ 3 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 test/issue-url.test.js diff --git a/src/_layouts/report.njk b/src/_layouts/report.njk index ac5c3f8..c615242 100644 --- a/src/_layouts/report.njk +++ b/src/_layouts/report.njk @@ -117,7 +117,8 @@ layout: base

{{ issue.title }}

- {% newIssueUrl issue.title, issue.rawInput, issue.sample, issuesUrl %} + + Create an issuefor '{{ issue.title }}' (external link)
{% renderString issue.body, "md" %}
diff --git a/src/_utils/new-issue-url.js b/src/_utils/new-issue-url.js index 1dacba5..f59599b 100644 --- a/src/_utils/new-issue-url.js +++ b/src/_utils/new-issue-url.js @@ -5,7 +5,7 @@ export default function newIssueUrl(title, body, sample, issuesUrl) { let issueUrl = ""; - body = sample === "all" ? `${body}\n##### Pages\n\n- All pages` : `${body}\n##### Pages\n\n- ${sample}`; + body = sample === "all" ? `${body}\n\n##### Pages\n\n- All pages` : `${body}\n\n##### Pages\n\n- ${sample}`; if (issuesUrl.includes("github")) { issueUrl = newGithubIssueUrl({ @@ -16,8 +16,8 @@ export default function newIssueUrl(title, body, sample, issuesUrl) { } if (issuesUrl.includes("gitlab")) { - issueUrl = new URL(`${issuesUrl}/-/issues/new?issue[title]=${encodeURIComponent(title)}&issue[description]=${encodeURIComponent(body)}`); + issueUrl = `${issuesUrl}/-/issues/new?issue[title]=${encodeURIComponent(title)}&issue[description]=${encodeURIComponent(body)}`; } - return `Create an issuefor '${title}' (external link)`; + return issueUrl; } diff --git a/test/issue-url.test.js b/test/issue-url.test.js new file mode 100644 index 0000000..626c69c --- /dev/null +++ b/test/issue-url.test.js @@ -0,0 +1,10 @@ +import test from "ava"; +import newIssueUrl from "../src/_utils/new-issue-url.js"; + +test("new issue URL can be generated for GitHub", (t) => { + t.is(newIssueUrl('Test issue', 'Not applicable.', 'all', 'https://github.com/inclusive-design/idrc-wcag-reporter'), 'https://github.com/inclusive-design/idrc-wcag-reporter/issues/new?body=Not+applicable.%0A%0A%23%23%23%23%23+Pages%0A%0A-+All+pages&title=Test+issue'); +}); + +test("new issue URL can be generated for GitLab", (t) => { + t.is(newIssueUrl('Test issue', 'Not applicable.', 'all', 'https://gitlab.com/inclusive-design/idrc-wcag-reporter'), 'https://gitlab.com/inclusive-design/idrc-wcag-reporter/-/issues/new?issue[title]=Test%20issue&issue[description]=Not%20applicable.%0A%0A%23%23%23%23%23%20Pages%0A%0A-%20All%20pages'); +}); From 0fc54dc63a75b08d021f8f2d142184293548d52f Mon Sep 17 00:00:00 2001 From: Ned Zimmerman Date: Tue, 9 Jul 2024 11:19:47 -0300 Subject: [PATCH 02/18] fix: resolve linting issue --- package.json | 2 +- src/_utils/new-issue-url.js | 2 +- test/issue-url.test.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 735037c..d613309 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ }, "lint-staged": { "*.css": "stylelint --fix", - "*.{js,cjs,json,jsonc}": "biome check --write --no-errors-on-unmatched", + "*.{js,cjs,json,jsonc}": "biome check . --write --no-errors-on-unmatched", "*.md": ["markdownlint-cli2 --fix"] } } diff --git a/src/_utils/new-issue-url.js b/src/_utils/new-issue-url.js index f59599b..cc38f9f 100644 --- a/src/_utils/new-issue-url.js +++ b/src/_utils/new-issue-url.js @@ -19,5 +19,5 @@ export default function newIssueUrl(title, body, sample, issuesUrl) { issueUrl = `${issuesUrl}/-/issues/new?issue[title]=${encodeURIComponent(title)}&issue[description]=${encodeURIComponent(body)}`; } - return issueUrl; + return issueUrl; } diff --git a/test/issue-url.test.js b/test/issue-url.test.js index 626c69c..19db774 100644 --- a/test/issue-url.test.js +++ b/test/issue-url.test.js @@ -2,9 +2,9 @@ import test from "ava"; import newIssueUrl from "../src/_utils/new-issue-url.js"; test("new issue URL can be generated for GitHub", (t) => { - t.is(newIssueUrl('Test issue', 'Not applicable.', 'all', 'https://github.com/inclusive-design/idrc-wcag-reporter'), 'https://github.com/inclusive-design/idrc-wcag-reporter/issues/new?body=Not+applicable.%0A%0A%23%23%23%23%23+Pages%0A%0A-+All+pages&title=Test+issue'); + t.is(newIssueUrl("Test issue", "Not applicable.", "all", "https://github.com/inclusive-design/idrc-wcag-reporter"), "https://github.com/inclusive-design/idrc-wcag-reporter/issues/new?body=Not+applicable.%0A%0A%23%23%23%23%23+Pages%0A%0A-+All+pages&title=Test+issue"); }); test("new issue URL can be generated for GitLab", (t) => { - t.is(newIssueUrl('Test issue', 'Not applicable.', 'all', 'https://gitlab.com/inclusive-design/idrc-wcag-reporter'), 'https://gitlab.com/inclusive-design/idrc-wcag-reporter/-/issues/new?issue[title]=Test%20issue&issue[description]=Not%20applicable.%0A%0A%23%23%23%23%23%20Pages%0A%0A-%20All%20pages'); + t.is(newIssueUrl("Test issue", "Not applicable.", "all", "https://gitlab.com/inclusive-design/idrc-wcag-reporter"), "https://gitlab.com/inclusive-design/idrc-wcag-reporter/-/issues/new?issue[title]=Test%20issue&issue[description]=Not%20applicable.%0A%0A%23%23%23%23%23%20Pages%0A%0A-%20All%20pages"); }); From f67b6eb298ac41415b83fb6b292380004819f1dc Mon Sep 17 00:00:00 2001 From: Ned Zimmerman Date: Tue, 9 Jul 2024 11:20:22 -0300 Subject: [PATCH 03/18] ci: rename things --- .github/workflows/{list-and-test.yml => lint-and-test.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{list-and-test.yml => lint-and-test.yml} (94%) diff --git a/.github/workflows/list-and-test.yml b/.github/workflows/lint-and-test.yml similarity index 94% rename from .github/workflows/list-and-test.yml rename to .github/workflows/lint-and-test.yml index 4db88d8..7eee5e3 100644 --- a/.github/workflows/list-and-test.yml +++ b/.github/workflows/lint-and-test.yml @@ -17,7 +17,7 @@ jobs: with: path: node_modules key: ${{ runner.OS }}-build-${{ hashFiles('**/package-lock.json') }} - - name: Install dependencies and lint files + - name: Install dependencies, lint files and run tests run: | npm ci npm run lint From 67566b38525d17b50952ca577b90232f05675625 Mon Sep 17 00:00:00 2001 From: Ned Zimmerman Date: Thu, 11 Jul 2024 15:57:03 -0300 Subject: [PATCH 04/18] fix: remove circular dependency within data files --- .github/workflows/lint-and-test.yml | 44 ++-- eleventy.config.js | 176 +++++++++----- package-lock.json | 103 +++++++- package.json | 5 +- src/_data/scData.json | 352 ---------------------------- src/_data/successcriteria.js | 33 --- src/_data/totalsbylevel.js | 105 --------- src/_layouts/report.njk | 6 +- src/_utils/sanitize-number.js | 7 - src/_utils/sc-support.js | 73 +++--- src/_utils/sc-table.js | 47 ++-- src/_utils/totals-by-level.js | 96 ++++++++ 12 files changed, 403 insertions(+), 644 deletions(-) delete mode 100644 src/_data/scData.json delete mode 100644 src/_data/successcriteria.js delete mode 100644 src/_data/totalsbylevel.js delete mode 100644 src/_utils/sanitize-number.js create mode 100644 src/_utils/totals-by-level.js diff --git a/.github/workflows/lint-and-test.yml b/.github/workflows/lint-and-test.yml index 7eee5e3..1286ae7 100644 --- a/.github/workflows/lint-and-test.yml +++ b/.github/workflows/lint-and-test.yml @@ -21,25 +21,25 @@ jobs: run: | npm ci npm run lint - npm run test - - name: Save code coverage to artifact - uses: actions/upload-artifact@v4 - with: - name: code-coverage - path: "coverage/clover.xml" - retention-days: 5 - upload-coverage: - name: Upload code coverage - runs-on: ubuntu-latest - needs: - - lint-test - steps: - - name: Fetch code coverage artifact - uses: actions/download-artifact@v4 - with: - name: code-coverage - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 - with: - token: ${{ secrets.CODECOV_TOKEN }} - fail_ci_if_error: true + # npm run test + # - name: Save code coverage to artifact + # uses: actions/upload-artifact@v4 + # with: + # name: code-coverage + # path: "coverage/clover.xml" + # retention-days: 5 + # upload-coverage: + # name: Upload code coverage + # runs-on: ubuntu-latest + # needs: + # - lint-test + # steps: + # - name: Fetch code coverage artifact + # uses: actions/download-artifact@v4 + # with: + # name: code-coverage + # - name: Upload coverage to Codecov + # uses: codecov/codecov-action@v4 + # with: + # token: ${{ secrets.CODECOV_TOKEN }} + # fail_ci_if_error: true diff --git a/eleventy.config.js b/eleventy.config.js index e8e33eb..5ea01ff 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -1,73 +1,121 @@ import { RenderPlugin } from "@11ty/eleventy"; import syntaxHighlightPlugin from "@11ty/eleventy-plugin-syntaxhighlight"; +import fetch from "@11ty/eleventy-fetch"; +import pluginWebc from "@11ty/eleventy-plugin-webc"; // Import {$} from 'execa'; import newIssueUrl from "./src/_utils/new-issue-url.js"; import scSupport from "./src/_utils/sc-support.js"; import scTable from "./src/_utils/sc-table.js"; export default function eleventy(eleventyConfig) { - eleventyConfig.addNunjucksAsyncShortcode("scTable", scTable); - eleventyConfig.addNunjucksAsyncShortcode("scSupport", scSupport); - eleventyConfig.addShortcode("newIssueUrl", newIssueUrl); - eleventyConfig.addLayoutAlias("report", "report.njk"); - - eleventyConfig.addPlugin(RenderPlugin); - eleventyConfig.addPlugin(syntaxHighlightPlugin); - - eleventyConfig.addFilter("withoutTips", (issues) => issues.filter((item) => Object.hasOwn(item, "sc") && item.sc !== "")); - - eleventyConfig.addFilter("withoutViolations", (issues) => issues.filter((item) => item.sc === "" || !Object.hasOwn(item, "sc"))); - - eleventyConfig.addShortcode("renderString", async function (content, templateFormat) { - const renderManager = new RenderPlugin.RenderManager(); - const result = await renderManager.compile(content, templateFormat); - return result.call(this); - }); - - eleventyConfig.addAsyncFilter("formatDate", (value) => - new Date(value).toLocaleString("en-CA", { - year: "numeric", - month: "long", - day: "numeric" - }) - ); - - eleventyConfig.addCollection("reports", (collectionApi) => collectionApi.getFilteredByGlob("src/collections/reports/*.md")); - - eleventyConfig.addPassthroughCopy({ - "src/admin/config.yml": "admin/config.yml" - }); - - eleventyConfig.addPassthroughCopy({ - "src/assets": "assets" - }); - - eleventyConfig.addPassthroughCopy({ - "node_modules/a11y-syntax-highlighting/dist/prism/a11y-dark.min.css": "assets/styles/a11y-dark.min.css", - "node_modules/@zachleat/table-saw/table-saw.js": "assets/scripts/table-saw.js" - }); - - // EleventyConfig.on( - // "eleventy.after", - // async ({ _dir, results, _runMode, _outputMode }) => { - // for (const result of results) { - // if (result.inputPath.startsWith("./src/collections/reports/")) { - // const { stdout } = - // await $`weasyprint --pdf-variant=pdf/ua-1 ${result.outputPath} ./_site${result.url}report.pdf`; - // } - // } - // }, - // ); - - return { - dir: { - input: "src", - includes: "_includes", - layouts: "_layouts", - data: "_data" - }, - templateFormats: ["njk", "md", "css", "png", "jpg", "svg"], - htmlTemplateEngine: "njk", - markdownTemplateEngine: "njk" - }; + eleventyConfig.addNunjucksAsyncShortcode("scTable", scTable); + eleventyConfig.addNunjucksAsyncShortcode("scSupport", scSupport); + eleventyConfig.addShortcode("newIssueUrl", newIssueUrl); + eleventyConfig.addLayoutAlias("report", "report.njk"); + eleventyConfig.addPlugin(pluginWebc); + + eleventyConfig.addGlobalData("successCriteria", async () => { + const url = + "https://raw.githubusercontent.com/w3c/wcag/main/guidelines/wcag.json"; + + try { + const json = await fetch(url, { + duration: "1d", + type: "json", + }); + + const results = {}; + + for (const principle of json.principles) { + for (const guideline of principle.guidelines) { + for (const sc of guideline.successcriteria) { + results[sc.num] = { + number: sc.num, + principle: principle.handle, + guideline: guideline.handle, + name: sc.handle, + level: sc.level, + versions: sc.versions, + id: sc.id.replace("WCAG2:", ""), + }; + } + } + } + + return results; + } catch (error) { + console.error(`Fetch failed in successcriteria.js. ${error}`); + } + }); + + eleventyConfig.addPlugin(RenderPlugin); + eleventyConfig.addPlugin(syntaxHighlightPlugin); + + eleventyConfig.addFilter("withoutTips", (issues) => + issues.filter((item) => Object.hasOwn(item, "sc") && item.sc !== ""), + ); + + eleventyConfig.addFilter("withoutViolations", (issues) => + issues.filter((item) => item.sc === "" || !Object.hasOwn(item, "sc")), + ); + + eleventyConfig.addShortcode( + "renderString", + async function (content, templateFormat) { + const renderManager = new RenderPlugin.RenderManager(); + const result = await renderManager.compile(content, templateFormat); + return result.call(this); + }, + ); + + eleventyConfig.addAsyncFilter("formatDate", (value) => + new Date(value).toLocaleString("en-CA", { + year: "numeric", + month: "long", + day: "numeric", + }), + ); + + eleventyConfig.addCollection("reports", (collectionApi) => + collectionApi.getFilteredByGlob("src/collections/reports/*.md"), + ); + + eleventyConfig.addPassthroughCopy({ + "src/admin/config.yml": "admin/config.yml", + }); + + eleventyConfig.addPassthroughCopy({ + "src/assets": "assets", + }); + + eleventyConfig.addPassthroughCopy({ + "node_modules/a11y-syntax-highlighting/dist/prism/a11y-dark.min.css": + "assets/styles/a11y-dark.min.css", + "node_modules/@zachleat/table-saw/table-saw.js": + "assets/scripts/table-saw.js", + }); + + // EleventyConfig.on( + // "eleventy.after", + // async ({ _dir, results, _runMode, _outputMode }) => { + // for (const result of results) { + // if (result.inputPath.startsWith("./src/collections/reports/")) { + // const { stdout } = + // await $`weasyprint --pdf-variant=pdf/ua-1 ${result.outputPath} ./_site${result.url}report.pdf`; + // } + // } + // }, + // ); + + return { + dir: { + input: "src", + includes: "_includes", + layouts: "_layouts", + data: "_data", + }, + templateFormats: ["njk", "md", "css", "png", "jpg", "svg"], + htmlTemplateEngine: "njk", + markdownTemplateEngine: "njk", + }; } diff --git a/package-lock.json b/package-lock.json index 94a0be8..82a9136 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@11ty/eleventy": "3.0.0-alpha.16", "@11ty/eleventy-fetch": "^4.0.1", "@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0", + "@11ty/eleventy-plugin-webc": "^0.11.2", "@zachleat/table-saw": "^1.0.6", "a11y-syntax-highlighting": "^0.2.0", "execa": "^9.3.0", @@ -198,6 +199,37 @@ "url": "https://opencollective.com/11ty" } }, + "node_modules/@11ty/eleventy-plugin-webc": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/@11ty/eleventy-plugin-webc/-/eleventy-plugin-webc-0.11.2.tgz", + "integrity": "sha512-oa/XlAqI5KtVO7M14qaN92D2yJfBEMMSb66YWY6YZVbRqFSVbjO4WmRJ2Ti2ZZb1FNvxj4ypGNV8VJleGE69xw==", + "dependencies": { + "@11ty/eleventy-plugin-bundle": "^1.0.4", + "@11ty/webc": "^0.11.0" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/11ty" + } + }, + "node_modules/@11ty/eleventy-plugin-webc/node_modules/@11ty/eleventy-plugin-bundle": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@11ty/eleventy-plugin-bundle/-/eleventy-plugin-bundle-1.0.5.tgz", + "integrity": "sha512-Esv97j+mOo/yfxjaWl4j8CyszOBsRjU/DOUWOBqVnnDLM8VDXeus2LTJUxF70nAU0g+z+b6fRn8fKnm6b2a/UQ==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/11ty" + } + }, "node_modules/@11ty/eleventy-utils": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@11ty/eleventy-utils/-/eleventy-utils-1.0.3.tgz", @@ -243,6 +275,63 @@ "node": ">= 6" } }, + "node_modules/@11ty/webc": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/@11ty/webc/-/webc-0.11.4.tgz", + "integrity": "sha512-q1GMcjNnx9PxUr6jyTT5CdDFma3JWkT5D45wRNYUQ/B4cxTTxpC15b2rYdzNaGuSqB6tsArQ9Qh4BPqg6Xo9cA==", + "dependencies": { + "@11ty/eleventy-utils": "^1.0.1", + "css-tree": "^2.3.1", + "dependency-graph": "^0.11.0", + "entities": "^4.4.0", + "fast-glob": "^3.2.12", + "is-glob": "^4.0.3", + "nanoid": "^4.0.1", + "node-retrieve-globals": "^2.0.7", + "parse5": "^7.1.2" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/11ty" + } + }, + "node_modules/@11ty/webc/node_modules/dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/@11ty/webc/node_modules/nanoid": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.2.tgz", + "integrity": "sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^14 || ^16 || >=18" + } + }, + "node_modules/@11ty/webc/node_modules/node-retrieve-globals": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/node-retrieve-globals/-/node-retrieve-globals-2.0.8.tgz", + "integrity": "sha512-mVimS/m8H28kyMdvOIfyMCM8wFNiKXM83ag1yHYP297iVmlCSmCh7Ih4b+ig9/DZ2+LbXZCPLDSZO4yRa5ttyg==", + "dependencies": { + "acorn": "^8.8.2", + "acorn-walk": "^8.2.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", @@ -2531,7 +2620,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, "license": "MIT", "dependencies": { "mdn-data": "2.0.30", @@ -5064,7 +5152,6 @@ "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true, "license": "CC0-1.0" }, "node_modules/mdurl": { @@ -5770,6 +5857,17 @@ "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==", "license": "MIT" }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -6618,7 +6716,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" diff --git a/package.json b/package.json index ef0098e..dc5a06c 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "@11ty/eleventy": "3.0.0-alpha.16", "@11ty/eleventy-fetch": "^4.0.1", "@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0", + "@11ty/eleventy-plugin-webc": "^0.11.2", "@zachleat/table-saw": "^1.0.6", "a11y-syntax-highlighting": "^0.2.0", "execa": "^9.3.0", @@ -58,6 +59,8 @@ "lint-staged": { "*.css": "stylelint --fix", "*.{js,cjs,json,jsonc}": "biome check . --write --no-errors-on-unmatched", - "*.md": ["markdownlint-cli2 --fix"] + "*.md": [ + "markdownlint-cli2 --fix" + ] } } diff --git a/src/_data/scData.json b/src/_data/scData.json deleted file mode 100644 index fe223d9..0000000 --- a/src/_data/scData.json +++ /dev/null @@ -1,352 +0,0 @@ -{ - "successCriteria": [ - { - "number": "1.1.1", - "name": "Non-text Content (Level A)" - }, - { - "number": "1.2.1", - "name": "Audio-only and Video-only (Prerecorded) (Level A)" - }, - { - "number": "1.2.2", - "name": "Captions (Prerecorded) (Level A)" - }, - { - "number": "1.2.3", - "name": "Audio Description or Media Alternative (Prerecorded) (Level A)" - }, - { - "number": "1.2.4", - "name": "Captions (Live) (Level AA)" - }, - { - "number": "1.2.5", - "name": "Audio Description (Prerecorded) (Level AA)" - }, - { - "number": "1.2.6", - "name": "Sign Language (Prerecorded) (Level AAA)" - }, - { - "number": "1.2.7", - "name": "Extended Audio Description (Prerecorded) (Level AAA)" - }, - { - "number": "1.2.8", - "name": "Media Alternative (Prerecorded) (Level AAA)" - }, - { - "number": "1.2.9", - "name": "Audio-only (Live) (Level AAA)" - }, - { - "number": "1.3.1", - "name": "Info and Relationships (Level A)" - }, - { - "number": "1.3.2", - "name": "Meaningful Sequence (Level A)" - }, - { - "number": "1.3.3", - "name": "Sensory Characteristics (Level A)" - }, - { - "number": "1.3.4", - "name": "Orientation (Level AA)" - }, - { - "number": "1.3.5", - "name": "Identify Input Purpose (Level AA)" - }, - { - "number": "1.3.6", - "name": "Identify Purpose (Level AAA)" - }, - { - "number": "1.4.1", - "name": "Use of Color (Level A)" - }, - { - "number": "1.4.2", - "name": "Audio Control (Level A)" - }, - { - "number": "1.4.3", - "name": "Contrast (Minimum) (Level AA)" - }, - { - "number": "1.4.4", - "name": "Resize Text (Level AA)" - }, - { - "number": "1.4.5", - "name": "Images of Text (Level AA)" - }, - { - "number": "1.4.6", - "name": "Contrast (Enhanced) (Level AAA)" - }, - { - "number": "1.4.7", - "name": "Low or No Background Audio (Level AAA)" - }, - { - "number": "1.4.8", - "name": "Visual Presentation (Level AAA)" - }, - { - "number": "1.4.9", - "name": "Images of Text (No Exception) (Level AAA)" - }, - { - "number": "1.4.10", - "name": "Reflow (Level AA)" - }, - { - "number": "1.4.11", - "name": "Non-text Contrast (Level AA)" - }, - { - "number": "1.4.12", - "name": "Text Spacing (Level AA)" - }, - { - "number": "1.4.13", - "name": "Content on Hover or Focus (Level AA)" - }, - { - "number": "2.1.1", - "name": "Keyboard (Level A)" - }, - { - "number": "2.1.2", - "name": "No Keyboard Trap (Level A)" - }, - { - "number": "2.1.3", - "name": "Keyboard (No Exception) (Level AAA)" - }, - { - "number": "2.1.4", - "name": "Character Key Shortcuts (Level A)" - }, - { - "number": "2.2.1", - "name": "Timing Adjustable (Level A)" - }, - { - "number": "2.2.2", - "name": "Pause, Stop, Hide (Level A)" - }, - { - "number": "2.2.3", - "name": "No Timing (Level AAA)" - }, - { - "number": "2.2.4", - "name": "Interruptions (Level AAA)" - }, - { - "number": "2.2.5", - "name": "Re-authenticating (Level AAA)" - }, - { - "number": "2.2.6", - "name": "Timeouts (Level AAA)" - }, - { - "number": "2.3.1", - "name": "Three Flashes or Below Threshold (Level A)" - }, - { - "number": "2.3.2", - "name": "Three Flashes (Level AAA)" - }, - { - "number": "2.3.3", - "name": "Animation from Interactions (Level AAA)" - }, - { - "number": "2.4.1", - "name": "Bypass Blocks (Level A)" - }, - { - "number": "2.4.2", - "name": "Page Titled (Level A)" - }, - { - "number": "2.4.3", - "name": "Focus Order (Level A)" - }, - { - "number": "2.4.4", - "name": "Link Purpose (In Context) (Level A)" - }, - { - "number": "2.4.5", - "name": "Multiple Ways (Level AA)" - }, - { - "number": "2.4.6", - "name": "Headings and Labels (Level AA)" - }, - { - "number": "2.4.7", - "name": "Focus Visible (Level AA)" - }, - { - "number": "2.4.8", - "name": "Location (Level AAA)" - }, - { - "number": "2.4.9", - "name": "Link Purpose (Link Only) (Level AAA)" - }, - { - "number": "2.4.10", - "name": "Section Headings (Level AAA)" - }, - { - "number": "2.4.11", - "name": "Focus Not Obscured (Minimum) (Level AA)" - }, - { - "number": "2.4.12", - "name": "Focus Not Obscured (Enhanced) (Level AAA)" - }, - { - "number": "2.4.13", - "name": "Focus Appearance (Level AAA)" - }, - { - "number": "2.5.1", - "name": "Pointer Gestures (Level A)" - }, - { - "number": "2.5.2", - "name": "Pointer Cancellation (Level A)" - }, - { - "number": "2.5.3", - "name": "Label in Name (Level A)" - }, - { - "number": "2.5.4", - "name": "Motion Actuation (Level A)" - }, - { - "number": "2.5.5", - "name": "Target Size (Enhanced) (Level AAA)" - }, - { - "number": "2.5.6", - "name": "Concurrent Input Mechanisms (Level AAA)" - }, - { - "number": "2.5.7", - "name": "Dragging Movements (Level AA)" - }, - { - "number": "2.5.8", - "name": "Target Size (Minimum) (Level AA)" - }, - { - "number": "3.1.1", - "name": "Language of Page (Level A)" - }, - { - "number": "3.1.2", - "name": "Language of Parts (Level AA)" - }, - { - "number": "3.1.3", - "name": "Unusual Words (Level AAA)" - }, - { - "number": "3.1.4", - "name": "Abbreviations (Level AAA)" - }, - { - "number": "3.1.5", - "name": "Reading Level (Level AAA)" - }, - { - "number": "3.1.6", - "name": "Pronunciation (Level AAA)" - }, - { - "number": "3.2.1", - "name": "On Focus (Level A)" - }, - { - "number": "3.2.2", - "name": "On Input (Level A)" - }, - { - "number": "3.2.3", - "name": "Consistent Navigation (Level AA)" - }, - { - "number": "3.2.4", - "name": "Consistent Identification (Level AA)" - }, - { - "number": "3.2.5", - "name": "Change on Request (Level AAA)" - }, - { - "number": "3.2.6", - "name": "Consistent Help (Level A)" - }, - { - "number": "3.3.1", - "name": "Error Identification (Level A)" - }, - { - "number": "3.3.2", - "name": "Labels or Instructions (Level A)" - }, - { - "number": "3.3.3", - "name": "Error Suggestion (Level AA)" - }, - { - "number": "3.3.4", - "name": "Error Prevention (Legal, Financial, Data) (Level AA)" - }, - { - "number": "3.3.5", - "name": "Help (Level AAA)" - }, - { - "number": "3.3.6", - "name": "Error Prevention (All) (Level AAA)" - }, - { - "number": "3.3.7", - "name": "Redundant Entry (Level A)" - }, - { - "number": "3.3.8", - "name": "Accessible Authentication (Minimum) (Level AA)" - }, - { - "number": "3.3.9", - "name": "Accessible Authentication (Enhanced) (Level AAA)" - }, - { - "number": "4.1.1", - "name": "Parsing (Obsolete and removed) (Level )" - }, - { - "number": "4.1.2", - "name": "Name, Role, Value (Level A)" - }, - { - "number": "4.1.3", - "name": "Status Messages (Level AA)" - } - ] -} diff --git a/src/_data/successcriteria.js b/src/_data/successcriteria.js deleted file mode 100644 index 225bf4a..0000000 --- a/src/_data/successcriteria.js +++ /dev/null @@ -1,33 +0,0 @@ -import fetch from "@11ty/eleventy-fetch"; - -export default async function successCriteria() { - const url = "https://raw.githubusercontent.com/w3c/wcag/main/guidelines/wcag.json"; - - try { - const json = await fetch(url, { - duration: "1d", - type: "json" - }); - - const results = {}; - - for (const principle of json.principles) { - for (const guideline of principle.guidelines) { - for (const sc of guideline.successcriteria) { - results[sc.num] = { - principle: principle.handle, - guideline: guideline.handle, - name: sc.handle, - level: sc.level, - versions: sc.versions, - id: sc.id.replace("WCAG2:", "") - }; - } - } - } - - return results; - } catch (error) { - console.error(`Fetch failed in successcriteria.js. ${error}`); - } -} diff --git a/src/_data/totalsbylevel.js b/src/_data/totalsbylevel.js deleted file mode 100644 index 7968018..0000000 --- a/src/_data/totalsbylevel.js +++ /dev/null @@ -1,105 +0,0 @@ -import successCriteria from "./successcriteria.js"; - -export default async function totalsByLevel() { - const totals = { - 2.2: { - A: { - all: 0, - perceivable: 0, - operable: 0, - understandable: 0, - robust: 0 - }, - AA: { - all: 0, - perceivable: 0, - operable: 0, - understandable: 0, - robust: 0 - }, - AAA: { - all: 0, - perceivable: 0, - operable: 0, - understandable: 0, - robust: 0 - } - }, - 2.1: { - A: { - all: 0, - perceivable: 0, - operable: 0, - understandable: 0, - robust: 0 - }, - AA: { - all: 0, - perceivable: 0, - operable: 0, - understandable: 0, - robust: 0 - }, - AAA: { - all: 0, - perceivable: 0, - operable: 0, - understandable: 0, - robust: 0 - } - }, - "2.0": { - A: { - all: 0, - perceivable: 0, - operable: 0, - understandable: 0, - robust: 0 - }, - AA: { - all: 0, - perceivable: 0, - operable: 0, - understandable: 0, - robust: 0 - }, - AAA: { - all: 0, - perceivable: 0, - operable: 0, - understandable: 0, - robust: 0 - } - } - }; - let criteria; - - try { - criteria = await successCriteria(); - } catch (error) { - console.error(`Fetch failed in totalsPerLevel.js. ${error}`); - } - - for (const sc of Object.values(criteria)) { - for (const version of sc.versions) { - if (sc.level !== "") { - totals[version][sc.level].all++; - totals[version][sc.level][sc.principle.toLowerCase()]++; - - if (sc.level === "A") { - totals[version].AA.all++; - totals[version].AA[sc.principle.toLowerCase()]++; - totals[version].AAA.all++; - totals[version].AAA[sc.principle.toLowerCase()]++; - } - - if (sc.level === "AA") { - totals[version].AAA.all++; - totals[version].AAA[sc.principle.toLowerCase()]++; - } - } - } - } - - return totals; -} diff --git a/src/_layouts/report.njk b/src/_layouts/report.njk index c615242..4603dfc 100644 --- a/src/_layouts/report.njk +++ b/src/_layouts/report.njk @@ -30,11 +30,13 @@ layout: base {{ content | safe }}

Results per principle

- {% scTable issueList, targetLevel, targetWcagVersion %} + {% set scTableData = { targetLevel: targetLevel, targetWcagVersion: targetWcagVersion } %} + {% scTable successCriteria, issueList, scTableData %}

Detailed results

- {% scSupport targetLevel, targetWcagVersion, issueList, notSupported, notApplicable %} + {% set scSupportData = { targetLevel: targetLevel, targetWcagVersion: targetWcagVersion, notSupported: notSupported, notApplicable: notApplicable } %} + {% scSupport successCriteria, issueList, scSupportData %} diff --git a/src/_utils/sanitize-number.js b/src/_utils/sanitize-number.js deleted file mode 100644 index bd30a24..0000000 --- a/src/_utils/sanitize-number.js +++ /dev/null @@ -1,7 +0,0 @@ -export default function sanitizeNumber(numberWithDots) { - const numberString = numberWithDots - .split(".") - .map((number) => (Number(number) < 10 ? "0" + number : number)) - .join(""); - return Number(numberString); -} diff --git a/src/_utils/sc-support.js b/src/_utils/sc-support.js index be3f48f..186f388 100644 --- a/src/_utils/sc-support.js +++ b/src/_utils/sc-support.js @@ -1,22 +1,25 @@ import slugify from "@sindresorhus/slugify"; -import successCriteria from "../_data/successcriteria.js"; import matchesLevel from "./matches-level.js"; import matchesVersion from "./matches-version.js"; import scUri from "./sc-uri.js"; -/* eslint max-params: ["error", 5] */ -export default async function scSupport(targetLevel, targetVersion, allIssues, notSupported = [], notApplicable = []) { - let criteria; +export default async function scSupport(successCriteria, allIssues, data) { + const { + targetLevel, + targetWcagVersion, + notSupported = [], + notApplicable = [], + } = data; - try { - criteria = await successCriteria(); - } catch (error) { - console.error(`Fetch failed in sc-support.js. ${error}`); - } - - const filteredCriteria = Object.fromEntries(Object.entries(criteria).filter(([_key, criterion]) => matchesVersion(criterion.versions, targetVersion) && matchesLevel(criterion.level, targetLevel))); + const filteredCriteria = Object.fromEntries( + Object.entries(successCriteria).filter( + ([_key, criterion]) => + matchesVersion(criterion.versions, targetWcagVersion) && + matchesLevel(criterion.level, targetLevel), + ), + ); - let output = ` + let output = ` @@ -28,38 +31,40 @@ export default async function scSupport(targetLevel, targetVersion, allIssues, n `; - for (const key in filteredCriteria) { - if (Object.hasOwn(filteredCriteria, key)) { - const relevantIssues = allIssues.filter((issue) => issue.sc === key); + for (const key in filteredCriteria) { + const relevantIssues = allIssues.filter((issue) => issue.sc === key); + const relevantSevereIssues = relevantIssues.filter( + (issue) => issue.severity === "High", + ); - const relevantSevereIssues = allIssues.filter((issue) => issue.sc === key && issue.severity === "High"); + let support = "Supports"; - let support = "Supports"; - - if (notApplicable.includes(key)) { - support = "Not applicable"; - } + if (notApplicable.includes(key)) { + support = "Not applicable"; + } - if (relevantIssues.length > 0) { - support = "Partially supports"; - } + if (relevantIssues.length > 0) { + support = "Partially supports"; + } - if (relevantSevereIssues.length > 0 || notSupported.includes(key)) { - support = "Does not support"; - } + if (relevantSevereIssues.length > 0 || notSupported.includes(key)) { + support = "Does not support"; + } - const scLabel = relevantIssues.length > 0 ? `${key}: ${criteria[key].name}` : `${key}: ${criteria[key].name}`; + const scLabel = + relevantIssues.length > 0 + ? `${key}: ${successCriteria[key].name}` + : `${key}: ${successCriteria[key].name}`; - const scReferenceLink = scUri(key, criteria); + const scReferenceLink = scUri(key, successCriteria); - output += ``; - } - } + } - output += ` + output += `
${scLabel}${criteria[key].level}${support} + output += `
${scLabel}${successCriteria[key].level}${support} Understanding ${key} (external link)
`; - return output; + return output; } diff --git a/src/_utils/sc-table.js b/src/_utils/sc-table.js index c12bf6c..84d6ca6 100644 --- a/src/_utils/sc-table.js +++ b/src/_utils/sc-table.js @@ -1,31 +1,36 @@ -/* eslint-disable unicorn/no-array-callback-reference */ -/* eslint-disable unicorn/no-array-reduce */ -import totalsByLevel from "../_data/totalsbylevel.js"; +import totalsByLevel from "../_utils/totals-by-level.js"; import countSuccessCriterionOnce from "./count-success-criteria-once.js"; -export default async function scTable(allIssues, targetLevel, targetWcagVersion) { - if (!allIssues || !targetLevel) { - return ""; - } +export default async function scTable(successCriteria, allIssues, data) { + const { targetLevel, targetWcagVersion } = data; - let totalsByLevelData; + let totalsByLevelData; - try { - totalsByLevelData = await totalsByLevel(); - } catch (error) { - console.error(`Fetch failed in sc-table.js. ${error}`); - } + totalsByLevelData = await totalsByLevel(successCriteria); - // Use string representation of WCAG version to avoid unwanted conversion from e.g. 2.0 to index 2 - const totals = totalsByLevelData[targetWcagVersion.toString()][targetLevel]; + // Use string representation of WCAG version to avoid unwanted conversion from e.g. 2.0 to index 2 + const totals = totalsByLevelData[targetWcagVersion.toString()][targetLevel]; - const perceivable = allIssues.filter((issue) => issue.sc.startsWith("1.")).reduce(countSuccessCriterionOnce, []); - const operable = allIssues.filter((issue) => issue.sc.startsWith("2.")).reduce(countSuccessCriterionOnce, []); - const understandable = allIssues.filter((issue) => issue.sc.startsWith("3.")).reduce(countSuccessCriterionOnce, []); - const robust = allIssues.filter((issue) => issue.sc.startsWith("4.")).reduce(countSuccessCriterionOnce, []); + const perceivable = allIssues + .filter((issue) => issue.sc.startsWith("1.")) + .reduce(countSuccessCriterionOnce, []); + const operable = allIssues + .filter((issue) => issue.sc.startsWith("2.")) + .reduce(countSuccessCriterionOnce, []); + const understandable = allIssues + .filter((issue) => issue.sc.startsWith("3.")) + .reduce(countSuccessCriterionOnce, []); + const robust = allIssues + .filter((issue) => issue.sc.startsWith("4.")) + .reduce(countSuccessCriterionOnce, []); - const totalConforming = totals.perceivable - perceivable.length + (totals.operable - operable.length) + (totals.understandable - understandable.length) + (totals.robust - robust.length); - return ` + const totalConforming = + totals.perceivable - + perceivable.length + + (totals.operable - operable.length) + + (totals.understandable - understandable.length) + + (totals.robust - robust.length); + return ` diff --git a/src/_utils/totals-by-level.js b/src/_utils/totals-by-level.js new file mode 100644 index 0000000..d242d05 --- /dev/null +++ b/src/_utils/totals-by-level.js @@ -0,0 +1,96 @@ +export default async function totalsByLevel(successCriteria) { + const totals = { + 2.2: { + A: { + all: 0, + perceivable: 0, + operable: 0, + understandable: 0, + robust: 0, + }, + AA: { + all: 0, + perceivable: 0, + operable: 0, + understandable: 0, + robust: 0, + }, + AAA: { + all: 0, + perceivable: 0, + operable: 0, + understandable: 0, + robust: 0, + }, + }, + 2.1: { + A: { + all: 0, + perceivable: 0, + operable: 0, + understandable: 0, + robust: 0, + }, + AA: { + all: 0, + perceivable: 0, + operable: 0, + understandable: 0, + robust: 0, + }, + AAA: { + all: 0, + perceivable: 0, + operable: 0, + understandable: 0, + robust: 0, + }, + }, + "2.0": { + A: { + all: 0, + perceivable: 0, + operable: 0, + understandable: 0, + robust: 0, + }, + AA: { + all: 0, + perceivable: 0, + operable: 0, + understandable: 0, + robust: 0, + }, + AAA: { + all: 0, + perceivable: 0, + operable: 0, + understandable: 0, + robust: 0, + }, + }, + }; + + for (const sc of Object.values(successCriteria)) { + for (const version of sc.versions) { + if (sc.level !== "") { + totals[version][sc.level].all++; + totals[version][sc.level][sc.principle.toLowerCase()]++; + + if (sc.level === "A") { + totals[version].AA.all++; + totals[version].AA[sc.principle.toLowerCase()]++; + totals[version].AAA.all++; + totals[version].AAA[sc.principle.toLowerCase()]++; + } + + if (sc.level === "AA") { + totals[version].AAA.all++; + totals[version].AAA[sc.principle.toLowerCase()]++; + } + } + } + } + + return totals; +} From bd02fdcf84518861341bd384baecb1da5b012f5d Mon Sep 17 00:00:00 2001 From: Ned Zimmerman Date: Thu, 11 Jul 2024 15:58:17 -0300 Subject: [PATCH 05/18] fix: resolve linting errors --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dc5a06c..ed42d52 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ }, "lint-staged": { "*.css": "stylelint --fix", - "*.{js,cjs,json,jsonc}": "biome check . --write --no-errors-on-unmatched", + "*.{js,cjs,json,jsonc}": "biome check --write --no-errors-on-unmatched", "*.md": [ "markdownlint-cli2 --fix" ] From d34af7b0f059e24943e8600d86f9b670bcdac637 Mon Sep 17 00:00:00 2001 From: Ned Zimmerman Date: Thu, 11 Jul 2024 15:59:30 -0300 Subject: [PATCH 06/18] fix: add Husky configurations --- .husky/commit-msg | 1 + .husky/pre-commit | 1 + 2 files changed, 2 insertions(+) create mode 100755 .husky/commit-msg create mode 100644 .husky/pre-commit diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100755 index 0000000..a3993b1 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1 @@ +npx --no -- commitlint --config commitlint.config.js --edit "$1" diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..718da8a --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx --no lint-staged From 7891010f26786fdce0e2d03cb6b0860497aa7b19 Mon Sep 17 00:00:00 2001 From: Ned Zimmerman Date: Thu, 11 Jul 2024 15:59:48 -0300 Subject: [PATCH 07/18] fix: resolve linting issues --- eleventy.config.js | 208 ++++++++++++++++------------------ package.json | 4 +- src/_utils/sc-support.js | 60 ++++------ src/_utils/sc-table.js | 35 ++---- src/_utils/totals-by-level.js | 176 ++++++++++++++-------------- 5 files changed, 220 insertions(+), 263 deletions(-) diff --git a/eleventy.config.js b/eleventy.config.js index 5ea01ff..b57deb0 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -1,6 +1,6 @@ import { RenderPlugin } from "@11ty/eleventy"; -import syntaxHighlightPlugin from "@11ty/eleventy-plugin-syntaxhighlight"; import fetch from "@11ty/eleventy-fetch"; +import syntaxHighlightPlugin from "@11ty/eleventy-plugin-syntaxhighlight"; import pluginWebc from "@11ty/eleventy-plugin-webc"; // Import {$} from 'execa'; import newIssueUrl from "./src/_utils/new-issue-url.js"; @@ -8,114 +8,102 @@ import scSupport from "./src/_utils/sc-support.js"; import scTable from "./src/_utils/sc-table.js"; export default function eleventy(eleventyConfig) { - eleventyConfig.addNunjucksAsyncShortcode("scTable", scTable); - eleventyConfig.addNunjucksAsyncShortcode("scSupport", scSupport); - eleventyConfig.addShortcode("newIssueUrl", newIssueUrl); - eleventyConfig.addLayoutAlias("report", "report.njk"); - eleventyConfig.addPlugin(pluginWebc); - - eleventyConfig.addGlobalData("successCriteria", async () => { - const url = - "https://raw.githubusercontent.com/w3c/wcag/main/guidelines/wcag.json"; - - try { - const json = await fetch(url, { - duration: "1d", - type: "json", - }); - - const results = {}; - - for (const principle of json.principles) { - for (const guideline of principle.guidelines) { - for (const sc of guideline.successcriteria) { - results[sc.num] = { - number: sc.num, - principle: principle.handle, - guideline: guideline.handle, - name: sc.handle, - level: sc.level, - versions: sc.versions, - id: sc.id.replace("WCAG2:", ""), - }; - } + eleventyConfig.addNunjucksAsyncShortcode("scTable", scTable); + eleventyConfig.addNunjucksAsyncShortcode("scSupport", scSupport); + eleventyConfig.addShortcode("newIssueUrl", newIssueUrl); + eleventyConfig.addLayoutAlias("report", "report.njk"); + eleventyConfig.addPlugin(pluginWebc); + + eleventyConfig.addGlobalData("successCriteria", async () => { + const url = "https://raw.githubusercontent.com/w3c/wcag/main/guidelines/wcag.json"; + + try { + const json = await fetch(url, { + duration: "1d", + type: "json" + }); + + const results = {}; + + for (const principle of json.principles) { + for (const guideline of principle.guidelines) { + for (const sc of guideline.successcriteria) { + results[sc.num] = { + number: sc.num, + principle: principle.handle, + guideline: guideline.handle, + name: sc.handle, + level: sc.level, + versions: sc.versions, + id: sc.id.replace("WCAG2:", "") + }; + } + } + } + + return results; + } catch (error) { + console.error(`Fetch failed in successcriteria.js. ${error}`); } - } - - return results; - } catch (error) { - console.error(`Fetch failed in successcriteria.js. ${error}`); - } - }); - - eleventyConfig.addPlugin(RenderPlugin); - eleventyConfig.addPlugin(syntaxHighlightPlugin); - - eleventyConfig.addFilter("withoutTips", (issues) => - issues.filter((item) => Object.hasOwn(item, "sc") && item.sc !== ""), - ); - - eleventyConfig.addFilter("withoutViolations", (issues) => - issues.filter((item) => item.sc === "" || !Object.hasOwn(item, "sc")), - ); - - eleventyConfig.addShortcode( - "renderString", - async function (content, templateFormat) { - const renderManager = new RenderPlugin.RenderManager(); - const result = await renderManager.compile(content, templateFormat); - return result.call(this); - }, - ); - - eleventyConfig.addAsyncFilter("formatDate", (value) => - new Date(value).toLocaleString("en-CA", { - year: "numeric", - month: "long", - day: "numeric", - }), - ); - - eleventyConfig.addCollection("reports", (collectionApi) => - collectionApi.getFilteredByGlob("src/collections/reports/*.md"), - ); - - eleventyConfig.addPassthroughCopy({ - "src/admin/config.yml": "admin/config.yml", - }); - - eleventyConfig.addPassthroughCopy({ - "src/assets": "assets", - }); - - eleventyConfig.addPassthroughCopy({ - "node_modules/a11y-syntax-highlighting/dist/prism/a11y-dark.min.css": - "assets/styles/a11y-dark.min.css", - "node_modules/@zachleat/table-saw/table-saw.js": - "assets/scripts/table-saw.js", - }); - - // EleventyConfig.on( - // "eleventy.after", - // async ({ _dir, results, _runMode, _outputMode }) => { - // for (const result of results) { - // if (result.inputPath.startsWith("./src/collections/reports/")) { - // const { stdout } = - // await $`weasyprint --pdf-variant=pdf/ua-1 ${result.outputPath} ./_site${result.url}report.pdf`; - // } - // } - // }, - // ); - - return { - dir: { - input: "src", - includes: "_includes", - layouts: "_layouts", - data: "_data", - }, - templateFormats: ["njk", "md", "css", "png", "jpg", "svg"], - htmlTemplateEngine: "njk", - markdownTemplateEngine: "njk", - }; + }); + + eleventyConfig.addPlugin(RenderPlugin); + eleventyConfig.addPlugin(syntaxHighlightPlugin); + + eleventyConfig.addFilter("withoutTips", (issues) => issues.filter((item) => Object.hasOwn(item, "sc") && item.sc !== "")); + + eleventyConfig.addFilter("withoutViolations", (issues) => issues.filter((item) => item.sc === "" || !Object.hasOwn(item, "sc"))); + + eleventyConfig.addShortcode("renderString", async function (content, templateFormat) { + const renderManager = new RenderPlugin.RenderManager(); + const result = await renderManager.compile(content, templateFormat); + return result.call(this); + }); + + eleventyConfig.addAsyncFilter("formatDate", (value) => + new Date(value).toLocaleString("en-CA", { + year: "numeric", + month: "long", + day: "numeric" + }) + ); + + eleventyConfig.addCollection("reports", (collectionApi) => collectionApi.getFilteredByGlob("src/collections/reports/*.md")); + + eleventyConfig.addPassthroughCopy({ + "src/admin/config.yml": "admin/config.yml" + }); + + eleventyConfig.addPassthroughCopy({ + "src/assets": "assets" + }); + + eleventyConfig.addPassthroughCopy({ + "node_modules/a11y-syntax-highlighting/dist/prism/a11y-dark.min.css": "assets/styles/a11y-dark.min.css", + "node_modules/@zachleat/table-saw/table-saw.js": "assets/scripts/table-saw.js" + }); + + // EleventyConfig.on( + // "eleventy.after", + // async ({ _dir, results, _runMode, _outputMode }) => { + // for (const result of results) { + // if (result.inputPath.startsWith("./src/collections/reports/")) { + // const { stdout } = + // await $`weasyprint --pdf-variant=pdf/ua-1 ${result.outputPath} ./_site${result.url}report.pdf`; + // } + // } + // }, + // ); + + return { + dir: { + input: "src", + includes: "_includes", + layouts: "_layouts", + data: "_data" + }, + templateFormats: ["njk", "md", "css", "png", "jpg", "svg"], + htmlTemplateEngine: "njk", + markdownTemplateEngine: "njk" + }; } diff --git a/package.json b/package.json index ed42d52..c8a59c0 100644 --- a/package.json +++ b/package.json @@ -59,8 +59,6 @@ "lint-staged": { "*.css": "stylelint --fix", "*.{js,cjs,json,jsonc}": "biome check --write --no-errors-on-unmatched", - "*.md": [ - "markdownlint-cli2 --fix" - ] + "*.md": ["markdownlint-cli2 --fix"] } } diff --git a/src/_utils/sc-support.js b/src/_utils/sc-support.js index 186f388..a6c161a 100644 --- a/src/_utils/sc-support.js +++ b/src/_utils/sc-support.js @@ -4,22 +4,11 @@ import matchesVersion from "./matches-version.js"; import scUri from "./sc-uri.js"; export default async function scSupport(successCriteria, allIssues, data) { - const { - targetLevel, - targetWcagVersion, - notSupported = [], - notApplicable = [], - } = data; + const { targetLevel, targetWcagVersion, notSupported = [], notApplicable = [] } = data; - const filteredCriteria = Object.fromEntries( - Object.entries(successCriteria).filter( - ([_key, criterion]) => - matchesVersion(criterion.versions, targetWcagVersion) && - matchesLevel(criterion.level, targetLevel), - ), - ); + const filteredCriteria = Object.fromEntries(Object.entries(successCriteria).filter(([_key, criterion]) => matchesVersion(criterion.versions, targetWcagVersion) && matchesLevel(criterion.level, targetLevel))); - let output = ` + let output = `
@@ -31,40 +20,35 @@ export default async function scSupport(successCriteria, allIssues, data) { `; - for (const key in filteredCriteria) { - const relevantIssues = allIssues.filter((issue) => issue.sc === key); - const relevantSevereIssues = relevantIssues.filter( - (issue) => issue.severity === "High", - ); + for (const key in filteredCriteria) { + const relevantIssues = allIssues.filter((issue) => issue.sc === key); + const relevantSevereIssues = relevantIssues.filter((issue) => issue.severity === "High"); - let support = "Supports"; + let support = "Supports"; - if (notApplicable.includes(key)) { - support = "Not applicable"; - } + if (notApplicable.includes(key)) { + support = "Not applicable"; + } - if (relevantIssues.length > 0) { - support = "Partially supports"; - } + if (relevantIssues.length > 0) { + support = "Partially supports"; + } - if (relevantSevereIssues.length > 0 || notSupported.includes(key)) { - support = "Does not support"; - } + if (relevantSevereIssues.length > 0 || notSupported.includes(key)) { + support = "Does not support"; + } - const scLabel = - relevantIssues.length > 0 - ? `${key}: ${successCriteria[key].name}` - : `${key}: ${successCriteria[key].name}`; + const scLabel = relevantIssues.length > 0 ? `${key}: ${successCriteria[key].name}` : `${key}: ${successCriteria[key].name}`; - const scReferenceLink = scUri(key, successCriteria); + const scReferenceLink = scUri(key, successCriteria); - output += ``; - } + } - output += ` + output += `
${scLabel}${successCriteria[key].level}${support} + output += `
${scLabel}${successCriteria[key].level}${support} Understanding ${key} (external link)
`; - return output; + return output; } diff --git a/src/_utils/sc-table.js b/src/_utils/sc-table.js index 84d6ca6..8efb965 100644 --- a/src/_utils/sc-table.js +++ b/src/_utils/sc-table.js @@ -2,35 +2,22 @@ import totalsByLevel from "../_utils/totals-by-level.js"; import countSuccessCriterionOnce from "./count-success-criteria-once.js"; export default async function scTable(successCriteria, allIssues, data) { - const { targetLevel, targetWcagVersion } = data; + const { targetLevel, targetWcagVersion } = data; - let totalsByLevelData; + let totalsByLevelData; - totalsByLevelData = await totalsByLevel(successCriteria); + totalsByLevelData = await totalsByLevel(successCriteria); - // Use string representation of WCAG version to avoid unwanted conversion from e.g. 2.0 to index 2 - const totals = totalsByLevelData[targetWcagVersion.toString()][targetLevel]; + // Use string representation of WCAG version to avoid unwanted conversion from e.g. 2.0 to index 2 + const totals = totalsByLevelData[targetWcagVersion.toString()][targetLevel]; - const perceivable = allIssues - .filter((issue) => issue.sc.startsWith("1.")) - .reduce(countSuccessCriterionOnce, []); - const operable = allIssues - .filter((issue) => issue.sc.startsWith("2.")) - .reduce(countSuccessCriterionOnce, []); - const understandable = allIssues - .filter((issue) => issue.sc.startsWith("3.")) - .reduce(countSuccessCriterionOnce, []); - const robust = allIssues - .filter((issue) => issue.sc.startsWith("4.")) - .reduce(countSuccessCriterionOnce, []); + const perceivable = allIssues.filter((issue) => issue.sc.startsWith("1.")).reduce(countSuccessCriterionOnce, []); + const operable = allIssues.filter((issue) => issue.sc.startsWith("2.")).reduce(countSuccessCriterionOnce, []); + const understandable = allIssues.filter((issue) => issue.sc.startsWith("3.")).reduce(countSuccessCriterionOnce, []); + const robust = allIssues.filter((issue) => issue.sc.startsWith("4.")).reduce(countSuccessCriterionOnce, []); - const totalConforming = - totals.perceivable - - perceivable.length + - (totals.operable - operable.length) + - (totals.understandable - understandable.length) + - (totals.robust - robust.length); - return ` + const totalConforming = totals.perceivable - perceivable.length + (totals.operable - operable.length) + (totals.understandable - understandable.length) + (totals.robust - robust.length); + return ` diff --git a/src/_utils/totals-by-level.js b/src/_utils/totals-by-level.js index d242d05..dc46d7e 100644 --- a/src/_utils/totals-by-level.js +++ b/src/_utils/totals-by-level.js @@ -1,96 +1,96 @@ export default async function totalsByLevel(successCriteria) { - const totals = { - 2.2: { - A: { - all: 0, - perceivable: 0, - operable: 0, - understandable: 0, - robust: 0, - }, - AA: { - all: 0, - perceivable: 0, - operable: 0, - understandable: 0, - robust: 0, - }, - AAA: { - all: 0, - perceivable: 0, - operable: 0, - understandable: 0, - robust: 0, - }, - }, - 2.1: { - A: { - all: 0, - perceivable: 0, - operable: 0, - understandable: 0, - robust: 0, - }, - AA: { - all: 0, - perceivable: 0, - operable: 0, - understandable: 0, - robust: 0, - }, - AAA: { - all: 0, - perceivable: 0, - operable: 0, - understandable: 0, - robust: 0, - }, - }, - "2.0": { - A: { - all: 0, - perceivable: 0, - operable: 0, - understandable: 0, - robust: 0, - }, - AA: { - all: 0, - perceivable: 0, - operable: 0, - understandable: 0, - robust: 0, - }, - AAA: { - all: 0, - perceivable: 0, - operable: 0, - understandable: 0, - robust: 0, - }, - }, - }; + const totals = { + 2.2: { + A: { + all: 0, + perceivable: 0, + operable: 0, + understandable: 0, + robust: 0 + }, + AA: { + all: 0, + perceivable: 0, + operable: 0, + understandable: 0, + robust: 0 + }, + AAA: { + all: 0, + perceivable: 0, + operable: 0, + understandable: 0, + robust: 0 + } + }, + 2.1: { + A: { + all: 0, + perceivable: 0, + operable: 0, + understandable: 0, + robust: 0 + }, + AA: { + all: 0, + perceivable: 0, + operable: 0, + understandable: 0, + robust: 0 + }, + AAA: { + all: 0, + perceivable: 0, + operable: 0, + understandable: 0, + robust: 0 + } + }, + "2.0": { + A: { + all: 0, + perceivable: 0, + operable: 0, + understandable: 0, + robust: 0 + }, + AA: { + all: 0, + perceivable: 0, + operable: 0, + understandable: 0, + robust: 0 + }, + AAA: { + all: 0, + perceivable: 0, + operable: 0, + understandable: 0, + robust: 0 + } + } + }; - for (const sc of Object.values(successCriteria)) { - for (const version of sc.versions) { - if (sc.level !== "") { - totals[version][sc.level].all++; - totals[version][sc.level][sc.principle.toLowerCase()]++; + for (const sc of Object.values(successCriteria)) { + for (const version of sc.versions) { + if (sc.level !== "") { + totals[version][sc.level].all++; + totals[version][sc.level][sc.principle.toLowerCase()]++; - if (sc.level === "A") { - totals[version].AA.all++; - totals[version].AA[sc.principle.toLowerCase()]++; - totals[version].AAA.all++; - totals[version].AAA[sc.principle.toLowerCase()]++; - } + if (sc.level === "A") { + totals[version].AA.all++; + totals[version].AA[sc.principle.toLowerCase()]++; + totals[version].AAA.all++; + totals[version].AAA[sc.principle.toLowerCase()]++; + } - if (sc.level === "AA") { - totals[version].AAA.all++; - totals[version].AAA[sc.principle.toLowerCase()]++; + if (sc.level === "AA") { + totals[version].AAA.all++; + totals[version].AAA[sc.principle.toLowerCase()]++; + } + } } - } } - } - return totals; + return totals; } From 0a3fe7c0cc5adc078f42798c692c8a6ff877affb Mon Sep 17 00:00:00 2001 From: Ned Zimmerman Date: Thu, 11 Jul 2024 16:03:00 -0300 Subject: [PATCH 08/18] ci: restore coverage step --- .github/workflows/lint-and-test.yml | 44 ++++++++++++++--------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/.github/workflows/lint-and-test.yml b/.github/workflows/lint-and-test.yml index 1286ae7..3016683 100644 --- a/.github/workflows/lint-and-test.yml +++ b/.github/workflows/lint-and-test.yml @@ -21,25 +21,25 @@ jobs: run: | npm ci npm run lint - # npm run test - # - name: Save code coverage to artifact - # uses: actions/upload-artifact@v4 - # with: - # name: code-coverage - # path: "coverage/clover.xml" - # retention-days: 5 - # upload-coverage: - # name: Upload code coverage - # runs-on: ubuntu-latest - # needs: - # - lint-test - # steps: - # - name: Fetch code coverage artifact - # uses: actions/download-artifact@v4 - # with: - # name: code-coverage - # - name: Upload coverage to Codecov - # uses: codecov/codecov-action@v4 - # with: - # token: ${{ secrets.CODECOV_TOKEN }} - # fail_ci_if_error: true + npm run test + - name: Save code coverage to artifact + uses: actions/upload-artifact@v4 + with: + name: code-coverage + path: "coverage/clover.xml" + retention-days: 5 + upload-coverage: + name: Upload code coverage + runs-on: ubuntu-latest + needs: + - lint-test + steps: + - name: Fetch code coverage artifact + uses: actions/download-artifact@v4 + with: + name: code-coverage + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: true From 664e4a46126a074cb527d1dd46f5949ec23ae07e Mon Sep 17 00:00:00 2001 From: Ned Zimmerman Date: Thu, 11 Jul 2024 16:06:06 -0300 Subject: [PATCH 09/18] ci: fix indentation issue --- .github/workflows/lint-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-and-test.yml b/.github/workflows/lint-and-test.yml index 3016683..7eee5e3 100644 --- a/.github/workflows/lint-and-test.yml +++ b/.github/workflows/lint-and-test.yml @@ -21,7 +21,7 @@ jobs: run: | npm ci npm run lint - npm run test + npm run test - name: Save code coverage to artifact uses: actions/upload-artifact@v4 with: From 1138473cb458861e0626376d93fe25171029df97 Mon Sep 17 00:00:00 2001 From: Ned Zimmerman Date: Thu, 11 Jul 2024 16:33:43 -0300 Subject: [PATCH 10/18] feat: provide SC support as computed data --- eleventy.config.js | 6 -- package-lock.json | 103 +------------------- package.json | 1 - src/_data/scData.json | 4 + src/_layouts/report.njk | 8 +- src/collections/reports/reports.11tydata.js | 9 ++ 6 files changed, 19 insertions(+), 112 deletions(-) create mode 100644 src/_data/scData.json create mode 100644 src/collections/reports/reports.11tydata.js diff --git a/eleventy.config.js b/eleventy.config.js index b57deb0..4f54cb6 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -1,18 +1,12 @@ import { RenderPlugin } from "@11ty/eleventy"; import fetch from "@11ty/eleventy-fetch"; import syntaxHighlightPlugin from "@11ty/eleventy-plugin-syntaxhighlight"; -import pluginWebc from "@11ty/eleventy-plugin-webc"; // Import {$} from 'execa'; import newIssueUrl from "./src/_utils/new-issue-url.js"; -import scSupport from "./src/_utils/sc-support.js"; -import scTable from "./src/_utils/sc-table.js"; export default function eleventy(eleventyConfig) { - eleventyConfig.addNunjucksAsyncShortcode("scTable", scTable); - eleventyConfig.addNunjucksAsyncShortcode("scSupport", scSupport); eleventyConfig.addShortcode("newIssueUrl", newIssueUrl); eleventyConfig.addLayoutAlias("report", "report.njk"); - eleventyConfig.addPlugin(pluginWebc); eleventyConfig.addGlobalData("successCriteria", async () => { const url = "https://raw.githubusercontent.com/w3c/wcag/main/guidelines/wcag.json"; diff --git a/package-lock.json b/package-lock.json index b5f4f08..6851da3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,6 @@ "@11ty/eleventy": "3.0.0-alpha.16", "@11ty/eleventy-fetch": "^4.0.1", "@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0", - "@11ty/eleventy-plugin-webc": "^0.11.2", "@zachleat/table-saw": "^1.0.6", "a11y-syntax-highlighting": "^0.2.0", "execa": "^9.3.0", @@ -199,37 +198,6 @@ "url": "https://opencollective.com/11ty" } }, - "node_modules/@11ty/eleventy-plugin-webc": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/@11ty/eleventy-plugin-webc/-/eleventy-plugin-webc-0.11.2.tgz", - "integrity": "sha512-oa/XlAqI5KtVO7M14qaN92D2yJfBEMMSb66YWY6YZVbRqFSVbjO4WmRJ2Ti2ZZb1FNvxj4ypGNV8VJleGE69xw==", - "dependencies": { - "@11ty/eleventy-plugin-bundle": "^1.0.4", - "@11ty/webc": "^0.11.0" - }, - "engines": { - "node": ">=14.18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/11ty" - } - }, - "node_modules/@11ty/eleventy-plugin-webc/node_modules/@11ty/eleventy-plugin-bundle": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@11ty/eleventy-plugin-bundle/-/eleventy-plugin-bundle-1.0.5.tgz", - "integrity": "sha512-Esv97j+mOo/yfxjaWl4j8CyszOBsRjU/DOUWOBqVnnDLM8VDXeus2LTJUxF70nAU0g+z+b6fRn8fKnm6b2a/UQ==", - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/11ty" - } - }, "node_modules/@11ty/eleventy-utils": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@11ty/eleventy-utils/-/eleventy-utils-1.0.3.tgz", @@ -275,63 +243,6 @@ "node": ">= 6" } }, - "node_modules/@11ty/webc": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/@11ty/webc/-/webc-0.11.4.tgz", - "integrity": "sha512-q1GMcjNnx9PxUr6jyTT5CdDFma3JWkT5D45wRNYUQ/B4cxTTxpC15b2rYdzNaGuSqB6tsArQ9Qh4BPqg6Xo9cA==", - "dependencies": { - "@11ty/eleventy-utils": "^1.0.1", - "css-tree": "^2.3.1", - "dependency-graph": "^0.11.0", - "entities": "^4.4.0", - "fast-glob": "^3.2.12", - "is-glob": "^4.0.3", - "nanoid": "^4.0.1", - "node-retrieve-globals": "^2.0.7", - "parse5": "^7.1.2" - }, - "engines": { - "node": ">=14.18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/11ty" - } - }, - "node_modules/@11ty/webc/node_modules/dependency-graph": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", - "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/@11ty/webc/node_modules/nanoid": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.2.tgz", - "integrity": "sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.js" - }, - "engines": { - "node": "^14 || ^16 || >=18" - } - }, - "node_modules/@11ty/webc/node_modules/node-retrieve-globals": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/node-retrieve-globals/-/node-retrieve-globals-2.0.8.tgz", - "integrity": "sha512-mVimS/m8H28kyMdvOIfyMCM8wFNiKXM83ag1yHYP297iVmlCSmCh7Ih4b+ig9/DZ2+LbXZCPLDSZO4yRa5ttyg==", - "dependencies": { - "acorn": "^8.8.2", - "acorn-walk": "^8.2.0" - } - }, "node_modules/@babel/code-frame": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", @@ -2620,6 +2531,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, "license": "MIT", "dependencies": { "mdn-data": "2.0.30", @@ -5152,6 +5064,7 @@ "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true, "license": "CC0-1.0" }, "node_modules/mdurl": { @@ -5857,17 +5770,6 @@ "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==", "license": "MIT" }, - "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -6717,6 +6619,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" diff --git a/package.json b/package.json index c8a59c0..55fc0b6 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ "@11ty/eleventy": "3.0.0-alpha.16", "@11ty/eleventy-fetch": "^4.0.1", "@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0", - "@11ty/eleventy-plugin-webc": "^0.11.2", "@zachleat/table-saw": "^1.0.6", "a11y-syntax-highlighting": "^0.2.0", "execa": "^9.3.0", diff --git a/src/_data/scData.json b/src/_data/scData.json new file mode 100644 index 0000000..8b68cd9 --- /dev/null +++ b/src/_data/scData.json @@ -0,0 +1,4 @@ +{ + "successCriteria": [ + ] +} diff --git a/src/_layouts/report.njk b/src/_layouts/report.njk index 4603dfc..2a13f8d 100644 --- a/src/_layouts/report.njk +++ b/src/_layouts/report.njk @@ -30,13 +30,11 @@ layout: base {{ content | safe }}

Results per principle

- {% set scTableData = { targetLevel: targetLevel, targetWcagVersion: targetWcagVersion } %} - {% scTable successCriteria, issueList, scTableData %} + {{ scTable | safe }}

Detailed results

- - {% set scSupportData = { targetLevel: targetLevel, targetWcagVersion: targetWcagVersion, notSupported: notSupported, notApplicable: notApplicable } %} - {% scSupport successCriteria, issueList, scSupportData %} + + {{ scSupport | safe }} diff --git a/src/collections/reports/reports.11tydata.js b/src/collections/reports/reports.11tydata.js new file mode 100644 index 0000000..1224661 --- /dev/null +++ b/src/collections/reports/reports.11tydata.js @@ -0,0 +1,9 @@ +import scSupport from "../../_utils/sc-support.js"; +import scTable from "../../_utils/sc-table.js"; + +export default { + eleventyComputed: { + scSupport: (data) => scSupport(data.successCriteria, data.issues, data), + scTable: (data) => scTable(data.successCriteria, data.issues, data) + } +}; From 45fe917e88f33665c4a10b121f823b09ea95765f Mon Sep 17 00:00:00 2001 From: Ned Zimmerman Date: Thu, 11 Jul 2024 16:48:46 -0300 Subject: [PATCH 11/18] feat: render in templates --- src/_layouts/report.njk | 37 ++++++++++++++++++++++++--- src/_utils/sc-support.js | 30 ++++++++-------------- src/_utils/sc-table.js | 54 +++++++++++++++++----------------------- 3 files changed, 67 insertions(+), 54 deletions(-) diff --git a/src/_layouts/report.njk b/src/_layouts/report.njk index 2a13f8d..76ea04e 100644 --- a/src/_layouts/report.njk +++ b/src/_layouts/report.njk @@ -30,11 +30,42 @@ layout: base {{ content | safe }}

Results per principle

- {{ scTable | safe }} +
+ + + + + + + + {% for label, group in scTable %} + + + + + {% endfor %} + +
PrincipleResults by principle
{{ label }}{{ group.supported }} of {{ group.total }}

Detailed results

- {{ scSupport | safe }} + + + + + + + + + + + {% for criterion in scSupport %} + + {% endfor %} + +
Success criteriaLevelSupportReference
{% if criterion.link %}{% endif %}{{ criterion.label }}{% if criterion.link %}{% endif %}{{ criterion.level }}{{ criterion.support }} + Understanding {{ criterion.key }} (external link) +
@@ -110,7 +141,7 @@ layout: base {% set newSc = false %} {% endif %} {% if newSc %} -

{{ sc }}: {{ successcriteria[sc].name }} (Level {{ successcriteria[sc].level }})

+

{{ sc }}: {{ successCriteria[sc].name }} (Level {{ successCriteria[sc].level }})

{% endif %} {% if issue.fileSlug !== page.fileSlug %} diff --git a/src/_utils/sc-support.js b/src/_utils/sc-support.js index a6c161a..f3ea5a6 100644 --- a/src/_utils/sc-support.js +++ b/src/_utils/sc-support.js @@ -8,17 +8,7 @@ export default async function scSupport(successCriteria, allIssues, data) { const filteredCriteria = Object.fromEntries(Object.entries(successCriteria).filter(([_key, criterion]) => matchesVersion(criterion.versions, targetWcagVersion) && matchesLevel(criterion.level, targetLevel))); - let output = ` - - - - - - - - - - `; + let result = []; for (const key in filteredCriteria) { const relevantIssues = allIssues.filter((issue) => issue.sc === key); @@ -38,17 +28,17 @@ export default async function scSupport(successCriteria, allIssues, data) { support = "Does not support"; } - const scLabel = relevantIssues.length > 0 ? `${key}: ${successCriteria[key].name}` : `${key}: ${successCriteria[key].name}`; - const scReferenceLink = scUri(key, successCriteria); - output += ``; + result.push({ + key, + label: `${key}: ${successCriteria[key].name}`, + level: successCriteria[key].level, + support, + link: relevantIssues.length > 0 ? `#${slugify(successCriteria[key].name)}` : false, + referenceLink: scReferenceLink + }); } - output += ` -
Success criteriaLevelSupportReference
${scLabel}${successCriteria[key].level}${support} - Understanding ${key} (external link) -
`; - - return output; + return result; } diff --git a/src/_utils/sc-table.js b/src/_utils/sc-table.js index 8efb965..77779ca 100644 --- a/src/_utils/sc-table.js +++ b/src/_utils/sc-table.js @@ -17,35 +17,27 @@ export default async function scTable(successCriteria, allIssues, data) { const robust = allIssues.filter((issue) => issue.sc.startsWith("4.")).reduce(countSuccessCriterionOnce, []); const totalConforming = totals.perceivable - perceivable.length + (totals.operable - operable.length) + (totals.understandable - understandable.length) + (totals.robust - robust.length); - return ` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PrincipleResults by principle
Perceivable${totals.perceivable - perceivable.length} of ${totals.perceivable}
Operable${totals.operable - operable.length} of ${totals.operable}
Understandable${totals.understandable - understandable.length} of ${totals.understandable}
Robust${totals.robust - robust.length} of ${totals.robust}
Total${totalConforming} of ${totals.all}
`; + + return { + Perceivable: { + supported: totals.perceivable - perceivable.length, + total: totals.perceivable + }, + Operable: { + supported: totals.operable - operable.length, + total: totals.operable + }, + Understandable: { + supported: totals.understandable - understandable.length, + total: totals.understandable + }, + Robust: { + supported: totals.robust - robust.length, + total: totals.robust + }, + Total: { + supported: totalConforming, + total: totals.all + } + }; } From abab312ed1231667c85f2bb92bf241bed866ea70 Mon Sep 17 00:00:00 2001 From: Ned Zimmerman Date: Thu, 11 Jul 2024 23:38:51 -0300 Subject: [PATCH 12/18] feat: simplify --- src/_layouts/report.njk | 15 +++---- src/_utils/count-success-criteria-once.js | 11 ----- src/_utils/determine-failures.js | 7 ++++ .../{sc-table.js => results-by-principle.js} | 15 ++++--- ...ort.js => results-by-success-criterion.js} | 8 ++-- src/assets/scripts/criteria.js | 41 +++++++++++++++---- src/collections/reports/example-client.md | 27 +++++++++++- src/collections/reports/reports.11tydata.js | 8 ++-- 8 files changed, 88 insertions(+), 44 deletions(-) delete mode 100644 src/_utils/count-success-criteria-once.js create mode 100644 src/_utils/determine-failures.js rename src/_utils/{sc-table.js => results-by-principle.js} (67%) rename src/_utils/{sc-support.js => results-by-success-criterion.js} (79%) diff --git a/src/_layouts/report.njk b/src/_layouts/report.njk index 76ea04e..d3c0fe9 100644 --- a/src/_layouts/report.njk +++ b/src/_layouts/report.njk @@ -28,7 +28,7 @@ layout: base

Executive summary

{{ content | safe }} -

Results per principle

+

Results by principle

@@ -38,7 +38,7 @@ layout: base - {% for label, group in scTable %} + {% for label, group in resultsByPrinciple %} @@ -59,7 +59,7 @@ layout: base - {% for criterion in scSupport %} + {% for criterion in resultsBySuccessCriterion %} @@ -134,7 +134,7 @@ layout: base

Issues

{% set sc = '' %} {% for issue in issueList %} - {% if sc !== issue.sc %} + {% if sc != issue.sc %} {% set sc = issue.sc %} {% set newSc = true %} {% else %} @@ -142,9 +142,7 @@ layout: base {% endif %} {% if newSc %}

{{ sc }}: {{ successCriteria[sc].name }} (Level {{ successCriteria[sc].level }})

-
{% endif %} - {% if issue.fileSlug !== page.fileSlug %}

{{ issue.title }}

@@ -171,10 +169,7 @@ layout: base
- {% endif %} - {% if newSc %} - - {% endif %} + {% endfor %} diff --git a/src/_utils/count-success-criteria-once.js b/src/_utils/count-success-criteria-once.js deleted file mode 100644 index e4363e2..0000000 --- a/src/_utils/count-success-criteria-once.js +++ /dev/null @@ -1,11 +0,0 @@ -export default function countSuccessCriteriaOnce(accumulator, current) { - for (let i = 0; i < accumulator.length; i++) { - if (accumulator[i].sc === current.sc) { - return accumulator; - } - } - - accumulator.push(current); - - return accumulator; -} diff --git a/src/_utils/determine-failures.js b/src/_utils/determine-failures.js new file mode 100644 index 0000000..d5dd84a --- /dev/null +++ b/src/_utils/determine-failures.js @@ -0,0 +1,7 @@ +export default function determineFailures(issues, principle, notSupported) { + const failuresFromIssues = issues.filter((issue) => issue.sc.startsWith(principle) && issue.severity === "High").map((issue) => issue.sc); + + const manualFailures = notSupported.filter((sc) => sc.startsWith(principle)); + + return [...new Set(failuresFromIssues.concat(manualFailures))]; +} diff --git a/src/_utils/sc-table.js b/src/_utils/results-by-principle.js similarity index 67% rename from src/_utils/sc-table.js rename to src/_utils/results-by-principle.js index 77779ca..355e276 100644 --- a/src/_utils/sc-table.js +++ b/src/_utils/results-by-principle.js @@ -1,20 +1,23 @@ import totalsByLevel from "../_utils/totals-by-level.js"; import countSuccessCriterionOnce from "./count-success-criteria-once.js"; +import determineFailures from "./determine-failures.js"; -export default async function scTable(successCriteria, allIssues, data) { - const { targetLevel, targetWcagVersion } = data; +export default async function resultsByPrinciple(data) { + const { successCriteria, issues, targetLevel, targetWcagVersion, notSupported } = data; let totalsByLevelData; totalsByLevelData = await totalsByLevel(successCriteria); + const issuesWithCriteria = issues.filter((issue) => issue?.sc !== ""); + // Use string representation of WCAG version to avoid unwanted conversion from e.g. 2.0 to index 2 const totals = totalsByLevelData[targetWcagVersion.toString()][targetLevel]; - const perceivable = allIssues.filter((issue) => issue.sc.startsWith("1.")).reduce(countSuccessCriterionOnce, []); - const operable = allIssues.filter((issue) => issue.sc.startsWith("2.")).reduce(countSuccessCriterionOnce, []); - const understandable = allIssues.filter((issue) => issue.sc.startsWith("3.")).reduce(countSuccessCriterionOnce, []); - const robust = allIssues.filter((issue) => issue.sc.startsWith("4.")).reduce(countSuccessCriterionOnce, []); + const perceivable = determineFailures(issuesWithCriteria, "1.", notSupported); + const operable = determineFailures(issuesWithCriteria, "2.", notSupported); + const understandable = determineFailures(issuesWithCriteria, "3.", notSupported); + const robust = determineFailures(issuesWithCriteria, "4.", notSupported); const totalConforming = totals.perceivable - perceivable.length + (totals.operable - operable.length) + (totals.understandable - understandable.length) + (totals.robust - robust.length); diff --git a/src/_utils/sc-support.js b/src/_utils/results-by-success-criterion.js similarity index 79% rename from src/_utils/sc-support.js rename to src/_utils/results-by-success-criterion.js index f3ea5a6..a41f988 100644 --- a/src/_utils/sc-support.js +++ b/src/_utils/results-by-success-criterion.js @@ -3,15 +3,17 @@ import matchesLevel from "./matches-level.js"; import matchesVersion from "./matches-version.js"; import scUri from "./sc-uri.js"; -export default async function scSupport(successCriteria, allIssues, data) { - const { targetLevel, targetWcagVersion, notSupported = [], notApplicable = [] } = data; +export default async function resultsBySuccessCriterion(data) { + const { issues, successCriteria, targetLevel, targetWcagVersion, notSupported = [], notApplicable = [] } = data; const filteredCriteria = Object.fromEntries(Object.entries(successCriteria).filter(([_key, criterion]) => matchesVersion(criterion.versions, targetWcagVersion) && matchesLevel(criterion.level, targetLevel))); let result = []; + const issuesWithCriteria = issues.filter((issue) => issue?.sc !== ""); + for (const key in filteredCriteria) { - const relevantIssues = allIssues.filter((issue) => issue.sc === key); + const relevantIssues = issuesWithCriteria.filter((issue) => issue.sc === key); const relevantSevereIssues = relevantIssues.filter((issue) => issue.severity === "High"); let support = "Supports"; diff --git a/src/assets/scripts/criteria.js b/src/assets/scripts/criteria.js index 5796da9..c42f073 100644 --- a/src/assets/scripts/criteria.js +++ b/src/assets/scripts/criteria.js @@ -2,14 +2,37 @@ const criteria = document.querySelectorAll("#executive-summary h3, #about-this-report h3, #issues h3, #scope h3"); for (const criterion of criteria) { - const button = document.createElement("button"); - button.setAttribute("type", "button"); - button.setAttribute("aria-expanded", false); - button.innerHTML = ` ${criterion.textContent}`; - button.addEventListener("click", (event) => { - const expanded = event.target.getAttribute("aria-expanded") === "false" || false; - event.target.setAttribute("aria-expanded", expanded); + criterion.innerHTML = ``; + + const getContent = (elem) => { + let elems = []; + while (elem.nextElementSibling && elem.nextElementSibling.tagName !== "H2" && elem.nextElementSibling.tagName !== "H3") { + elems.push(elem.nextElementSibling); + elem = elem.nextElementSibling; + } + + elems.forEach((node) => { + node.parentNode.removeChild(node); + }); + + return elems; + }; + + let contents = getContent(criterion); + + let wrapper = document.createElement("div"); + + contents.forEach((node) => { + wrapper.appendChild(node); }); - criterion.textContent = ""; - criterion.append(button); + + criterion.parentNode.insertBefore(wrapper, criterion.nextElementSibling); + + let btn = criterion.querySelector("button"); + + btn.onclick = () => { + let expanded = btn.getAttribute("aria-expanded") === "true" || false; + + btn.setAttribute("aria-expanded", !expanded); + }; } diff --git a/src/collections/reports/example-client.md b/src/collections/reports/example-client.md index 4a3220c..bd05e6b 100644 --- a/src/collections/reports/example-client.md +++ b/src/collections/reports/example-client.md @@ -44,7 +44,7 @@ technologies: partiallySupported: - 1.2.1 - 1.2.3 -unsupported: +notSupported: - 1.4.1 notApplicable: - 1.2.3 @@ -97,6 +97,31 @@ issues: ##### Read more + - [Indicating focus to improve accessibility](https://hiddedevries.nl/en/blog/2019-06-06-indicating-focus-to-improve-accessibility) + - title: Focus style missing + sc: 2.4.7 + severity: High + sample: all + screenshots: null + body: |- + ##### Problem + + Focus styles have been removed through the website's stylesheets: + + ```css + * { + outline: none + } + ``` + + This causes problems for people who use the website without a mouse, as they will not be able to see where they are. + + ##### Solution + + Remove the `outline: none` rule, and/or add a specific style that applies on `:focus`. Make sure that it has sufficient contrast, too. + + ##### Read more + - [Indicating focus to improve accessibility](https://hiddedevries.nl/en/blog/2019-06-06-indicating-focus-to-improve-accessibility) supported: - 1.1.1 diff --git a/src/collections/reports/reports.11tydata.js b/src/collections/reports/reports.11tydata.js index 1224661..a8cbd07 100644 --- a/src/collections/reports/reports.11tydata.js +++ b/src/collections/reports/reports.11tydata.js @@ -1,9 +1,9 @@ -import scSupport from "../../_utils/sc-support.js"; -import scTable from "../../_utils/sc-table.js"; +import resultsByPrinciple from "../../_utils/results-by-principle.js"; +import resultsBySuccessCriterion from "../../_utils/results-by-success-criterion.js"; export default { eleventyComputed: { - scSupport: (data) => scSupport(data.successCriteria, data.issues, data), - scTable: (data) => scTable(data.successCriteria, data.issues, data) + resultsBySuccessCriterion: (data) => resultsBySuccessCriterion(data), + resultsByPrinciple: (data) => resultsByPrinciple(data) } }; From 0cbc9a4b2931ea8d2ae9a6ed2c140c9126e94f0a Mon Sep 17 00:00:00 2001 From: Ned Zimmerman Date: Fri, 12 Jul 2024 09:03:35 -0300 Subject: [PATCH 13/18] fix: remove missing import --- src/_utils/results-by-principle.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/_utils/results-by-principle.js b/src/_utils/results-by-principle.js index 355e276..c88bf8f 100644 --- a/src/_utils/results-by-principle.js +++ b/src/_utils/results-by-principle.js @@ -1,5 +1,4 @@ import totalsByLevel from "../_utils/totals-by-level.js"; -import countSuccessCriterionOnce from "./count-success-criteria-once.js"; import determineFailures from "./determine-failures.js"; export default async function resultsByPrinciple(data) { From e8260523f9bdb1b1db8e631ce42b0df764801ab2 Mon Sep 17 00:00:00 2001 From: Ned Zimmerman Date: Fri, 12 Jul 2024 09:57:01 -0300 Subject: [PATCH 14/18] test: increase coverage --- src/_utils/determine-failures.js | 4 ++-- src/_utils/results-by-principle.js | 8 ++++---- src/_utils/results-by-success-criterion.js | 2 +- src/_utils/sc-uri.js | 12 ++++++------ test/issue-url.test.js | 10 ---------- 5 files changed, 13 insertions(+), 23 deletions(-) delete mode 100644 test/issue-url.test.js diff --git a/src/_utils/determine-failures.js b/src/_utils/determine-failures.js index d5dd84a..7e439c7 100644 --- a/src/_utils/determine-failures.js +++ b/src/_utils/determine-failures.js @@ -1,7 +1,7 @@ export default function determineFailures(issues, principle, notSupported) { - const failuresFromIssues = issues.filter((issue) => issue.sc.startsWith(principle) && issue.severity === "High").map((issue) => issue.sc); + const failuresFromIssues = issues.filter((issue) => issue.sc.startsWith(principle.toString()) && issue.severity === "High").map((issue) => issue.sc); - const manualFailures = notSupported.filter((sc) => sc.startsWith(principle)); + const manualFailures = notSupported.filter((sc) => sc.startsWith(principle.toString())); return [...new Set(failuresFromIssues.concat(manualFailures))]; } diff --git a/src/_utils/results-by-principle.js b/src/_utils/results-by-principle.js index c88bf8f..1fb8687 100644 --- a/src/_utils/results-by-principle.js +++ b/src/_utils/results-by-principle.js @@ -13,10 +13,10 @@ export default async function resultsByPrinciple(data) { // Use string representation of WCAG version to avoid unwanted conversion from e.g. 2.0 to index 2 const totals = totalsByLevelData[targetWcagVersion.toString()][targetLevel]; - const perceivable = determineFailures(issuesWithCriteria, "1.", notSupported); - const operable = determineFailures(issuesWithCriteria, "2.", notSupported); - const understandable = determineFailures(issuesWithCriteria, "3.", notSupported); - const robust = determineFailures(issuesWithCriteria, "4.", notSupported); + const perceivable = determineFailures(issuesWithCriteria, 1, notSupported); + const operable = determineFailures(issuesWithCriteria, 2, notSupported); + const understandable = determineFailures(issuesWithCriteria, 3, notSupported); + const robust = determineFailures(issuesWithCriteria, 4, notSupported); const totalConforming = totals.perceivable - perceivable.length + (totals.operable - operable.length) + (totals.understandable - understandable.length) + (totals.robust - robust.length); diff --git a/src/_utils/results-by-success-criterion.js b/src/_utils/results-by-success-criterion.js index a41f988..28cb085 100644 --- a/src/_utils/results-by-success-criterion.js +++ b/src/_utils/results-by-success-criterion.js @@ -30,7 +30,7 @@ export default async function resultsBySuccessCriterion(data) { support = "Does not support"; } - const scReferenceLink = scUri(key, successCriteria); + const scReferenceLink = scUri(key, targetWcagVersion, successCriteria); result.push({ key, diff --git a/src/_utils/sc-uri.js b/src/_utils/sc-uri.js index 38ff5d0..07d4931 100644 --- a/src/_utils/sc-uri.js +++ b/src/_utils/sc-uri.js @@ -1,13 +1,13 @@ -export default function scUri(sc, criteria) { - const baseUri = "https://www.w3.org/WAI/WCAG22/Understanding/"; +export default function scUri(sc, version, successCriteria) { + const simpleVersion = version.replace(".", ""); + const baseUri = `https://www.w3.org/WAI/WCAG${simpleVersion}/Understanding/`; let slug; - if (criteria[sc]) { - slug = criteria[sc].id || ""; + if (successCriteria[sc]) { + slug = successCriteria[sc].id; } else { - console.error(`Cannot generate URL for ${sc}, as it cannot be found in the data."`); - return; + throw new ReferenceError(`Cannot generate URL for ${sc}, as it cannot be found in the data.`); } return `${baseUri}${slug}.html`; diff --git a/test/issue-url.test.js b/test/issue-url.test.js deleted file mode 100644 index 19db774..0000000 --- a/test/issue-url.test.js +++ /dev/null @@ -1,10 +0,0 @@ -import test from "ava"; -import newIssueUrl from "../src/_utils/new-issue-url.js"; - -test("new issue URL can be generated for GitHub", (t) => { - t.is(newIssueUrl("Test issue", "Not applicable.", "all", "https://github.com/inclusive-design/idrc-wcag-reporter"), "https://github.com/inclusive-design/idrc-wcag-reporter/issues/new?body=Not+applicable.%0A%0A%23%23%23%23%23+Pages%0A%0A-+All+pages&title=Test+issue"); -}); - -test("new issue URL can be generated for GitLab", (t) => { - t.is(newIssueUrl("Test issue", "Not applicable.", "all", "https://gitlab.com/inclusive-design/idrc-wcag-reporter"), "https://gitlab.com/inclusive-design/idrc-wcag-reporter/-/issues/new?issue[title]=Test%20issue&issue[description]=Not%20applicable.%0A%0A%23%23%23%23%23%20Pages%0A%0A-%20All%20pages"); -}); From 55913fe85899a8f3c6f239f7a061c548746f6aa1 Mon Sep 17 00:00:00 2001 From: Ned Zimmerman Date: Fri, 12 Jul 2024 09:57:11 -0300 Subject: [PATCH 15/18] test: increase coverage --- test/failures.test.js | 23 +++++++++++++++++++++++ test/urls.test.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 test/failures.test.js create mode 100644 test/urls.test.js diff --git a/test/failures.test.js b/test/failures.test.js new file mode 100644 index 0000000..3461cdb --- /dev/null +++ b/test/failures.test.js @@ -0,0 +1,23 @@ +import test from "ava"; +import determineFailures from "../src/_utils/determine-failures.js"; + +test("high severity issue indicates a failure", (t) => { + let issues = [ + { sc: "2.1.2", severity: "High" }, + { sc: "2.3.1", severity: "Low" } + ]; + let principle = 2; + let notSupported = ["1.2.1"]; + let principleFailures = determineFailures(issues, principle, notSupported); + t.is(1, principleFailures.length); + t.is("2.1.2", principleFailures[0]); +}); + +test("manual failure indicates a failure", (t) => { + let issues = [{ sc: "1.3.1", severity: "Low" }]; + let principle = 1; + let notSupported = ["1.2.1"]; + let principleFailures = determineFailures(issues, principle, notSupported); + t.is(1, principleFailures.length); + t.is("1.2.1", principleFailures[0]); +}); diff --git a/test/urls.test.js b/test/urls.test.js new file mode 100644 index 0000000..3c12da9 --- /dev/null +++ b/test/urls.test.js @@ -0,0 +1,30 @@ +import test from "ava"; +import newIssueUrl from "../src/_utils/new-issue-url.js"; +import scUri from "../src/_utils/sc-uri.js"; + +test("success criterion URL can be generated", (t) => { + t.is("https://www.w3.org/WAI/WCAG20/Understanding/contrast-minimum.html", scUri("1.4.3", "2.0", { "1.4.3": { id: "contrast-minimum" } })); + + t.is("https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html", scUri("1.4.3", "2.1", { "1.4.3": { id: "contrast-minimum" } })); + + t.is("https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html", scUri("1.4.3", "2.2", { "1.4.3": { id: "contrast-minimum" } })); +}); + +test("success criterion URL cannot be generated for invalid success criterion", (t) => { + const error = t.throws( + () => { + scUri("3.3.9", "2.0", {}); + }, + { instanceOf: ReferenceError } + ); + + t.is("Cannot generate URL for 3.3.9, as it cannot be found in the data.", error.message); +}); + +test("new issue URL can be generated for GitHub", (t) => { + t.is(newIssueUrl("Test issue", "Not applicable.", "all", "https://github.com/inclusive-design/idrc-wcag-reporter"), "https://github.com/inclusive-design/idrc-wcag-reporter/issues/new?body=Not+applicable.%0A%0A%23%23%23%23%23+Pages%0A%0A-+All+pages&title=Test+issue"); +}); + +test("new issue URL can be generated for GitLab", (t) => { + t.is(newIssueUrl("Test issue", "Not applicable.", "all", "https://gitlab.com/inclusive-design/idrc-wcag-reporter"), "https://gitlab.com/inclusive-design/idrc-wcag-reporter/-/issues/new?issue[title]=Test%20issue&issue[description]=Not%20applicable.%0A%0A%23%23%23%23%23%20Pages%0A%0A-%20All%20pages"); +}); From 21558a5192137adda003a42280447e84595c5700 Mon Sep 17 00:00:00 2001 From: Ned Zimmerman Date: Fri, 12 Jul 2024 10:34:27 -0300 Subject: [PATCH 16/18] test: add tests for results --- src/_data/scData.json | 783 ++++++++++++++++++++++++++++++++++++++++++ src/scData.njk | 9 +- test/results.test.js | 38 ++ test/urls.test.js | 2 + 4 files changed, 830 insertions(+), 2 deletions(-) create mode 100644 test/results.test.js diff --git a/src/_data/scData.json b/src/_data/scData.json index 8b68cd9..4f1ae2e 100644 --- a/src/_data/scData.json +++ b/src/_data/scData.json @@ -1,4 +1,787 @@ { "successCriteria": [ + { + "number": "1.1.1", + "name": "Non-text Content (Level A)", + "principle": "Perceivable", + "guideline": "Text Alternatives", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "non-text-content" + }, + { + "number": "1.2.1", + "name": "Audio-only and Video-only (Prerecorded) (Level A)", + "principle": "Perceivable", + "guideline": "Time-based Media", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "audio-only-and-video-only-prerecorded" + }, + { + "number": "1.2.2", + "name": "Captions (Prerecorded) (Level A)", + "principle": "Perceivable", + "guideline": "Time-based Media", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "captions-prerecorded" + }, + { + "number": "1.2.3", + "name": "Audio Description or Media Alternative (Prerecorded) (Level A)", + "principle": "Perceivable", + "guideline": "Time-based Media", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "audio-description-or-media-alternative-prerecorded" + }, + { + "number": "1.2.4", + "name": "Captions (Live) (Level AA)", + "principle": "Perceivable", + "guideline": "Time-based Media", + "level": "AA", + "versions": ["2.0","2.1","2.2"], + "id": "captions-live" + }, + { + "number": "1.2.5", + "name": "Audio Description (Prerecorded) (Level AA)", + "principle": "Perceivable", + "guideline": "Time-based Media", + "level": "AA", + "versions": ["2.0","2.1","2.2"], + "id": "audio-description-prerecorded" + }, + { + "number": "1.2.6", + "name": "Sign Language (Prerecorded) (Level AAA)", + "principle": "Perceivable", + "guideline": "Time-based Media", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "sign-language-prerecorded" + }, + { + "number": "1.2.7", + "name": "Extended Audio Description (Prerecorded) (Level AAA)", + "principle": "Perceivable", + "guideline": "Time-based Media", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "extended-audio-description-prerecorded" + }, + { + "number": "1.2.8", + "name": "Media Alternative (Prerecorded) (Level AAA)", + "principle": "Perceivable", + "guideline": "Time-based Media", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "media-alternative-prerecorded" + }, + { + "number": "1.2.9", + "name": "Audio-only (Live) (Level AAA)", + "principle": "Perceivable", + "guideline": "Time-based Media", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "audio-only-live" + }, + { + "number": "1.3.1", + "name": "Info and Relationships (Level A)", + "principle": "Perceivable", + "guideline": "Adaptable", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "info-and-relationships" + }, + { + "number": "1.3.2", + "name": "Meaningful Sequence (Level A)", + "principle": "Perceivable", + "guideline": "Adaptable", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "meaningful-sequence" + }, + { + "number": "1.3.3", + "name": "Sensory Characteristics (Level A)", + "principle": "Perceivable", + "guideline": "Adaptable", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "sensory-characteristics" + }, + { + "number": "1.3.4", + "name": "Orientation (Level AA)", + "principle": "Perceivable", + "guideline": "Adaptable", + "level": "AA", + "versions": ["2.1","2.2"], + "id": "orientation" + }, + { + "number": "1.3.5", + "name": "Identify Input Purpose (Level AA)", + "principle": "Perceivable", + "guideline": "Adaptable", + "level": "AA", + "versions": ["2.1","2.2"], + "id": "identify-input-purpose" + }, + { + "number": "1.3.6", + "name": "Identify Purpose (Level AAA)", + "principle": "Perceivable", + "guideline": "Adaptable", + "level": "AAA", + "versions": ["2.1","2.2"], + "id": "identify-purpose" + }, + { + "number": "1.4.1", + "name": "Use of Color (Level A)", + "principle": "Perceivable", + "guideline": "Distinguishable", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "use-of-color" + }, + { + "number": "1.4.2", + "name": "Audio Control (Level A)", + "principle": "Perceivable", + "guideline": "Distinguishable", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "audio-control" + }, + { + "number": "1.4.3", + "name": "Contrast (Minimum) (Level AA)", + "principle": "Perceivable", + "guideline": "Distinguishable", + "level": "AA", + "versions": ["2.0","2.1","2.2"], + "id": "contrast-minimum" + }, + { + "number": "1.4.4", + "name": "Resize Text (Level AA)", + "principle": "Perceivable", + "guideline": "Distinguishable", + "level": "AA", + "versions": ["2.0","2.1","2.2"], + "id": "resize-text" + }, + { + "number": "1.4.5", + "name": "Images of Text (Level AA)", + "principle": "Perceivable", + "guideline": "Distinguishable", + "level": "AA", + "versions": ["2.0","2.1","2.2"], + "id": "images-of-text" + }, + { + "number": "1.4.6", + "name": "Contrast (Enhanced) (Level AAA)", + "principle": "Perceivable", + "guideline": "Distinguishable", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "contrast-enhanced" + }, + { + "number": "1.4.7", + "name": "Low or No Background Audio (Level AAA)", + "principle": "Perceivable", + "guideline": "Distinguishable", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "low-or-no-background-audio" + }, + { + "number": "1.4.8", + "name": "Visual Presentation (Level AAA)", + "principle": "Perceivable", + "guideline": "Distinguishable", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "visual-presentation" + }, + { + "number": "1.4.9", + "name": "Images of Text (No Exception) (Level AAA)", + "principle": "Perceivable", + "guideline": "Distinguishable", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "images-of-text-no-exception" + }, + { + "number": "1.4.10", + "name": "Reflow (Level AA)", + "principle": "Perceivable", + "guideline": "Distinguishable", + "level": "AA", + "versions": ["2.1","2.2"], + "id": "reflow" + }, + { + "number": "1.4.11", + "name": "Non-text Contrast (Level AA)", + "principle": "Perceivable", + "guideline": "Distinguishable", + "level": "AA", + "versions": ["2.1","2.2"], + "id": "non-text-contrast" + }, + { + "number": "1.4.12", + "name": "Text Spacing (Level AA)", + "principle": "Perceivable", + "guideline": "Distinguishable", + "level": "AA", + "versions": ["2.1","2.2"], + "id": "text-spacing" + }, + { + "number": "1.4.13", + "name": "Content on Hover or Focus (Level AA)", + "principle": "Perceivable", + "guideline": "Distinguishable", + "level": "AA", + "versions": ["2.1","2.2"], + "id": "content-on-hover-or-focus" + }, + { + "number": "2.1.1", + "name": "Keyboard (Level A)", + "principle": "Operable", + "guideline": "Keyboard Accessible", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "keyboard" + }, + { + "number": "2.1.2", + "name": "No Keyboard Trap (Level A)", + "principle": "Operable", + "guideline": "Keyboard Accessible", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "no-keyboard-trap" + }, + { + "number": "2.1.3", + "name": "Keyboard (No Exception) (Level AAA)", + "principle": "Operable", + "guideline": "Keyboard Accessible", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "keyboard-no-exception" + }, + { + "number": "2.1.4", + "name": "Character Key Shortcuts (Level A)", + "principle": "Operable", + "guideline": "Keyboard Accessible", + "level": "A", + "versions": ["2.1","2.2"], + "id": "character-key-shortcuts" + }, + { + "number": "2.2.1", + "name": "Timing Adjustable (Level A)", + "principle": "Operable", + "guideline": "Enough Time", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "timing-adjustable" + }, + { + "number": "2.2.2", + "name": "Pause, Stop, Hide (Level A)", + "principle": "Operable", + "guideline": "Enough Time", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "pause-stop-hide" + }, + { + "number": "2.2.3", + "name": "No Timing (Level AAA)", + "principle": "Operable", + "guideline": "Enough Time", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "no-timing" + }, + { + "number": "2.2.4", + "name": "Interruptions (Level AAA)", + "principle": "Operable", + "guideline": "Enough Time", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "interruptions" + }, + { + "number": "2.2.5", + "name": "Re-authenticating (Level AAA)", + "principle": "Operable", + "guideline": "Enough Time", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "re-authenticating" + }, + { + "number": "2.2.6", + "name": "Timeouts (Level AAA)", + "principle": "Operable", + "guideline": "Enough Time", + "level": "AAA", + "versions": ["2.1","2.2"], + "id": "timeouts" + }, + { + "number": "2.3.1", + "name": "Three Flashes or Below Threshold (Level A)", + "principle": "Operable", + "guideline": "Seizures and Physical Reactions", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "three-flashes-or-below-threshold" + }, + { + "number": "2.3.2", + "name": "Three Flashes (Level AAA)", + "principle": "Operable", + "guideline": "Seizures and Physical Reactions", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "three-flashes" + }, + { + "number": "2.3.3", + "name": "Animation from Interactions (Level AAA)", + "principle": "Operable", + "guideline": "Seizures and Physical Reactions", + "level": "AAA", + "versions": ["2.1","2.2"], + "id": "animation-from-interactions" + }, + { + "number": "2.4.1", + "name": "Bypass Blocks (Level A)", + "principle": "Operable", + "guideline": "Navigable", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "bypass-blocks" + }, + { + "number": "2.4.2", + "name": "Page Titled (Level A)", + "principle": "Operable", + "guideline": "Navigable", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "page-titled" + }, + { + "number": "2.4.3", + "name": "Focus Order (Level A)", + "principle": "Operable", + "guideline": "Navigable", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "focus-order" + }, + { + "number": "2.4.4", + "name": "Link Purpose (In Context) (Level A)", + "principle": "Operable", + "guideline": "Navigable", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "link-purpose-in-context" + }, + { + "number": "2.4.5", + "name": "Multiple Ways (Level AA)", + "principle": "Operable", + "guideline": "Navigable", + "level": "AA", + "versions": ["2.0","2.1","2.2"], + "id": "multiple-ways" + }, + { + "number": "2.4.6", + "name": "Headings and Labels (Level AA)", + "principle": "Operable", + "guideline": "Navigable", + "level": "AA", + "versions": ["2.0","2.1","2.2"], + "id": "headings-and-labels" + }, + { + "number": "2.4.7", + "name": "Focus Visible (Level AA)", + "principle": "Operable", + "guideline": "Navigable", + "level": "AA", + "versions": ["2.0","2.1","2.2"], + "id": "focus-visible" + }, + { + "number": "2.4.8", + "name": "Location (Level AAA)", + "principle": "Operable", + "guideline": "Navigable", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "location" + }, + { + "number": "2.4.9", + "name": "Link Purpose (Link Only) (Level AAA)", + "principle": "Operable", + "guideline": "Navigable", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "link-purpose-link-only" + }, + { + "number": "2.4.10", + "name": "Section Headings (Level AAA)", + "principle": "Operable", + "guideline": "Navigable", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "section-headings" + }, + { + "number": "2.4.11", + "name": "Focus Not Obscured (Minimum) (Level AA)", + "principle": "Operable", + "guideline": "Navigable", + "level": "AA", + "versions": ["2.2"], + "id": "focus-not-obscured-minimum" + }, + { + "number": "2.4.12", + "name": "Focus Not Obscured (Enhanced) (Level AAA)", + "principle": "Operable", + "guideline": "Navigable", + "level": "AAA", + "versions": ["2.2"], + "id": "focus-not-obscured-enhanced" + }, + { + "number": "2.4.13", + "name": "Focus Appearance (Level AAA)", + "principle": "Operable", + "guideline": "Navigable", + "level": "AAA", + "versions": ["2.2"], + "id": "focus-appearance" + }, + { + "number": "2.5.1", + "name": "Pointer Gestures (Level A)", + "principle": "Operable", + "guideline": "Input Modalities", + "level": "A", + "versions": ["2.1","2.2"], + "id": "pointer-gestures" + }, + { + "number": "2.5.2", + "name": "Pointer Cancellation (Level A)", + "principle": "Operable", + "guideline": "Input Modalities", + "level": "A", + "versions": ["2.1","2.2"], + "id": "pointer-cancellation" + }, + { + "number": "2.5.3", + "name": "Label in Name (Level A)", + "principle": "Operable", + "guideline": "Input Modalities", + "level": "A", + "versions": ["2.1","2.2"], + "id": "label-in-name" + }, + { + "number": "2.5.4", + "name": "Motion Actuation (Level A)", + "principle": "Operable", + "guideline": "Input Modalities", + "level": "A", + "versions": ["2.1","2.2"], + "id": "motion-actuation" + }, + { + "number": "2.5.5", + "name": "Target Size (Enhanced) (Level AAA)", + "principle": "Operable", + "guideline": "Input Modalities", + "level": "AAA", + "versions": ["2.1","2.2"], + "id": "target-size-enhanced" + }, + { + "number": "2.5.6", + "name": "Concurrent Input Mechanisms (Level AAA)", + "principle": "Operable", + "guideline": "Input Modalities", + "level": "AAA", + "versions": ["2.1","2.2"], + "id": "concurrent-input-mechanisms" + }, + { + "number": "2.5.7", + "name": "Dragging Movements (Level AA)", + "principle": "Operable", + "guideline": "Input Modalities", + "level": "AA", + "versions": ["2.2"], + "id": "dragging-movements" + }, + { + "number": "2.5.8", + "name": "Target Size (Minimum) (Level AA)", + "principle": "Operable", + "guideline": "Input Modalities", + "level": "AA", + "versions": ["2.2"], + "id": "target-size-minimum" + }, + { + "number": "3.1.1", + "name": "Language of Page (Level A)", + "principle": "Understandable", + "guideline": "Readable", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "language-of-page" + }, + { + "number": "3.1.2", + "name": "Language of Parts (Level AA)", + "principle": "Understandable", + "guideline": "Readable", + "level": "AA", + "versions": ["2.0","2.1","2.2"], + "id": "language-of-parts" + }, + { + "number": "3.1.3", + "name": "Unusual Words (Level AAA)", + "principle": "Understandable", + "guideline": "Readable", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "unusual-words" + }, + { + "number": "3.1.4", + "name": "Abbreviations (Level AAA)", + "principle": "Understandable", + "guideline": "Readable", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "abbreviations" + }, + { + "number": "3.1.5", + "name": "Reading Level (Level AAA)", + "principle": "Understandable", + "guideline": "Readable", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "reading-level" + }, + { + "number": "3.1.6", + "name": "Pronunciation (Level AAA)", + "principle": "Understandable", + "guideline": "Readable", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "pronunciation" + }, + { + "number": "3.2.1", + "name": "On Focus (Level A)", + "principle": "Understandable", + "guideline": "Predictable", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "on-focus" + }, + { + "number": "3.2.2", + "name": "On Input (Level A)", + "principle": "Understandable", + "guideline": "Predictable", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "on-input" + }, + { + "number": "3.2.3", + "name": "Consistent Navigation (Level AA)", + "principle": "Understandable", + "guideline": "Predictable", + "level": "AA", + "versions": ["2.0","2.1","2.2"], + "id": "consistent-navigation" + }, + { + "number": "3.2.4", + "name": "Consistent Identification (Level AA)", + "principle": "Understandable", + "guideline": "Predictable", + "level": "AA", + "versions": ["2.0","2.1","2.2"], + "id": "consistent-identification" + }, + { + "number": "3.2.5", + "name": "Change on Request (Level AAA)", + "principle": "Understandable", + "guideline": "Predictable", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "change-on-request" + }, + { + "number": "3.2.6", + "name": "Consistent Help (Level A)", + "principle": "Understandable", + "guideline": "Predictable", + "level": "A", + "versions": ["2.2"], + "id": "consistent-help" + }, + { + "number": "3.3.1", + "name": "Error Identification (Level A)", + "principle": "Understandable", + "guideline": "Input Assistance", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "error-identification" + }, + { + "number": "3.3.2", + "name": "Labels or Instructions (Level A)", + "principle": "Understandable", + "guideline": "Input Assistance", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "labels-or-instructions" + }, + { + "number": "3.3.3", + "name": "Error Suggestion (Level AA)", + "principle": "Understandable", + "guideline": "Input Assistance", + "level": "AA", + "versions": ["2.0","2.1","2.2"], + "id": "error-suggestion" + }, + { + "number": "3.3.4", + "name": "Error Prevention (Legal, Financial, Data) (Level AA)", + "principle": "Understandable", + "guideline": "Input Assistance", + "level": "AA", + "versions": ["2.0","2.1","2.2"], + "id": "error-prevention-legal-financial-data" + }, + { + "number": "3.3.5", + "name": "Help (Level AAA)", + "principle": "Understandable", + "guideline": "Input Assistance", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "help" + }, + { + "number": "3.3.6", + "name": "Error Prevention (All) (Level AAA)", + "principle": "Understandable", + "guideline": "Input Assistance", + "level": "AAA", + "versions": ["2.0","2.1","2.2"], + "id": "error-prevention-all" + }, + { + "number": "3.3.7", + "name": "Redundant Entry (Level A)", + "principle": "Understandable", + "guideline": "Input Assistance", + "level": "A", + "versions": ["2.2"], + "id": "redundant-entry" + }, + { + "number": "3.3.8", + "name": "Accessible Authentication (Minimum) (Level AA)", + "principle": "Understandable", + "guideline": "Input Assistance", + "level": "AA", + "versions": ["2.2"], + "id": "accessible-authentication-minimum" + }, + { + "number": "3.3.9", + "name": "Accessible Authentication (Enhanced) (Level AAA)", + "principle": "Understandable", + "guideline": "Input Assistance", + "level": "AAA", + "versions": ["2.2"], + "id": "accessible-authentication-enhanced" + }, + { + "number": "4.1.1", + "name": "Parsing (Obsolete and removed) (Level )", + "principle": "Robust", + "guideline": "Compatible", + "level": "", + "versions": ["2.0","2.1"], + "id": "parsing" + }, + { + "number": "4.1.2", + "name": "Name, Role, Value (Level A)", + "principle": "Robust", + "guideline": "Compatible", + "level": "A", + "versions": ["2.0","2.1","2.2"], + "id": "name-role-value" + }, + { + "number": "4.1.3", + "name": "Status Messages (Level AA)", + "principle": "Robust", + "guideline": "Compatible", + "level": "AA", + "versions": ["2.1","2.2"], + "id": "status-messages" + } ] } diff --git a/src/scData.njk b/src/scData.njk index 6763d84..beccfac 100644 --- a/src/scData.njk +++ b/src/scData.njk @@ -3,10 +3,15 @@ permalink: ../src/_data/scData.json --- { "successCriteria": [ -{%- for number, sc in successcriteria %} +{%- for number, sc in successCriteria %} { "number": "{{ number }}", - "name": "{{ sc.name }} (Level {{ sc.level }})" + "name": "{{ sc.name }} (Level {{ sc.level }})", + "principle": "{{ sc.principle }}", + "guideline": "{{ sc.guideline }}", + "level": "{{ sc.level }}", + "versions": {{ sc.versions | dump | safe }}, + "id": "{{ sc.id.replace("WCAG2:", "") }}" }{% if not loop.last %},{% endif %} {%- endfor %} ] diff --git a/test/results.test.js b/test/results.test.js new file mode 100644 index 0000000..3d03a79 --- /dev/null +++ b/test/results.test.js @@ -0,0 +1,38 @@ +import test from "ava"; +import { readFile } from "fs/promises"; +import resultsByPrinciple from "../src/_utils/results-by-principle.js"; +import resultsBySuccessCriterion from "../src/_utils/results-by-success-criterion.js"; + +const scData = JSON.parse(await readFile(new URL("../src/_data/scData.json", import.meta.url))).successCriteria; + +let successCriteria = {}; +scData.map((criterion) => { + successCriteria[criterion.number] = criterion; +}); + +const data = { + successCriteria, + issues: [ + { sc: "1.3.1", severity: "High" }, + { sc: "1.3.2", severity: "Low" } + ], + targetLevel: "AA", + targetWcagVersion: "2.2", + notSupported: ["2.1.2"], + notApplicable: ["1.2.2"] +}; + +test("results by principle can be generated", async (t) => { + const results = await resultsByPrinciple(data); + t.is(results.Perceivable.supported, 19); + t.is(results.Operable.supported, 19); +}); + +test("results by success criterion can be generated", async (t) => { + const results = await resultsBySuccessCriterion(data); + t.is(1, results.filter((criterion) => criterion.support === "Not applicable").length); + + t.is(1, results.filter((criterion) => criterion.support === "Partially supports").length); + + t.is(2, results.filter((criterion) => criterion.support === "Does not support").length); +}); diff --git a/test/urls.test.js b/test/urls.test.js index 3c12da9..d740a01 100644 --- a/test/urls.test.js +++ b/test/urls.test.js @@ -23,8 +23,10 @@ test("success criterion URL cannot be generated for invalid success criterion", test("new issue URL can be generated for GitHub", (t) => { t.is(newIssueUrl("Test issue", "Not applicable.", "all", "https://github.com/inclusive-design/idrc-wcag-reporter"), "https://github.com/inclusive-design/idrc-wcag-reporter/issues/new?body=Not+applicable.%0A%0A%23%23%23%23%23+Pages%0A%0A-+All+pages&title=Test+issue"); + t.is(newIssueUrl("Test issue", "Not applicable.", "Home page", "https://github.com/inclusive-design/idrc-wcag-reporter"), "https://github.com/inclusive-design/idrc-wcag-reporter/issues/new?body=Not+applicable.%0A%0A%23%23%23%23%23+Pages%0A%0A-+Home+page&title=Test+issue"); }); test("new issue URL can be generated for GitLab", (t) => { t.is(newIssueUrl("Test issue", "Not applicable.", "all", "https://gitlab.com/inclusive-design/idrc-wcag-reporter"), "https://gitlab.com/inclusive-design/idrc-wcag-reporter/-/issues/new?issue[title]=Test%20issue&issue[description]=Not%20applicable.%0A%0A%23%23%23%23%23%20Pages%0A%0A-%20All%20pages"); + t.is(newIssueUrl("Test issue", "Not applicable.", "Home page", "https://github.com/inclusive-design/idrc-wcag-reporter"), "https://github.com/inclusive-design/idrc-wcag-reporter/issues/new?body=Not+applicable.%0A%0A%23%23%23%23%23+Pages%0A%0A-+Home+page&title=Test+issue"); }); From cd588acc32bb5e7a9227b766a5535040e575e2bf Mon Sep 17 00:00:00 2001 From: Ned Zimmerman Date: Fri, 12 Jul 2024 12:07:04 -0300 Subject: [PATCH 17/18] test: finalize --- package.json | 2 +- src/_layouts/report.njk | 3 ++- src/assets/scripts/criteria.js | 38 ---------------------------------- test/results.test.js | 38 ++++++++++++++++++---------------- 4 files changed, 23 insertions(+), 58 deletions(-) delete mode 100644 src/assets/scripts/criteria.js diff --git a/package.json b/package.json index 55fc0b6..5e6f80d 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "lint:scripts": "biome check .", "lint:markdown": "markdownlint-cli2 \"**/*.md\"", "start": "npm-run-all -l clean dev", - "test": "c8 --all --src src -r clover -r text ava", + "test": "c8 --all --src src/_utils -r clover -r text ava", "prepare": "husky" }, "repository": { diff --git a/src/_layouts/report.njk b/src/_layouts/report.njk index d3c0fe9..876c2fb 100644 --- a/src/_layouts/report.njk +++ b/src/_layouts/report.njk @@ -173,7 +173,6 @@ layout: base {% endfor %} - {% if tipsList.length %}
@@ -203,3 +202,5 @@ layout: base {% endfor %}
{% endif %} + + diff --git a/src/assets/scripts/criteria.js b/src/assets/scripts/criteria.js deleted file mode 100644 index c42f073..0000000 --- a/src/assets/scripts/criteria.js +++ /dev/null @@ -1,38 +0,0 @@ -/* global document */ - -const criteria = document.querySelectorAll("#executive-summary h3, #about-this-report h3, #issues h3, #scope h3"); -for (const criterion of criteria) { - criterion.innerHTML = ``; - - const getContent = (elem) => { - let elems = []; - while (elem.nextElementSibling && elem.nextElementSibling.tagName !== "H2" && elem.nextElementSibling.tagName !== "H3") { - elems.push(elem.nextElementSibling); - elem = elem.nextElementSibling; - } - - elems.forEach((node) => { - node.parentNode.removeChild(node); - }); - - return elems; - }; - - let contents = getContent(criterion); - - let wrapper = document.createElement("div"); - - contents.forEach((node) => { - wrapper.appendChild(node); - }); - - criterion.parentNode.insertBefore(wrapper, criterion.nextElementSibling); - - let btn = criterion.querySelector("button"); - - btn.onclick = () => { - let expanded = btn.getAttribute("aria-expanded") === "true" || false; - - btn.setAttribute("aria-expanded", !expanded); - }; -} diff --git a/test/results.test.js b/test/results.test.js index 3d03a79..4ac18b4 100644 --- a/test/results.test.js +++ b/test/results.test.js @@ -3,33 +3,35 @@ import { readFile } from "fs/promises"; import resultsByPrinciple from "../src/_utils/results-by-principle.js"; import resultsBySuccessCriterion from "../src/_utils/results-by-success-criterion.js"; -const scData = JSON.parse(await readFile(new URL("../src/_data/scData.json", import.meta.url))).successCriteria; +test.before(async (t) => { + const scData = JSON.parse(await readFile(new URL("../src/_data/scData.json", import.meta.url))).successCriteria; -let successCriteria = {}; -scData.map((criterion) => { - successCriteria[criterion.number] = criterion; -}); + let successCriteria = {}; + scData.map((criterion) => { + successCriteria[criterion.number] = criterion; + }); -const data = { - successCriteria, - issues: [ - { sc: "1.3.1", severity: "High" }, - { sc: "1.3.2", severity: "Low" } - ], - targetLevel: "AA", - targetWcagVersion: "2.2", - notSupported: ["2.1.2"], - notApplicable: ["1.2.2"] -}; + t.context.data = { + successCriteria, + issues: [ + { sc: "1.3.1", severity: "High" }, + { sc: "1.3.2", severity: "Low" } + ], + targetLevel: "AA", + targetWcagVersion: "2.2", + notSupported: ["2.1.2"], + notApplicable: ["1.2.2"] + }; +}); test("results by principle can be generated", async (t) => { - const results = await resultsByPrinciple(data); + const results = await resultsByPrinciple(t.context.data); t.is(results.Perceivable.supported, 19); t.is(results.Operable.supported, 19); }); test("results by success criterion can be generated", async (t) => { - const results = await resultsBySuccessCriterion(data); + const results = await resultsBySuccessCriterion(t.context.data); t.is(1, results.filter((criterion) => criterion.support === "Not applicable").length); t.is(1, results.filter((criterion) => criterion.support === "Partially supports").length); From 4ef32df3ae768c411f1be220092f43568b1fc90d Mon Sep 17 00:00:00 2001 From: Ned Zimmerman Date: Fri, 12 Jul 2024 12:07:23 -0300 Subject: [PATCH 18/18] fix: rename script --- src/assets/scripts/collapse.js | 40 ++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/assets/scripts/collapse.js diff --git a/src/assets/scripts/collapse.js b/src/assets/scripts/collapse.js new file mode 100644 index 0000000..dd48347 --- /dev/null +++ b/src/assets/scripts/collapse.js @@ -0,0 +1,40 @@ +export default function collapsibleSections() { + const criteria = document.querySelectorAll("h3"); + for (const criterion of criteria) { + criterion.innerHTML = ``; + + const getContent = (elem) => { + let elems = []; + while (elem.nextElementSibling && elem.nextElementSibling.tagName !== "H2" && elem.nextElementSibling.tagName !== "H3") { + elems.push(elem.nextElementSibling); + elem = elem.nextElementSibling; + } + + elems.forEach((node) => { + node.parentNode.removeChild(node); + }); + + return elems; + }; + + let contents = getContent(criterion); + + let wrapper = document.createElement("div"); + + contents.forEach((node) => { + wrapper.appendChild(node); + }); + + criterion.parentNode.insertBefore(wrapper, criterion.nextElementSibling); + + let btn = criterion.querySelector("button"); + + btn.onclick = () => { + let expanded = btn.getAttribute("aria-expanded") === "true" || false; + + btn.setAttribute("aria-expanded", !expanded); + }; + } +} + +collapsibleSections();
{{ label }} {{ group.supported }} of {{ group.total }}
{% if criterion.link %}{% endif %}{{ criterion.label }}{% if criterion.link %}{% endif %}{{ criterion.level }}{{ criterion.support }} Understanding {{ criterion.key }} (external link)