testaro 78.0.8 → 78.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +94 -0
- package/.github/workflows/ci.yml +58 -0
- package/.github/workflows/publish.yml +49 -0
- package/.github/workflows/typescript.yml +35 -0
- package/AGENTS.md +2 -2
- package/CLAUDE.md +24 -18
- package/CONTAINERS.md +9 -6
- package/CONTRIBUTING.md +29 -3
- package/Dockerfile +1 -1
- package/README.md +73 -19
- package/UPGRADES.md +4 -0
- package/actSpecs-doc.md +13 -1
- package/actSpecs.js +29 -5
- package/call.js +6 -5
- package/docker-compose.yml +8 -2
- package/docs/checkpoint-scanning.md +199 -0
- package/docs/standard-result-outcome.md +165 -0
- package/env.example +44 -10
- package/eslint.config.mjs +101 -0
- package/netWatch.js +372 -222
- package/package.json +46 -31
- package/pour/README.md +47 -0
- package/pour/pour.min.js +8 -0
- package/procs/actDo.js +808 -0
- package/procs/catalog.d.ts +17 -0
- package/procs/catalog.js +312 -221
- package/procs/catalog.ts +398 -0
- package/procs/checkpoint.js +110 -0
- package/procs/config.d.ts +35 -0
- package/procs/config.js +62 -0
- package/procs/dateTime.js +2 -1
- package/procs/doActs.js +442 -849
- package/procs/doTestAct.js +27 -121
- package/procs/flow.js +221 -0
- package/procs/generateRuleRegistry.js +94 -0
- package/procs/getSource.d.ts +26 -0
- package/procs/job.js +115 -1
- package/procs/launch.d.ts +40 -0
- package/procs/launch.js +239 -108
- package/procs/nu.d.ts +48 -0
- package/procs/scope.js +196 -0
- package/procs/shoot.d.ts +33 -0
- package/procs/standard.d.ts +18 -0
- package/procs/standard.js +83 -0
- package/procs/standard.ts +126 -0
- package/procs/testAct.js +145 -0
- package/procs/testaro.d.ts +20 -0
- package/procs/testaro.js +236 -189
- package/procs/testaro.ts +321 -0
- package/procs/userPath.js +126 -0
- package/procs/xPath.d.ts +4 -0
- package/procs/xPath.js +81 -69
- package/procs/xPath.ts +106 -0
- package/procs/xPathScript.d.ts +6 -0
- package/procs/xPathScript.js +70 -0
- package/run.js +3 -2
- package/surea11y/README.md +44 -0
- package/surea11y/surea11y.browser.js +14 -0
- package/testaro/adbID.d.ts +3 -0
- package/testaro/adbID.js +38 -41
- package/testaro/adbID.ts +66 -0
- package/testaro/allCapStyle.d.ts +3 -0
- package/testaro/allCapStyle.js +31 -34
- package/testaro/allCapStyle.ts +55 -0
- package/testaro/allCaps.d.ts +16 -0
- package/testaro/allCaps.js +179 -151
- package/testaro/allCaps.ts +228 -0
- package/testaro/allHidden.d.ts +13 -0
- package/testaro/allHidden.js +29 -30
- package/testaro/allHidden.ts +50 -0
- package/testaro/allSlanted.d.ts +3 -0
- package/testaro/allSlanted.js +30 -33
- package/testaro/allSlanted.ts +54 -0
- package/testaro/altScheme.d.ts +3 -0
- package/testaro/altScheme.js +27 -30
- package/testaro/altScheme.ts +50 -0
- package/testaro/attVal.d.ts +3 -0
- package/testaro/attVal.js +20 -21
- package/testaro/attVal.ts +52 -0
- package/testaro/autocomplete.d.ts +3 -0
- package/testaro/autocomplete.js +59 -75
- package/testaro/autocomplete.ts +101 -0
- package/testaro/bulk.d.ts +13 -0
- package/testaro/bulk.js +32 -33
- package/testaro/bulk.ts +55 -0
- package/testaro/buttonMenu.d.ts +9 -0
- package/testaro/buttonMenu.js +317 -319
- package/testaro/buttonMenu.ts +391 -0
- package/testaro/captionLoc.d.ts +3 -0
- package/testaro/captionLoc.js +17 -20
- package/testaro/captionLoc.ts +40 -0
- package/testaro/datalistRef.d.ts +3 -0
- package/testaro/datalistRef.js +33 -36
- package/testaro/datalistRef.ts +55 -0
- package/testaro/distortion.d.ts +3 -0
- package/testaro/distortion.js +57 -26
- package/testaro/distortion.ts +81 -0
- package/testaro/docType.d.ts +15 -0
- package/testaro/docType.js +25 -25
- package/testaro/docType.ts +45 -0
- package/testaro/dupAtt.d.ts +16 -0
- package/testaro/dupAtt.js +113 -104
- package/testaro/dupAtt.ts +144 -0
- package/testaro/elements.d.ts +6 -0
- package/testaro/elements.js +153 -153
- package/testaro/elements.ts +215 -0
- package/testaro/embAc.d.ts +3 -0
- package/testaro/embAc.js +19 -20
- package/testaro/embAc.ts +40 -0
- package/testaro/focAll.d.ts +13 -0
- package/testaro/focAll.js +185 -191
- package/testaro/focAll.ts +217 -0
- package/testaro/focAndOp.d.ts +3 -0
- package/testaro/focAndOp.js +100 -104
- package/testaro/focAndOp.ts +128 -0
- package/testaro/focInd.d.ts +3 -0
- package/testaro/focInd.js +64 -66
- package/testaro/focInd.ts +96 -0
- package/testaro/focVis.d.ts +3 -0
- package/testaro/focVis.js +28 -30
- package/testaro/focVis.ts +52 -0
- package/testaro/headEl.d.ts +10 -0
- package/testaro/headEl.js +61 -62
- package/testaro/headEl.ts +82 -0
- package/testaro/headingAmb.d.ts +3 -0
- package/testaro/headingAmb.js +54 -63
- package/testaro/headingAmb.ts +72 -0
- package/testaro/hovInd.d.ts +12 -0
- package/testaro/hovInd.js +163 -130
- package/testaro/hovInd.ts +199 -0
- package/testaro/hover.d.ts +3 -0
- package/testaro/hover.js +155 -126
- package/testaro/hover.ts +154 -0
- package/testaro/hr.d.ts +3 -0
- package/testaro/hr.js +14 -17
- package/testaro/hr.ts +36 -0
- package/testaro/imageLink.d.ts +3 -0
- package/testaro/imageLink.js +17 -20
- package/testaro/imageLink.ts +42 -0
- package/testaro/labClash.d.ts +3 -0
- package/testaro/labClash.js +31 -33
- package/testaro/labClash.ts +54 -0
- package/testaro/legendLoc.d.ts +3 -0
- package/testaro/legendLoc.js +17 -20
- package/testaro/legendLoc.ts +42 -0
- package/testaro/lineHeight.d.ts +3 -0
- package/testaro/lineHeight.js +43 -48
- package/testaro/lineHeight.ts +70 -0
- package/testaro/linkAmb.d.ts +7 -0
- package/testaro/linkAmb.js +79 -80
- package/testaro/linkAmb.ts +105 -0
- package/testaro/linkExt.d.ts +3 -0
- package/testaro/linkExt.js +13 -16
- package/testaro/linkExt.ts +35 -0
- package/testaro/linkOldAtt.d.ts +3 -0
- package/testaro/linkOldAtt.js +25 -28
- package/testaro/linkOldAtt.ts +48 -0
- package/testaro/linkTo.d.ts +3 -0
- package/testaro/linkTo.js +22 -22
- package/testaro/linkTo.ts +43 -0
- package/testaro/linkUl.d.ts +3 -0
- package/testaro/linkUl.js +30 -34
- package/testaro/linkUl.ts +54 -0
- package/testaro/miniText.d.ts +3 -0
- package/testaro/miniText.js +41 -44
- package/testaro/miniText.ts +68 -0
- package/testaro/motion.d.ts +10 -0
- package/testaro/motion.js +92 -96
- package/testaro/motion.ts +125 -0
- package/testaro/nonTable.d.ts +3 -0
- package/testaro/nonTable.js +39 -45
- package/testaro/nonTable.ts +66 -0
- package/testaro/optRoleSel.d.ts +3 -0
- package/testaro/optRoleSel.js +16 -19
- package/testaro/optRoleSel.ts +41 -0
- package/testaro/phOnly.d.ts +3 -0
- package/testaro/phOnly.js +18 -21
- package/testaro/phOnly.ts +43 -0
- package/testaro/pseudoP.d.ts +3 -0
- package/testaro/pseudoP.js +36 -38
- package/testaro/pseudoP.ts +59 -0
- package/testaro/radioSet.d.ts +3 -0
- package/testaro/radioSet.js +57 -59
- package/testaro/radioSet.ts +79 -0
- package/testaro/registry.d.ts +63 -0
- package/testaro/registry.js +67 -0
- package/testaro/registry.ts +141 -0
- package/testaro/role.d.ts +3 -0
- package/testaro/role.js +27 -29
- package/testaro/role.ts +53 -0
- package/testaro/secHeading.d.ts +3 -0
- package/testaro/secHeading.js +30 -33
- package/testaro/secHeading.ts +53 -0
- package/testaro/styleDiff.d.ts +25 -0
- package/testaro/styleDiff.js +248 -252
- package/testaro/styleDiff.ts +303 -0
- package/testaro/tabNav.d.ts +33 -0
- package/testaro/tabNav.js +272 -342
- package/testaro/tabNav.ts +454 -0
- package/testaro/targetsNear.d.ts +9 -0
- package/testaro/targetsNear.js +130 -132
- package/testaro/targetsNear.ts +160 -0
- package/testaro/textNodes.d.ts +6 -0
- package/testaro/textNodes.js +139 -135
- package/testaro/textNodes.ts +185 -0
- package/testaro/textSem.d.ts +3 -0
- package/testaro/textSem.js +25 -28
- package/testaro/textSem.ts +47 -0
- package/testaro/title.d.ts +9 -0
- package/testaro/title.js +16 -13
- package/testaro/title.ts +31 -0
- package/testaro/titledEl.d.ts +3 -0
- package/testaro/titledEl.js +15 -18
- package/testaro/titledEl.ts +38 -0
- package/testaro/zIndex.d.ts +3 -0
- package/testaro/zIndex.js +19 -22
- package/testaro/zIndex.ts +42 -0
- package/tests/alfa.d.ts +45 -0
- package/tests/alfa.js +138 -141
- package/tests/alfa.ts +214 -0
- package/tests/aslint.d.ts +33 -0
- package/tests/aslint.js +272 -249
- package/tests/aslint.ts +301 -0
- package/tests/axe.d.ts +27 -0
- package/tests/axe.js +199 -200
- package/tests/axe.ts +277 -0
- package/tests/ed11y.d.ts +28 -0
- package/tests/ed11y.js +141 -99
- package/tests/ed11y.ts +178 -0
- package/tests/htmlcs.d.ts +21 -0
- package/tests/htmlcs.js +174 -140
- package/tests/htmlcs.ts +181 -0
- package/tests/ibm.d.ts +52 -0
- package/tests/ibm.js +164 -166
- package/tests/ibm.ts +251 -0
- package/tests/nuVal.d.ts +13 -0
- package/tests/nuVal.js +107 -112
- package/tests/nuVal.ts +145 -0
- package/tests/nuVnu.d.ts +15 -0
- package/tests/nuVnu.js +141 -111
- package/tests/nuVnu.ts +144 -0
- package/tests/pour.d.ts +31 -0
- package/tests/pour.js +242 -0
- package/tests/pour.ts +273 -0
- package/tests/qualWeb.d.ts +39 -0
- package/tests/qualWeb.js +302 -272
- package/tests/qualWeb.ts +415 -0
- package/tests/surea11y.d.ts +33 -0
- package/tests/surea11y.js +288 -0
- package/tests/surea11y.ts +334 -0
- package/tests/testaro.d.ts +25 -0
- package/tests/testaro.js +745 -652
- package/tests/testaro.ts +862 -0
- package/tests/wave.d.ts +46 -0
- package/tests/wave.js +166 -177
- package/tests/wave.ts +252 -0
- package/tsconfig.json +17 -0
- package/types.d.ts +243 -0
- package/types.js +10 -0
- package/types.ts +376 -0
- package/validation/act/README.md +46 -0
- package/validation/act/capture.js +424 -0
- package/validation/act/chromium-issue-draft.md +66 -0
- package/validation/act/fp-triage-2026-08-22.md +86 -0
- package/validation/act/isolation-notes.md +159 -0
- package/validation/act/playwright-issue-draft.md +73 -0
- package/validation/act/propose-mappings.js +0 -0
- package/validation/act/repro-cdp-raw.js +105 -0
- package/validation/act/repro-metarefresh.js +65 -0
- package/validation/act/score.js +184 -0
- package/validation/act/stage3a-stress-report.md +69 -0
- package/validation/act/stage3b-mapping-proposals.md +94 -0
- package/validation/act/stage3b-triage-draft.md +138 -0
- package/validation/act/surea11y-track-a-2026-09-01.md +50 -0
- package/validation/executors/netWatch.js +180 -90
- package/validation/executors/test.js +17 -2
- package/validation/executors/tests.js +118 -10
- package/validation/jobs/reports/raw/260901T1000-surea11y-validation.json +964 -0
- package/validation/jobs/todo/240101T1200-simple-example.json +14 -6
- package/validation/jobs/todo/240101T1300-shoot-example.json +2 -1
- package/validation/jobs/todo/260821T1900-pour-validation.json +45 -0
- package/validation/jobs/todo/260901T1000-surea11y-validation.json +45 -0
- package/validation/knownFailures.json +1 -0
- package/validation/tests/jobProperties/adbID.json +27 -2
- package/validation/tests/jobProperties/{focOp.json → allCapStyle.json} +56 -53
- package/validation/tests/jobProperties/allCaps.json +25 -0
- package/validation/tests/jobProperties/allHidden.json +133 -13
- package/validation/tests/jobProperties/allSlanted.json +3 -3
- package/validation/tests/jobProperties/altScheme.json +23 -8
- package/validation/tests/jobProperties/attVal.json +57 -57
- package/validation/tests/jobProperties/autocomplete.json +11 -1
- package/validation/tests/jobProperties/bulk.json +6 -1
- package/validation/tests/jobProperties/buttonMenu.json +63 -42
- package/validation/tests/jobProperties/captionLoc.json +1 -6
- package/validation/tests/jobProperties/checkpoint-browser.json +401 -0
- package/validation/tests/jobProperties/checkpoint-page.json +397 -0
- package/validation/tests/jobProperties/checkpoint.json +395 -0
- package/validation/tests/jobProperties/datalistRef.json +20 -5
- package/validation/tests/jobProperties/distortion.json +28 -3
- package/validation/tests/jobProperties/docType.json +2 -2
- package/validation/tests/jobProperties/dupAtt.json +48 -33
- package/validation/tests/jobProperties/elements.json +28 -28
- package/validation/tests/jobProperties/embAc.json +36 -31
- package/validation/tests/jobProperties/focAndOp.json +284 -0
- package/validation/tests/jobProperties/focInd.json +34 -34
- package/validation/tests/jobProperties/focVis.json +1 -1
- package/validation/tests/jobProperties/hover.json +39 -37
- package/validation/tests/jobProperties/hr.json +13 -3
- package/validation/tests/jobProperties/imageLink.json +0 -5
- package/validation/tests/jobProperties/labClash.json +68 -33
- package/validation/tests/jobProperties/legendLoc.json +1 -6
- package/validation/tests/jobProperties/lineHeight.json +2 -2
- package/validation/tests/jobProperties/linkAmb.json +13 -18
- package/validation/tests/jobProperties/linkExt.json +1 -1
- package/validation/tests/jobProperties/linkOldAtt.json +12 -2
- package/validation/tests/jobProperties/linkTo.json +1 -1
- package/validation/tests/jobProperties/linkUl.json +65 -65
- package/validation/tests/jobProperties/miniText.json +7 -2
- package/validation/tests/jobProperties/motion.json +4 -50
- package/validation/tests/jobProperties/nonTable.json +48 -3
- package/validation/tests/jobProperties/optRoleSel.json +12 -2
- package/validation/tests/jobProperties/phOnly.json +6 -16
- package/validation/tests/jobProperties/pseudoP.json +17 -2
- package/validation/tests/jobProperties/radioSet.json +30 -30
- package/validation/tests/jobProperties/role.json +25 -5
- package/validation/tests/jobProperties/secHeading.json +26 -21
- package/validation/tests/jobProperties/styleDiff.json +35 -5
- package/validation/tests/jobProperties/tabNav.json +3 -1
- package/validation/tests/jobProperties/targetsNear.json +237 -0
- package/validation/tests/jobProperties/textNodes.json +29 -29
- package/validation/tests/jobProperties/textSem.json +26 -1
- package/validation/tests/jobProperties/title.json +12 -2
- package/validation/tests/jobProperties/titledEl.json +39 -9
- package/validation/tests/jobProperties/userPath.json +317 -0
- package/validation/tests/jobProperties/zIndex.json +40 -35
- package/validation/tests/targets/allCapStyle/index.html +26 -0
- package/validation/tests/targets/checkpoint/index.html +38 -0
- package/validation/tests/targets/datalistRef/index.html +1 -1
- package/validation/tests/targets/focAndOp/bad.html +29 -0
- package/validation/tests/targets/{focOp → focAndOp}/good.html +3 -1
- package/validation/tests/targets/focInd/bad.html +2 -1
- package/validation/tests/targets/headEl/index.html +10 -1
- package/validation/tests/targets/{targetSmall → targetsNear}/index.html +15 -1
- package/validation/tests/targets/userPath/index.html +42 -0
- package/validation/validateTest.js +61 -9
- package/.claude/settings.local.json +0 -11
- package/.eslintrc.json +0 -41
- package/htmlcs/.eslintrc.json +0 -67
- package/validation/tests/jobProperties/linkTitle.json +0 -127
- package/validation/tests/jobProperties/opFoc.json +0 -164
- package/validation/tests/jobProperties/targetSmall.json +0 -152
- package/validation/tests/jobProperties/targetTiny.json +0 -142
- package/validation/tests/targets/focOp/bad.html +0 -25
- package/validation/tests/targets/linkTitle/index.html +0 -24
- package/validation/tests/targets/opFoc/bad.html +0 -26
- package/validation/tests/targets/opFoc/good.html +0 -23
package/tests/qualWeb.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/*
|
|
2
3
|
© 2023–2024 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
4
|
© 2026 Jeff Witt.
|
|
@@ -8,297 +9,326 @@
|
|
|
8
9
|
|
|
9
10
|
SPDX-License-Identifier: MIT
|
|
10
11
|
*/
|
|
11
|
-
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.reporter = void 0;
|
|
14
|
+
const xPath_1 = require("../procs/xPath");
|
|
15
|
+
const standard_1 = require("../procs/standard");
|
|
12
16
|
/*
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
The @qualweb packages declare their types only in package-exports maps, which
|
|
18
|
+
this project's node10 module resolution cannot read, so the imports stay
|
|
19
|
+
requires and are untyped.
|
|
15
20
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const {
|
|
20
|
-
const {
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}));
|
|
21
|
+
const { QualWeb } = require('@qualweb/core');
|
|
22
|
+
const { ACTRules } = require('@qualweb/act-rules');
|
|
23
|
+
const { WCAGTechniques } = require('@qualweb/wcag-techniques');
|
|
24
|
+
const { BestPractices } = require('@qualweb/best-practices');
|
|
25
|
+
const { PlaywrightDriver } = require('@qualweb/playwright-driver');
|
|
26
|
+
const config_1 = require("../procs/config");
|
|
27
|
+
const qualWebInstances = {};
|
|
28
|
+
const getQualWeb = (options) => {
|
|
29
|
+
const key = `${options.stealth}:${options.adBlock}`;
|
|
30
|
+
if (!qualWebInstances[key]) {
|
|
31
|
+
let launcher;
|
|
32
|
+
if (options.stealth) {
|
|
33
|
+
const { chromium } = require('playwright-extra');
|
|
34
|
+
chromium.use(require('puppeteer-extra-plugin-stealth')());
|
|
35
|
+
launcher = chromium;
|
|
36
|
+
}
|
|
37
|
+
const qualWeb = new QualWeb(undefined, new PlaywrightDriver(launcher ? { launcher } : {}));
|
|
38
|
+
if (options.adBlock) {
|
|
39
|
+
const { PlaywrightBlocker } = require('@ghostery/adblocker-playwright');
|
|
40
|
+
let blockerPromise = null;
|
|
41
|
+
qualWeb.use({
|
|
42
|
+
async beforePageLoad(page) {
|
|
43
|
+
blockerPromise ??= PlaywrightBlocker.fromPrebuiltAdsAndTracking(fetch, {
|
|
44
|
+
path: require('path').join(require('os').tmpdir(), 'qualweb-adblocker-engine.bin'),
|
|
45
|
+
read: require('fs').promises.readFile,
|
|
46
|
+
write: require('fs').promises.writeFile
|
|
47
|
+
}).catch((error) => {
|
|
48
|
+
console.log(`qualWeb: ad blocker unavailable, continuing without it (${error.message})`);
|
|
49
|
+
return null;
|
|
50
|
+
});
|
|
51
|
+
const blocker = await blockerPromise;
|
|
52
|
+
if (blocker) {
|
|
53
|
+
await blocker.enableBlockingInPage(page.nativePage);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
qualWebInstances[key] = qualWeb;
|
|
59
|
+
}
|
|
60
|
+
return qualWebInstances[key];
|
|
61
|
+
};
|
|
33
62
|
const actRulesModule = new ACTRules({});
|
|
34
63
|
const wcagModule = new WCAGTechniques({});
|
|
35
64
|
const bpModule = new BestPractices({});
|
|
36
65
|
// Mapping of QualWeb module violation types to ordinal severities.
|
|
37
66
|
const ordinalSeverities = {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
67
|
+
'act-rules': {
|
|
68
|
+
'warning': 1,
|
|
69
|
+
'failed': 3
|
|
70
|
+
},
|
|
71
|
+
'wcag-techniques': {
|
|
72
|
+
'warning': 0,
|
|
73
|
+
'failed': 2
|
|
74
|
+
},
|
|
75
|
+
'best-practices': {
|
|
76
|
+
'warning': 0,
|
|
77
|
+
'failed': 1
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
/*
|
|
81
|
+
qualWeb
|
|
82
|
+
Implements the QualWeb ruleset for accessibility.
|
|
83
|
+
Compiled to qualWeb.js by tsc (issue #73); edit this file, not the emitted one.
|
|
84
|
+
*/
|
|
52
85
|
// FUNCTIONS
|
|
53
|
-
|
|
54
86
|
// Conducts and reports the QualWeb tests.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
standardResult: {}
|
|
68
|
-
};
|
|
69
|
-
const standard = report.standard !== 'no';
|
|
70
|
-
// If standard results are to be reported:
|
|
71
|
-
if (standard) {
|
|
72
|
-
// Initialize the standard result.
|
|
73
|
-
result.standardResult = {
|
|
74
|
-
prevented: false,
|
|
75
|
-
totals: [0, 0, 0, 0],
|
|
76
|
-
instances: []
|
|
87
|
+
const reporter = async (page, report, actIndex, timeLimit) => {
|
|
88
|
+
const qualWebAct = report.acts[actIndex];
|
|
89
|
+
const qualWeb = getQualWeb({
|
|
90
|
+
stealth: qualWebAct.stealth ?? config_1.qualWebDefaults.stealth,
|
|
91
|
+
adBlock: qualWebAct.adBlock ?? config_1.qualWebDefaults.adBlock
|
|
92
|
+
});
|
|
93
|
+
const act = report.acts[actIndex];
|
|
94
|
+
const { rules } = act;
|
|
95
|
+
const clusterOptions = {
|
|
96
|
+
maxConcurrency: 1,
|
|
97
|
+
timeout: timeLimit * 1000,
|
|
98
|
+
monitor: false
|
|
77
99
|
};
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
// If the start fails:
|
|
84
|
-
catch(error) {
|
|
85
|
-
return {
|
|
86
|
-
data: {
|
|
87
|
-
prevented: true,
|
|
88
|
-
error: `Core engine start failed (${error.message})`
|
|
89
|
-
},
|
|
90
|
-
result
|
|
100
|
+
// Initialize the act report.
|
|
101
|
+
const data = {};
|
|
102
|
+
const result = {
|
|
103
|
+
nativeResult: {},
|
|
104
|
+
standardResult: {}
|
|
91
105
|
};
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
file: false
|
|
98
|
-
},
|
|
99
|
-
crawlOptions: {
|
|
100
|
-
maxDepth: 0,
|
|
101
|
-
maxUrls: 1,
|
|
102
|
-
timeout: timeLimit * 1000,
|
|
103
|
-
maxParallelCrawls: 1,
|
|
104
|
-
logging: true
|
|
105
|
-
},
|
|
106
|
-
execute: {
|
|
107
|
-
counter: true
|
|
108
|
-
},
|
|
109
|
-
modules: []
|
|
110
|
-
};
|
|
111
|
-
try {
|
|
112
|
-
// Provide the page content, including the data-xpath attributes.
|
|
113
|
-
qualWebOptions.html = await page.content();
|
|
114
|
-
// Specify which rules to test for, adding a custom execute property for report processing.
|
|
115
|
-
const actSpec = rules ? rules.find(typeRules => typeRules.startsWith('act:')) : null;
|
|
116
|
-
const wcagSpec = rules ? rules.find(typeRules => typeRules.startsWith('wcag:')) : null;
|
|
117
|
-
const bestSpec = rules ? rules.find(typeRules => typeRules.startsWith('best:')) : null;
|
|
118
|
-
if (actSpec) {
|
|
119
|
-
if (actSpec === 'act:') {
|
|
120
|
-
qualWebOptions.execute.act = false;
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
const actRules = actSpec.slice(4).split(',').map(num => `QW-ACT-R${num}`);
|
|
124
|
-
qualWebOptions['act-rules'] = {rules: actRules};
|
|
125
|
-
qualWebOptions.modules.push(actRulesModule);
|
|
126
|
-
qualWebOptions.execute.act = true;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
qualWebOptions['act-rules'] = {
|
|
131
|
-
levels: ['A', 'AA', 'AAA'],
|
|
132
|
-
principles: ['Perceivable', 'Operable', 'Understandable', 'Robust']
|
|
133
|
-
};
|
|
134
|
-
qualWebOptions.modules.push(actRulesModule);
|
|
135
|
-
qualWebOptions.execute.act = true;
|
|
136
|
-
}
|
|
137
|
-
if (wcagSpec) {
|
|
138
|
-
if (wcagSpec === 'wcag:') {
|
|
139
|
-
qualWebOptions.execute.wcag = false;
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
const wcagTechniques = wcagSpec.slice(5).split(',').map(num => `QW-WCAG-T${num}`);
|
|
143
|
-
qualWebOptions['wcag-techniques'] = {techniques: wcagTechniques};
|
|
144
|
-
qualWebOptions.modules.push(wcagModule);
|
|
145
|
-
qualWebOptions.execute.wcag = true;
|
|
146
|
-
}
|
|
106
|
+
const standard = report.standard !== 'no';
|
|
107
|
+
// If standard results are to be reported:
|
|
108
|
+
if (standard) {
|
|
109
|
+
// Initialize the standard result.
|
|
110
|
+
result.standardResult = (0, standard_1.getStandardResult)();
|
|
147
111
|
}
|
|
148
|
-
else {
|
|
149
|
-
qualWebOptions['wcag-techniques'] = {
|
|
150
|
-
levels: ['A', 'AA', 'AAA'],
|
|
151
|
-
principles: ['Perceivable', 'Operable', 'Understandable', 'Robust']
|
|
152
|
-
};
|
|
153
|
-
qualWebOptions.modules.push(wcagModule);
|
|
154
|
-
qualWebOptions.execute.wcag = true;
|
|
155
|
-
}
|
|
156
|
-
if (bestSpec) {
|
|
157
|
-
if (bestSpec === 'best:') {
|
|
158
|
-
qualWebOptions.execute.bp = false;
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
const bestPractices = bestSpec.slice(5).split(',').map(num => `QW-BP${num}`);
|
|
162
|
-
qualWebOptions['best-practices'] = {bestPractices};
|
|
163
|
-
qualWebOptions.modules.push(bpModule);
|
|
164
|
-
qualWebOptions.execute.bp = true;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
else {
|
|
168
|
-
qualWebOptions['best-practices'] = {};
|
|
169
|
-
qualWebOptions.modules.push(bpModule);
|
|
170
|
-
qualWebOptions.execute.bp = true;
|
|
171
|
-
}
|
|
172
|
-
let qwReport;
|
|
173
112
|
try {
|
|
174
|
-
|
|
175
|
-
|
|
113
|
+
// Start the QualWeb core engine, which launches a Playwright browser.
|
|
114
|
+
await qualWeb.start(clusterOptions);
|
|
176
115
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
116
|
+
// If the start fails:
|
|
117
|
+
catch (error) {
|
|
118
|
+
return {
|
|
119
|
+
data: {
|
|
120
|
+
prevented: true,
|
|
121
|
+
error: `Core engine start failed (${error.message})`
|
|
122
|
+
},
|
|
123
|
+
result
|
|
124
|
+
};
|
|
185
125
|
}
|
|
186
|
-
//
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
raResult => raResult.verdict !== 'passed'
|
|
215
|
-
);
|
|
216
|
-
// For each test result:
|
|
217
|
-
for (const raResult of ruleAssertions.results) {
|
|
218
|
-
const {elements, verdict} = raResult;
|
|
219
|
-
// If any violations are reported:
|
|
220
|
-
if (elements?.length) {
|
|
221
|
-
// For each violating element:
|
|
222
|
-
for (const element of elements) {
|
|
223
|
-
// Limit the size of its reported excerpt.
|
|
224
|
-
if (element.htmlCode?.length > 2000) {
|
|
225
|
-
element.htmlCode = `${element.htmlCode.slice(0, 2000)} …`;
|
|
226
|
-
}
|
|
227
|
-
// If standard results are to be reported:
|
|
228
|
-
if (standard) {
|
|
229
|
-
const ordinalSeverity = ordinalSeverities[section][verdict];
|
|
230
|
-
// Increment the applicable total.
|
|
231
|
-
standardResult.totals[ordinalSeverity]++;
|
|
232
|
-
// Initialize a standard instance.
|
|
233
|
-
const what = `[${verdict}] ${raResult.description}`;
|
|
234
|
-
const xPath = getAttributeXPath(element.htmlCode);
|
|
235
|
-
const instance = {
|
|
236
|
-
ruleID,
|
|
237
|
-
what,
|
|
238
|
-
ordinalSeverity: ordinalSeverities[section][verdict],
|
|
239
|
-
count: 1,
|
|
240
|
-
catalogIndex: getXPathCatalogIndex(report, xPath)
|
|
241
|
-
};
|
|
242
|
-
// Add the instance to the standard result.
|
|
243
|
-
standardResult.instances.push(instance);
|
|
244
|
-
}
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
// Otherwise, i.e. if there were no warnings or failures:
|
|
250
|
-
else {
|
|
251
|
-
// Delete the rule.
|
|
252
|
-
delete assertions[ruleID];
|
|
253
|
-
}
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
// Otherwise, i.e. if it contains no assertions:
|
|
257
|
-
else {
|
|
258
|
-
// Report this.
|
|
259
|
-
data.prevented = true;
|
|
260
|
-
data.error = 'No assertions';
|
|
261
|
-
}
|
|
126
|
+
// Otherwise, i.e. if the start succeeds, specify the invariant test options.
|
|
127
|
+
const qualWebOptions = {
|
|
128
|
+
log: {
|
|
129
|
+
console: false,
|
|
130
|
+
file: false
|
|
131
|
+
},
|
|
132
|
+
crawlOptions: {
|
|
133
|
+
maxDepth: 0,
|
|
134
|
+
maxUrls: 1,
|
|
135
|
+
timeout: timeLimit * 1000,
|
|
136
|
+
maxParallelCrawls: 1,
|
|
137
|
+
logging: true
|
|
138
|
+
},
|
|
139
|
+
execute: {
|
|
140
|
+
counter: true
|
|
141
|
+
},
|
|
142
|
+
modules: []
|
|
143
|
+
};
|
|
144
|
+
try {
|
|
145
|
+
// Provide the page content, including the data-xpath attributes.
|
|
146
|
+
qualWebOptions.html = await page.content();
|
|
147
|
+
// Specify which rules to test for, adding a custom execute property for report processing.
|
|
148
|
+
const actSpec = rules ? rules.find(typeRules => typeRules.startsWith('act:')) : null;
|
|
149
|
+
const wcagSpec = rules ? rules.find(typeRules => typeRules.startsWith('wcag:')) : null;
|
|
150
|
+
const bestSpec = rules ? rules.find(typeRules => typeRules.startsWith('best:')) : null;
|
|
151
|
+
if (actSpec) {
|
|
152
|
+
if (actSpec === 'act:') {
|
|
153
|
+
qualWebOptions.execute.act = false;
|
|
262
154
|
}
|
|
263
|
-
// Otherwise, i.e. if the section is missing:
|
|
264
155
|
else {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
156
|
+
const actRules = actSpec.slice(4).split(',').map(num => `QW-ACT-R${num}`);
|
|
157
|
+
qualWebOptions['act-rules'] = { rules: actRules };
|
|
158
|
+
qualWebOptions.modules.push(actRulesModule);
|
|
159
|
+
qualWebOptions.execute.act = true;
|
|
268
160
|
}
|
|
269
|
-
}
|
|
270
161
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
162
|
+
else {
|
|
163
|
+
qualWebOptions['act-rules'] = {
|
|
164
|
+
levels: ['A', 'AA', 'AAA'],
|
|
165
|
+
principles: ['Perceivable', 'Operable', 'Understandable', 'Robust']
|
|
166
|
+
};
|
|
167
|
+
qualWebOptions.modules.push(actRulesModule);
|
|
168
|
+
qualWebOptions.execute.act = true;
|
|
169
|
+
}
|
|
170
|
+
if (wcagSpec) {
|
|
171
|
+
if (wcagSpec === 'wcag:') {
|
|
172
|
+
qualWebOptions.execute.wcag = false;
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
const wcagTechniques = wcagSpec.slice(5).split(',').map(num => `QW-WCAG-T${num}`);
|
|
176
|
+
qualWebOptions['wcag-techniques'] = { techniques: wcagTechniques };
|
|
177
|
+
qualWebOptions.modules.push(wcagModule);
|
|
178
|
+
qualWebOptions.execute.wcag = true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
qualWebOptions['wcag-techniques'] = {
|
|
183
|
+
levels: ['A', 'AA', 'AAA'],
|
|
184
|
+
principles: ['Perceivable', 'Operable', 'Understandable', 'Robust']
|
|
185
|
+
};
|
|
186
|
+
qualWebOptions.modules.push(wcagModule);
|
|
187
|
+
qualWebOptions.execute.wcag = true;
|
|
188
|
+
}
|
|
189
|
+
if (bestSpec) {
|
|
190
|
+
if (bestSpec === 'best:') {
|
|
191
|
+
qualWebOptions.execute.bp = false;
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
const bestPractices = bestSpec.slice(5).split(',').map(num => `QW-BP${num}`);
|
|
195
|
+
qualWebOptions['best-practices'] = { bestPractices };
|
|
196
|
+
qualWebOptions.modules.push(bpModule);
|
|
197
|
+
qualWebOptions.execute.bp = true;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
qualWebOptions['best-practices'] = {};
|
|
202
|
+
qualWebOptions.modules.push(bpModule);
|
|
203
|
+
qualWebOptions.execute.bp = true;
|
|
204
|
+
}
|
|
205
|
+
let qwReport;
|
|
206
|
+
try {
|
|
207
|
+
// Get the report.
|
|
208
|
+
qwReport = await qualWeb.evaluate(qualWebOptions);
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
return {
|
|
212
|
+
data: {
|
|
213
|
+
prevented: true,
|
|
214
|
+
error: `qualWeb evaluation failed (${error.message})`
|
|
215
|
+
},
|
|
216
|
+
result
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
// Add the report to the result.
|
|
220
|
+
result.nativeResult = qwReport.customHtml;
|
|
221
|
+
const { nativeResult, standardResult } = result;
|
|
222
|
+
// If the report contains, as it should, a copy of the DOM:
|
|
223
|
+
if (nativeResult?.system?.page?.dom) {
|
|
224
|
+
// Delete the copy for parsimony.
|
|
225
|
+
delete nativeResult.system.page.dom;
|
|
226
|
+
const { modules } = nativeResult;
|
|
227
|
+
// If the report contains, as it should, a modules property:
|
|
228
|
+
if (modules) {
|
|
229
|
+
// For each test section in it:
|
|
230
|
+
for (const section of ['act-rules', 'wcag-techniques', 'best-practices']) {
|
|
231
|
+
// If testing in the section was specified:
|
|
232
|
+
if (qualWebOptions[section]) {
|
|
233
|
+
// If the section exists:
|
|
234
|
+
if (modules[section]) {
|
|
235
|
+
const { assertions } = modules[section];
|
|
236
|
+
// If it contains assertions (test results):
|
|
237
|
+
if (assertions) {
|
|
238
|
+
const ruleIDs = Object.keys(assertions);
|
|
239
|
+
// For each rule:
|
|
240
|
+
for (const ruleID of ruleIDs) {
|
|
241
|
+
const ruleAssertions = assertions[ruleID];
|
|
242
|
+
const { metadata } = ruleAssertions;
|
|
243
|
+
// If there were any warnings or failures:
|
|
244
|
+
if (metadata?.warning || metadata?.failed) {
|
|
245
|
+
// Delete nonviolations from the results.
|
|
246
|
+
ruleAssertions.results = ruleAssertions.results.filter(raResult => raResult.verdict !== 'passed');
|
|
247
|
+
// For each test result:
|
|
248
|
+
for (const raResult of ruleAssertions.results) {
|
|
249
|
+
const { elements, verdict } = raResult;
|
|
250
|
+
// If any violations are reported:
|
|
251
|
+
if (elements?.length) {
|
|
252
|
+
// For each violating element:
|
|
253
|
+
for (const element of elements) {
|
|
254
|
+
// Limit the size of its reported excerpt.
|
|
255
|
+
if (element.htmlCode?.length > 2000) {
|
|
256
|
+
element.htmlCode = `${element.htmlCode.slice(0, 2000)} …`;
|
|
257
|
+
}
|
|
258
|
+
// If standard results are to be reported:
|
|
259
|
+
if (standard) {
|
|
260
|
+
const what = `[${verdict}] ${raResult.description}`;
|
|
261
|
+
const xPath = (0, xPath_1.getAttributeXPath)(element.htmlCode);
|
|
262
|
+
// Add an instance to the standard result.
|
|
263
|
+
(0, standard_1.addInstance)(standardResult, {
|
|
264
|
+
ruleID,
|
|
265
|
+
what,
|
|
266
|
+
ordinalSeverity: ordinalSeverities[section][verdict],
|
|
267
|
+
outcome: verdict === 'warning' ? 'cantTell' : 'failed',
|
|
268
|
+
catalogIndex: (0, xPath_1.getXPathCatalogIndex)(report, xPath)
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
;
|
|
276
|
+
}
|
|
277
|
+
// Otherwise, i.e. if there were no warnings or failures:
|
|
278
|
+
else {
|
|
279
|
+
// Delete the rule.
|
|
280
|
+
delete assertions[ruleID];
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
;
|
|
284
|
+
}
|
|
285
|
+
// Otherwise, i.e. if it contains no assertions:
|
|
286
|
+
else {
|
|
287
|
+
// Report this.
|
|
288
|
+
data.prevented = true;
|
|
289
|
+
data.error = 'No assertions';
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// Otherwise, i.e. if the section is missing:
|
|
293
|
+
else {
|
|
294
|
+
// Report this.
|
|
295
|
+
data.prevented = true;
|
|
296
|
+
data.error = `No ${section} section`;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// Otherwise, i.e. if the report does not contain a modules property:
|
|
302
|
+
else {
|
|
303
|
+
// Report this.
|
|
304
|
+
data.prevented = true;
|
|
305
|
+
data.error = 'No modules';
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
// Otherwise, i.e. if the report does not contain a copy of the DOM:
|
|
309
|
+
else {
|
|
310
|
+
// Report this.
|
|
311
|
+
data.prevented = true;
|
|
312
|
+
data.error = 'No DOM';
|
|
313
|
+
}
|
|
314
|
+
// Stop the QualWeb core engine.
|
|
315
|
+
await qualWeb.stop();
|
|
316
|
+
// Test whether the result is an object.
|
|
317
|
+
try {
|
|
318
|
+
JSON.stringify(result);
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
data.prevented = true;
|
|
322
|
+
data.error = `QualWeb result cannot be made JSON (${error.message})`;
|
|
323
|
+
}
|
|
290
324
|
}
|
|
291
|
-
catch(error) {
|
|
292
|
-
|
|
293
|
-
|
|
325
|
+
catch (error) {
|
|
326
|
+
data.prevented = true;
|
|
327
|
+
data.error = `QualWeb failed (${error.message})`;
|
|
294
328
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
}
|
|
300
|
-
return {
|
|
301
|
-
data,
|
|
302
|
-
result
|
|
303
|
-
};
|
|
329
|
+
return {
|
|
330
|
+
data,
|
|
331
|
+
result
|
|
332
|
+
};
|
|
304
333
|
};
|
|
334
|
+
exports.reporter = reporter;
|