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/testaro/labClash.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/*
|
|
2
3
|
© 2021–2023 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
4
|
© 2026 Jeff Witt.
|
|
@@ -8,43 +9,40 @@
|
|
|
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 testaro_1 = require("../procs/testaro");
|
|
12
15
|
/*
|
|
13
16
|
labClash
|
|
14
17
|
This test reports redundant labeling of buttons, non-hidden inputs, select lists, and text areas. Redundant labels are labels that are superseded by other labels. Explicit and implicit (wrapped) labels are additive, not conflicting.
|
|
18
|
+
Compiled to labClash.js by tsc (issue #73); edit this file, not the emitted one.
|
|
15
19
|
*/
|
|
16
|
-
|
|
17
|
-
// IMPORTS
|
|
18
|
-
|
|
19
|
-
const {doTest} = require('../procs/testaro');
|
|
20
|
-
|
|
21
20
|
// FUNCTIONS
|
|
22
|
-
|
|
23
21
|
// Runs the test and returns the result.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
page, report, withItems, 'labClash', selector, whats, 2, getBadWhat.toString()
|
|
49
|
-
);
|
|
22
|
+
const reporter = async (page, report, _, withItems) => {
|
|
23
|
+
// The candidate selector guarantees labelable form controls.
|
|
24
|
+
const getBadWhat = (element) => {
|
|
25
|
+
// Get the label types of the element.
|
|
26
|
+
const labelTypes = [];
|
|
27
|
+
// Attribute and reference labels.
|
|
28
|
+
['aria-label', 'aria-labelledby'].forEach(type => {
|
|
29
|
+
if (element.hasAttribute(type)) {
|
|
30
|
+
labelTypes.push(type);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
// Explicit and implicit labels.
|
|
34
|
+
const labels = Array.from(element.labels);
|
|
35
|
+
if (labels.length) {
|
|
36
|
+
labelTypes.push('label');
|
|
37
|
+
}
|
|
38
|
+
// If it has more than 1 label type:
|
|
39
|
+
if (labelTypes.length > 1) {
|
|
40
|
+
// Return a violation description.
|
|
41
|
+
return `Element has inconsistent label types (${labelTypes.join(', ')})`;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const selector = 'body button, body input:not([type=hidden]), body select, body textarea';
|
|
45
|
+
const whats = 'Elements have inconsistent label types';
|
|
46
|
+
return await (0, testaro_1.doTest)(page, report, withItems, 'labClash', selector, whats, 2, getBadWhat.toString());
|
|
50
47
|
};
|
|
48
|
+
exports.reporter = reporter;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
© 2021–2023 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
© 2026 Jeff Witt.
|
|
4
|
+
© 2025–2026 Jonathan Robert Pool.
|
|
5
|
+
|
|
6
|
+
Licensed under the MIT License. See LICENSE file at the project root or
|
|
7
|
+
https://opensource.org/license/mit/ for details.
|
|
8
|
+
|
|
9
|
+
SPDX-License-Identifier: MIT
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// IMPORTS
|
|
13
|
+
|
|
14
|
+
import type {Page} from 'playwright';
|
|
15
|
+
import {doTest} from '../procs/testaro';
|
|
16
|
+
import type {BadWhat, Report} from '../types';
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
labClash
|
|
20
|
+
This test reports redundant labeling of buttons, non-hidden inputs, select lists, and text areas. Redundant labels are labels that are superseded by other labels. Explicit and implicit (wrapped) labels are additive, not conflicting.
|
|
21
|
+
Compiled to labClash.js by tsc (issue #73); edit this file, not the emitted one.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
// FUNCTIONS
|
|
25
|
+
|
|
26
|
+
// Runs the test and returns the result.
|
|
27
|
+
export const reporter = async (page: Page, report: Report, _: unknown, withItems: boolean) => {
|
|
28
|
+
// The candidate selector guarantees labelable form controls.
|
|
29
|
+
const getBadWhat = (element: HTMLInputElement): BadWhat => {
|
|
30
|
+
// Get the label types of the element.
|
|
31
|
+
const labelTypes = [];
|
|
32
|
+
// Attribute and reference labels.
|
|
33
|
+
['aria-label', 'aria-labelledby'].forEach(type => {
|
|
34
|
+
if (element.hasAttribute(type)) {
|
|
35
|
+
labelTypes.push(type);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
// Explicit and implicit labels.
|
|
39
|
+
const labels = Array.from(element.labels!);
|
|
40
|
+
if (labels.length) {
|
|
41
|
+
labelTypes.push('label');
|
|
42
|
+
}
|
|
43
|
+
// If it has more than 1 label type:
|
|
44
|
+
if (labelTypes.length > 1) {
|
|
45
|
+
// Return a violation description.
|
|
46
|
+
return `Element has inconsistent label types (${labelTypes.join(', ')})`;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const selector = 'body button, body input:not([type=hidden]), body select, body textarea';
|
|
50
|
+
const whats = 'Elements have inconsistent label types';
|
|
51
|
+
return await doTest(
|
|
52
|
+
page, report, withItems, 'labClash', selector, whats, 2, getBadWhat.toString()
|
|
53
|
+
);
|
|
54
|
+
};
|
package/testaro/legendLoc.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/*
|
|
2
3
|
© 2025 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
4
|
© 2025 Juan S. Casado.
|
|
@@ -9,31 +10,27 @@
|
|
|
9
10
|
|
|
10
11
|
SPDX-License-Identifier: MIT
|
|
11
12
|
*/
|
|
12
|
-
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.reporter = void 0;
|
|
15
|
+
const testaro_1 = require("../procs/testaro");
|
|
13
16
|
/*
|
|
14
17
|
legendLoc
|
|
15
18
|
Clean-room rule.
|
|
16
19
|
This test reports legend elements that are not the first children of fieldset elements.
|
|
20
|
+
Compiled to legendLoc.js by tsc (issue #73); edit this file, not the emitted one.
|
|
17
21
|
*/
|
|
18
|
-
|
|
19
|
-
// IMPORTS
|
|
20
|
-
|
|
21
|
-
const {doTest} = require('../procs/testaro');
|
|
22
|
-
|
|
23
22
|
// FUNCTIONS
|
|
24
|
-
|
|
25
23
|
// Runs the test and returns the result.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
page, report, withItems, 'legendLoc', 'body legend', whats, 3, getBadWhat.toString()
|
|
38
|
-
);
|
|
24
|
+
const reporter = async (page, report, _, withItems) => {
|
|
25
|
+
const getBadWhat = element => {
|
|
26
|
+
const parent = element.parentElement;
|
|
27
|
+
// If the element violates the rule:
|
|
28
|
+
if (!(parent && parent.tagName === 'FIELDSET' && parent.firstElementChild === element)) {
|
|
29
|
+
// Return a violation description.
|
|
30
|
+
return 'Element is not the first child of a fieldset element';
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const whats = 'Legend elements are not the first children of fieldset elements';
|
|
34
|
+
return await (0, testaro_1.doTest)(page, report, withItems, 'legendLoc', 'body legend', whats, 3, getBadWhat.toString());
|
|
39
35
|
};
|
|
36
|
+
exports.reporter = reporter;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*
|
|
2
|
+
© 2025 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
© 2025 Juan S. Casado.
|
|
4
|
+
© 2026 Jeff Witt.
|
|
5
|
+
© 2025–2026 Jonathan Robert Pool.
|
|
6
|
+
|
|
7
|
+
Licensed under the MIT License. See LICENSE file at the project root or
|
|
8
|
+
https://opensource.org/license/mit/ for details.
|
|
9
|
+
|
|
10
|
+
SPDX-License-Identifier: MIT
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// IMPORTS
|
|
14
|
+
|
|
15
|
+
import type {Page} from 'playwright';
|
|
16
|
+
import {doTest} from '../procs/testaro';
|
|
17
|
+
import type {GetBadWhat, Report} from '../types';
|
|
18
|
+
|
|
19
|
+
/*
|
|
20
|
+
legendLoc
|
|
21
|
+
Clean-room rule.
|
|
22
|
+
This test reports legend elements that are not the first children of fieldset elements.
|
|
23
|
+
Compiled to legendLoc.js by tsc (issue #73); edit this file, not the emitted one.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
// FUNCTIONS
|
|
27
|
+
|
|
28
|
+
// Runs the test and returns the result.
|
|
29
|
+
export const reporter = async (page: Page, report: Report, _: unknown, withItems: boolean) => {
|
|
30
|
+
const getBadWhat: GetBadWhat = element => {
|
|
31
|
+
const parent = element.parentElement;
|
|
32
|
+
// If the element violates the rule:
|
|
33
|
+
if (! (parent && parent.tagName === 'FIELDSET' && parent.firstElementChild === element)) {
|
|
34
|
+
// Return a violation description.
|
|
35
|
+
return 'Element is not the first child of a fieldset element';
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const whats = 'Legend elements are not the first children of fieldset elements';
|
|
39
|
+
return await doTest(
|
|
40
|
+
page, report, withItems, 'legendLoc', 'body legend', whats, 3, getBadWhat.toString()
|
|
41
|
+
);
|
|
42
|
+
};
|
package/testaro/lineHeight.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,60 +9,54 @@
|
|
|
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 testaro_1 = require("../procs/testaro");
|
|
12
15
|
/*
|
|
13
16
|
lineHeight
|
|
14
17
|
Related to Tenon rule 144.
|
|
15
18
|
This test reports elements whose line heights are less than 1.5 times their font sizes. Even such elements with no text create accessibility risk, because any text node added to one of them would have a substandard line height. Nonetheless, elements with no non-spacing text in their subtrees are excluded.
|
|
19
|
+
Compiled to lineHeight.js by tsc (issue #73); edit this file, not the emitted one.
|
|
16
20
|
*/
|
|
17
|
-
|
|
18
|
-
// IMPORTS
|
|
19
|
-
|
|
20
|
-
const {doTest} = require('../procs/testaro');
|
|
21
|
-
|
|
22
21
|
// FUNCTIONS
|
|
23
|
-
|
|
24
22
|
// Runs the test and returns the result.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
23
|
+
const reporter = async (page, report, _, withItems) => {
|
|
24
|
+
const getBadWhat = element => {
|
|
25
|
+
// Get whether the element has a non-spacing child text node.
|
|
26
|
+
const hasText = Array.from(element.childNodes).some(child => child.nodeType === Node.TEXT_NODE && child.textContent.trim());
|
|
27
|
+
// If so:
|
|
28
|
+
if (hasText) {
|
|
29
|
+
// Get its relevant style properties.
|
|
30
|
+
const styleDec = window.getComputedStyle(element);
|
|
31
|
+
const { fontSize, lineHeight } = styleDec;
|
|
32
|
+
const fontSizeNum = Number.parseFloat(fontSize);
|
|
33
|
+
const lineHeightNum = Number.parseFloat(lineHeight);
|
|
34
|
+
// Get whether it violates the rule.
|
|
35
|
+
const isBad = lineHeightNum < 1.495 * fontSizeNum;
|
|
36
|
+
// If it does:
|
|
37
|
+
if (isBad) {
|
|
38
|
+
const parent = element.parentElement;
|
|
39
|
+
// If the element has a parent:
|
|
40
|
+
if (parent) {
|
|
41
|
+
// Get the style properties of the parent.
|
|
42
|
+
const parentStyleDec = window.getComputedStyle(parent);
|
|
43
|
+
const { fontSize: parentFontSize, lineHeight: parentLineHeight } = parentStyleDec;
|
|
44
|
+
const parentFontSizeNum = Number.parseFloat(parentFontSize);
|
|
45
|
+
const parentLineHeightNum = Number.parseFloat(parentLineHeight);
|
|
46
|
+
// If the parent also violates the rule:
|
|
47
|
+
if (parentLineHeightNum < 1.495 * parentFontSizeNum) {
|
|
48
|
+
// Do not report a violation, because the line height may be inherited.
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const whatFontSize = `font size (${fontSizeNum.toFixed(1)}px)`;
|
|
53
|
+
const whatLineHeight = `line height (${lineHeightNum.toFixed(1)}px)`;
|
|
54
|
+
// Return a violation description.
|
|
55
|
+
return `Element ${whatLineHeight} is less than 1.5 times its ${whatFontSize}`;
|
|
56
|
+
}
|
|
55
57
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return `Element ${whatLineHeight} is less than 1.5 times its ${whatFontSize}`;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
const whats = 'Element line heights are less than 1.5 times their font sizes';
|
|
64
|
-
return await doTest(
|
|
65
|
-
page, report, withItems, 'lineHeight', 'body, body *', whats, 1, getBadWhat.toString()
|
|
66
|
-
);
|
|
58
|
+
};
|
|
59
|
+
const whats = 'Element line heights are less than 1.5 times their font sizes';
|
|
60
|
+
return await (0, testaro_1.doTest)(page, report, withItems, 'lineHeight', 'body, body *', whats, 1, getBadWhat.toString());
|
|
67
61
|
};
|
|
62
|
+
exports.reporter = reporter;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/*
|
|
2
|
+
© 2023–2024 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
© 2026 Jeff Witt.
|
|
4
|
+
© 2025–2026 Jonathan Robert Pool.
|
|
5
|
+
|
|
6
|
+
Licensed under the MIT License. See LICENSE file at the project root or
|
|
7
|
+
https://opensource.org/license/mit/ for details.
|
|
8
|
+
|
|
9
|
+
SPDX-License-Identifier: MIT
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// IMPORTS
|
|
13
|
+
|
|
14
|
+
import type {Page} from 'playwright';
|
|
15
|
+
import {doTest} from '../procs/testaro';
|
|
16
|
+
import type {GetBadWhat, Report} from '../types';
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
lineHeight
|
|
20
|
+
Related to Tenon rule 144.
|
|
21
|
+
This test reports elements whose line heights are less than 1.5 times their font sizes. Even such elements with no text create accessibility risk, because any text node added to one of them would have a substandard line height. Nonetheless, elements with no non-spacing text in their subtrees are excluded.
|
|
22
|
+
Compiled to lineHeight.js by tsc (issue #73); edit this file, not the emitted one.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
// FUNCTIONS
|
|
26
|
+
|
|
27
|
+
// Runs the test and returns the result.
|
|
28
|
+
export const reporter = async (page: Page, report: Report, _: unknown, withItems: boolean) => {
|
|
29
|
+
const getBadWhat: GetBadWhat = element => {
|
|
30
|
+
// Get whether the element has a non-spacing child text node.
|
|
31
|
+
const hasText = Array.from(element.childNodes).some(child =>
|
|
32
|
+
child.nodeType === Node.TEXT_NODE && child.textContent!.trim()
|
|
33
|
+
);
|
|
34
|
+
// If so:
|
|
35
|
+
if (hasText) {
|
|
36
|
+
// Get its relevant style properties.
|
|
37
|
+
const styleDec = window.getComputedStyle(element);
|
|
38
|
+
const {fontSize, lineHeight} = styleDec;
|
|
39
|
+
const fontSizeNum = Number.parseFloat(fontSize);
|
|
40
|
+
const lineHeightNum = Number.parseFloat(lineHeight);
|
|
41
|
+
// Get whether it violates the rule.
|
|
42
|
+
const isBad = lineHeightNum < 1.495 * fontSizeNum;
|
|
43
|
+
// If it does:
|
|
44
|
+
if (isBad) {
|
|
45
|
+
const parent = element.parentElement;
|
|
46
|
+
// If the element has a parent:
|
|
47
|
+
if (parent) {
|
|
48
|
+
// Get the style properties of the parent.
|
|
49
|
+
const parentStyleDec = window.getComputedStyle(parent);
|
|
50
|
+
const {fontSize: parentFontSize, lineHeight: parentLineHeight} = parentStyleDec;
|
|
51
|
+
const parentFontSizeNum = Number.parseFloat(parentFontSize);
|
|
52
|
+
const parentLineHeightNum = Number.parseFloat(parentLineHeight);
|
|
53
|
+
// If the parent also violates the rule:
|
|
54
|
+
if (parentLineHeightNum < 1.495 * parentFontSizeNum) {
|
|
55
|
+
// Do not report a violation, because the line height may be inherited.
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const whatFontSize = `font size (${fontSizeNum.toFixed(1)}px)`;
|
|
60
|
+
const whatLineHeight = `line height (${lineHeightNum.toFixed(1)}px)`;
|
|
61
|
+
// Return a violation description.
|
|
62
|
+
return `Element ${whatLineHeight} is less than 1.5 times its ${whatFontSize}`;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
const whats = 'Element line heights are less than 1.5 times their font sizes';
|
|
67
|
+
return await doTest(
|
|
68
|
+
page, report, withItems, 'lineHeight', 'body, body *', whats, 1, getBadWhat.toString()
|
|
69
|
+
);
|
|
70
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Page } from 'playwright';
|
|
2
|
+
import type { Report, StandardInstance } from '../types';
|
|
3
|
+
export declare const reporter: (page: Page, report: Report, _: unknown, withItems: boolean) => Promise<{
|
|
4
|
+
data: {};
|
|
5
|
+
totals: number[];
|
|
6
|
+
standardInstances: StandardInstance[];
|
|
7
|
+
}>;
|
package/testaro/linkAmb.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/*
|
|
2
3
|
© 2023–2025 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
4
|
© 2026 Jeff Witt.
|
|
@@ -8,92 +9,90 @@
|
|
|
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");
|
|
12
15
|
/*
|
|
13
16
|
linkAmb
|
|
14
17
|
Related to Tenon rule 98.
|
|
15
18
|
This test reports text contents that are shared by links with distinct destinations. Text contents are compared case-insensitively.
|
|
19
|
+
Compiled to linkAmb.js by tsc (issue #73); edit this file, not the emitted one.
|
|
16
20
|
*/
|
|
17
|
-
|
|
18
|
-
// IMPORTS
|
|
19
|
-
|
|
20
|
-
const {getXPathCatalogIndex} = require('../procs/xPath');
|
|
21
|
-
|
|
22
21
|
// FUNCTIONS
|
|
23
|
-
|
|
24
22
|
// Runs the test and returns the result.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
23
|
+
const reporter = async (page, report, _, withItems) => {
|
|
24
|
+
const catalogIndex = (0, xPath_1.getXPathCatalogIndex)(report, '/html/body');
|
|
25
|
+
return await page.evaluate(args => {
|
|
26
|
+
const [withItems, catalogIndex] = args;
|
|
27
|
+
// Get all links.
|
|
28
|
+
const allLinks = Array.from(document.body.getElementsByTagName('a'));
|
|
29
|
+
// Get the visible ones.
|
|
30
|
+
const visibleLinks = allLinks.filter(link => link.checkVisibility({
|
|
31
|
+
contentVisibilityAuto: true,
|
|
32
|
+
opacityProperty: true,
|
|
33
|
+
visibilityProperty: true
|
|
34
|
+
}));
|
|
35
|
+
// Initialize the data.
|
|
36
|
+
const linksData = {
|
|
37
|
+
elementData: [],
|
|
38
|
+
textTotals: {}
|
|
39
|
+
};
|
|
40
|
+
// For each visible link:
|
|
41
|
+
visibleLinks.forEach(element => {
|
|
42
|
+
// Get its trimmed and lowercased text.
|
|
43
|
+
const text = element.textContent.trim().toLowerCase();
|
|
44
|
+
// Get its destination.
|
|
45
|
+
const href = element.getAttribute('href');
|
|
46
|
+
// Add to the data.
|
|
47
|
+
linksData.elementData.push([text, href]);
|
|
48
|
+
linksData.textTotals[text] ??= {
|
|
49
|
+
linkCount: 0,
|
|
50
|
+
hrefs: new Set()
|
|
51
|
+
};
|
|
52
|
+
const linkData = linksData.textTotals[text];
|
|
53
|
+
linkData.linkCount++;
|
|
54
|
+
linkData.hrefs.add(href);
|
|
55
|
+
});
|
|
56
|
+
let violationCount = 0;
|
|
57
|
+
const standardInstances = [];
|
|
58
|
+
// For each link text:
|
|
59
|
+
for (const [text, { linkCount, hrefs }] of Object.entries(linksData.textTotals)) {
|
|
60
|
+
const destinationCount = hrefs.size;
|
|
61
|
+
// If links with it violate the rule:
|
|
62
|
+
if (destinationCount > 1) {
|
|
63
|
+
// Increment the violation count.
|
|
64
|
+
violationCount += linkCount;
|
|
65
|
+
// If itemization is required:
|
|
66
|
+
if (withItems) {
|
|
67
|
+
const what = `${linkCount} links with the text “${text}” have ${destinationCount} different destinations`;
|
|
68
|
+
// Add an instance to the standard instances.
|
|
69
|
+
standardInstances.push({
|
|
70
|
+
ruleID: 'linkAmb',
|
|
71
|
+
what,
|
|
72
|
+
ordinalSeverity: 2,
|
|
73
|
+
count: linkCount,
|
|
74
|
+
catalogIndex
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// If there were any violations and itemization is not required:
|
|
80
|
+
if (violationCount && !withItems) {
|
|
81
|
+
const what = 'Links have the same text but different destinations';
|
|
82
|
+
// Add a summary instance to the instances.
|
|
83
|
+
standardInstances.push({
|
|
84
|
+
ruleID: 'linkAmb',
|
|
85
|
+
what,
|
|
86
|
+
ordinalSeverity: 2,
|
|
87
|
+
count: violationCount,
|
|
88
|
+
catalogIndex
|
|
89
|
+
});
|
|
78
90
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
standardInstances.push({
|
|
86
|
-
ruleID: 'linkAmb',
|
|
87
|
-
what,
|
|
88
|
-
ordinalSeverity: 2,
|
|
89
|
-
count: violationCount,
|
|
90
|
-
catalogIndex
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
return {
|
|
94
|
-
data: {},
|
|
95
|
-
totals: [0, 0, violationCount, 0],
|
|
96
|
-
standardInstances
|
|
97
|
-
};
|
|
98
|
-
}, [withItems, catalogIndex]);
|
|
91
|
+
return {
|
|
92
|
+
data: {},
|
|
93
|
+
totals: [0, 0, violationCount, 0],
|
|
94
|
+
standardInstances
|
|
95
|
+
};
|
|
96
|
+
}, [withItems, catalogIndex]);
|
|
99
97
|
};
|
|
98
|
+
exports.reporter = reporter;
|