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/textNodes.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 Jonathan Robert Pool.
|
|
@@ -7,150 +8,153 @@
|
|
|
7
8
|
|
|
8
9
|
SPDX-License-Identifier: MIT
|
|
9
10
|
*/
|
|
10
|
-
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.reporter = void 0;
|
|
11
13
|
/*
|
|
12
14
|
textNodes
|
|
13
15
|
This test reports data about specified text nodes. Meanings of detailLevel values:
|
|
14
16
|
0. Only total node count; no detail.
|
|
15
17
|
1-3. Count of ancestry levels to provide data on (1 = text node, 2 = also parent, 3 = also grandparent)
|
|
18
|
+
Compiled to textNodes.js by tsc (issue #73); edit this file, not the emitted one.
|
|
16
19
|
*/
|
|
17
|
-
|
|
18
20
|
// FUNCTIONS
|
|
19
|
-
|
|
20
21
|
// Runs the test and returns the result.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
});
|
|
36
|
-
// FUNCTION DEFINITIONS START
|
|
37
|
-
// Compacts a string.
|
|
38
|
-
const compact = string => string.replace(/\s+/g, ' ').trim();
|
|
39
|
-
// Compacts and lower-cases a string.
|
|
40
|
-
const toStandardString = string => compact(string).toLowerCase();
|
|
41
|
-
/*
|
|
42
|
-
Gets data (tagName, text if specified, attributes, refLabels, labels, and children)
|
|
43
|
-
on an element.
|
|
44
|
-
*/
|
|
45
|
-
const getElementData = (element, withText) => {
|
|
46
|
-
// Initialize the data.
|
|
47
|
-
const data = {
|
|
48
|
-
tagName: element.tagName
|
|
49
|
-
};
|
|
50
|
-
if (! ['STYLE', 'SCRIPT', 'SVG', 'svg'].includes(element.tagName)) {
|
|
51
|
-
if (withText) {
|
|
52
|
-
data.text = compact(element.textContent);
|
|
53
|
-
}
|
|
54
|
-
// Add data on its attributes, if any, to the data.
|
|
55
|
-
const {attributes} = element;
|
|
56
|
-
if (attributes) {
|
|
57
|
-
data.attributes = [];
|
|
58
|
-
for (const attribute of attributes) {
|
|
59
|
-
const {name, value} = attribute;
|
|
60
|
-
data.attributes.push({
|
|
61
|
-
name,
|
|
62
|
-
value
|
|
63
|
-
});
|
|
64
|
-
// If any attribute is a labeler reference:
|
|
65
|
-
if (name === 'aria-labelledby') {
|
|
66
|
-
// Add the label texts to the data.
|
|
67
|
-
const labelerIDs = value.split(/\s+/);
|
|
68
|
-
data.refLabels = [];
|
|
69
|
-
labelerIDs.forEach(id => {
|
|
70
|
-
const labeler = document.getElementById(id);
|
|
71
|
-
if (labeler) {
|
|
72
|
-
data.refLabels.push(compact(labeler.textContent));
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
// Add data on its labels, if any, to the data.
|
|
79
|
-
const {labels} = element;
|
|
80
|
-
if (labels && labels.length) {
|
|
81
|
-
data.labels = Array.from(labels).map(label => compact(label.textContent));
|
|
82
|
-
}
|
|
83
|
-
// Add data on its child elements, if any, to the data.
|
|
84
|
-
if (element.childElementCount) {
|
|
85
|
-
const children = Array.from(element.children);
|
|
86
|
-
data.children = [];
|
|
87
|
-
children.forEach(child => {
|
|
88
|
-
data.children.push(getElementData(child, true));
|
|
22
|
+
const reporter = async (page, _0, _1, _2, detailLevel, text = '') => {
|
|
23
|
+
let data = {};
|
|
24
|
+
// Get the data on the text nodes.
|
|
25
|
+
try {
|
|
26
|
+
data = await page.evaluate(args => {
|
|
27
|
+
const detailLevel = args[0];
|
|
28
|
+
const text = args[1];
|
|
29
|
+
const matchNodes = [];
|
|
30
|
+
// Collapse any adjacent text nodes.
|
|
31
|
+
document.body.normalize();
|
|
32
|
+
// Remove the irrelevant text content.
|
|
33
|
+
const extraElements = Array.from(document.body.querySelectorAll('style, script, svg'));
|
|
34
|
+
extraElements.forEach(element => {
|
|
35
|
+
element.textContent = '';
|
|
89
36
|
});
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
37
|
+
// FUNCTION DEFINITIONS START
|
|
38
|
+
// Compacts a string.
|
|
39
|
+
const compact = (string) => string.replace(/\s+/g, ' ').trim();
|
|
40
|
+
// Compacts and lower-cases a string.
|
|
41
|
+
const toStandardString = (string) => compact(string).toLowerCase();
|
|
42
|
+
/*
|
|
43
|
+
Gets data (tagName, text if specified, attributes, refLabels, labels, and children)
|
|
44
|
+
on an element.
|
|
45
|
+
*/
|
|
46
|
+
const getElementData = (element, withText) => {
|
|
47
|
+
// Initialize the data.
|
|
48
|
+
const data = {
|
|
49
|
+
tagName: element.tagName
|
|
50
|
+
};
|
|
51
|
+
if (!['STYLE', 'SCRIPT', 'SVG', 'svg'].includes(element.tagName)) {
|
|
52
|
+
if (withText) {
|
|
53
|
+
data.text = compact(element.textContent);
|
|
54
|
+
}
|
|
55
|
+
// Add data on its attributes, if any, to the data.
|
|
56
|
+
const { attributes } = element;
|
|
57
|
+
if (attributes) {
|
|
58
|
+
data.attributes = [];
|
|
59
|
+
for (const attribute of attributes) {
|
|
60
|
+
const { name, value } = attribute;
|
|
61
|
+
data.attributes.push({
|
|
62
|
+
name,
|
|
63
|
+
value
|
|
64
|
+
});
|
|
65
|
+
// If any attribute is a labeler reference:
|
|
66
|
+
if (name === 'aria-labelledby') {
|
|
67
|
+
// Add the label texts to the data.
|
|
68
|
+
const labelerIDs = value.split(/\s+/);
|
|
69
|
+
data.refLabels = [];
|
|
70
|
+
labelerIDs.forEach(id => {
|
|
71
|
+
const labeler = document.getElementById(id);
|
|
72
|
+
if (labeler) {
|
|
73
|
+
data.refLabels.push(compact(labeler.textContent));
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Add data on its labels, if any, to the data.
|
|
80
|
+
const { labels } = element;
|
|
81
|
+
if (labels && labels.length) {
|
|
82
|
+
data.labels = Array.from(labels).map(label => compact(label.textContent));
|
|
83
|
+
}
|
|
84
|
+
// Add data on its child elements, if any, to the data.
|
|
85
|
+
if (element.childElementCount) {
|
|
86
|
+
const children = Array.from(element.children);
|
|
87
|
+
data.children = [];
|
|
88
|
+
children.forEach(child => {
|
|
89
|
+
data.children.push(getElementData(child, true));
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return data;
|
|
94
|
+
};
|
|
95
|
+
// FUNCTION DEFINITIONS END
|
|
96
|
+
const stdText = toStandardString(text);
|
|
97
|
+
// Create a collection of the text nodes.
|
|
98
|
+
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
|
|
99
|
+
// Get their count.
|
|
100
|
+
const data = { nodeCount: 0 };
|
|
101
|
+
let more = true;
|
|
102
|
+
while (more) {
|
|
103
|
+
if (walker.nextNode()) {
|
|
104
|
+
const stdCurrent = toStandardString(walker.currentNode.nodeValue);
|
|
105
|
+
if (stdCurrent.includes(stdText)) {
|
|
106
|
+
data.nodeCount++;
|
|
107
|
+
matchNodes.push(walker.currentNode);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
more = false;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// If itemization is required:
|
|
115
|
+
if (detailLevel > 0) {
|
|
116
|
+
// Initialize the item data.
|
|
117
|
+
data.items = [];
|
|
118
|
+
// For each text node matching any specified text:
|
|
119
|
+
matchNodes.forEach(node => {
|
|
120
|
+
// Initialize the data on it.
|
|
121
|
+
const itemData = {
|
|
122
|
+
text: compact(node.nodeValue)
|
|
123
|
+
};
|
|
124
|
+
// If ancestral itemization is required:
|
|
125
|
+
if (detailLevel > 1) {
|
|
126
|
+
// Add the ancestral data, starting with the parent, to the item data.
|
|
127
|
+
itemData.ancestors = [];
|
|
128
|
+
let base = node;
|
|
129
|
+
let currentLevel = 1;
|
|
130
|
+
// For each specified ancestral distance:
|
|
131
|
+
while (currentLevel++ < detailLevel) {
|
|
132
|
+
// Add data on it to the data on the text node.
|
|
133
|
+
const newBase = base.parentElement;
|
|
134
|
+
// Omit the text of the text node if the ancestor is its parent.
|
|
135
|
+
itemData.ancestors.push(getElementData(newBase, currentLevel > 2));
|
|
136
|
+
base = newBase;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Add the node data to the itemization.
|
|
140
|
+
data.items.push(itemData);
|
|
141
|
+
});
|
|
134
142
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
143
|
+
return data;
|
|
144
|
+
}, [detailLevel, text]);
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
console.log(`ERROR performing test (${error.message.replace(/\n.+/s, '')})`);
|
|
148
|
+
data = {
|
|
149
|
+
prevented: true,
|
|
150
|
+
error: 'Test failed'
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
// Return the result.
|
|
154
|
+
return {
|
|
155
|
+
data,
|
|
156
|
+
totals: [],
|
|
157
|
+
standardInstances: []
|
|
148
158
|
};
|
|
149
|
-
}
|
|
150
|
-
// Return the result.
|
|
151
|
-
return {
|
|
152
|
-
data,
|
|
153
|
-
totals: [],
|
|
154
|
-
standardInstances: []
|
|
155
|
-
};
|
|
156
159
|
};
|
|
160
|
+
exports.reporter = reporter;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/*
|
|
2
|
+
© 2023–2024 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
© 2026 Jonathan Robert Pool.
|
|
4
|
+
|
|
5
|
+
Licensed under the MIT License. See LICENSE file at the project root or
|
|
6
|
+
https://opensource.org/license/mit/ for details.
|
|
7
|
+
|
|
8
|
+
SPDX-License-Identifier: MIT
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// IMPORTS
|
|
12
|
+
|
|
13
|
+
import type {Page} from 'playwright';
|
|
14
|
+
|
|
15
|
+
// TYPES
|
|
16
|
+
|
|
17
|
+
// Data on one attribute of an element.
|
|
18
|
+
interface AttributeDatum {
|
|
19
|
+
name: string;
|
|
20
|
+
value: string;
|
|
21
|
+
}
|
|
22
|
+
// Data on an element, possibly with data on its descendants.
|
|
23
|
+
interface ElementData {
|
|
24
|
+
tagName: string;
|
|
25
|
+
text?: string;
|
|
26
|
+
attributes?: AttributeDatum[];
|
|
27
|
+
refLabels?: string[];
|
|
28
|
+
labels?: string[];
|
|
29
|
+
children?: ElementData[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/*
|
|
33
|
+
textNodes
|
|
34
|
+
This test reports data about specified text nodes. Meanings of detailLevel values:
|
|
35
|
+
0. Only total node count; no detail.
|
|
36
|
+
1-3. Count of ancestry levels to provide data on (1 = text node, 2 = also parent, 3 = also grandparent)
|
|
37
|
+
Compiled to textNodes.js by tsc (issue #73); edit this file, not the emitted one.
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
// FUNCTIONS
|
|
41
|
+
|
|
42
|
+
// Runs the test and returns the result.
|
|
43
|
+
export const reporter = async (
|
|
44
|
+
page: Page, _0: unknown, _1: unknown, _2: unknown, detailLevel: number, text = ''
|
|
45
|
+
) => {
|
|
46
|
+
let data: Record<string, unknown> = {};
|
|
47
|
+
// Get the data on the text nodes.
|
|
48
|
+
try {
|
|
49
|
+
data = await page.evaluate(args => {
|
|
50
|
+
const detailLevel = args[0];
|
|
51
|
+
const text = args[1];
|
|
52
|
+
const matchNodes: Node[] = [];
|
|
53
|
+
// Collapse any adjacent text nodes.
|
|
54
|
+
document.body.normalize();
|
|
55
|
+
// Remove the irrelevant text content.
|
|
56
|
+
const extraElements = Array.from(document.body.querySelectorAll('style, script, svg'));
|
|
57
|
+
extraElements.forEach(element => {
|
|
58
|
+
element.textContent = '';
|
|
59
|
+
});
|
|
60
|
+
// FUNCTION DEFINITIONS START
|
|
61
|
+
// Compacts a string.
|
|
62
|
+
const compact = (string: string) => string.replace(/\s+/g, ' ').trim();
|
|
63
|
+
// Compacts and lower-cases a string.
|
|
64
|
+
const toStandardString = (string: string) => compact(string).toLowerCase();
|
|
65
|
+
/*
|
|
66
|
+
Gets data (tagName, text if specified, attributes, refLabels, labels, and children)
|
|
67
|
+
on an element.
|
|
68
|
+
*/
|
|
69
|
+
const getElementData = (element: Element, withText: boolean): ElementData => {
|
|
70
|
+
// Initialize the data.
|
|
71
|
+
const data: ElementData = {
|
|
72
|
+
tagName: element.tagName
|
|
73
|
+
};
|
|
74
|
+
if (! ['STYLE', 'SCRIPT', 'SVG', 'svg'].includes(element.tagName)) {
|
|
75
|
+
if (withText) {
|
|
76
|
+
data.text = compact(element.textContent!);
|
|
77
|
+
}
|
|
78
|
+
// Add data on its attributes, if any, to the data.
|
|
79
|
+
const {attributes} = element;
|
|
80
|
+
if (attributes) {
|
|
81
|
+
data.attributes = [];
|
|
82
|
+
for (const attribute of attributes) {
|
|
83
|
+
const {name, value} = attribute;
|
|
84
|
+
data.attributes.push({
|
|
85
|
+
name,
|
|
86
|
+
value
|
|
87
|
+
});
|
|
88
|
+
// If any attribute is a labeler reference:
|
|
89
|
+
if (name === 'aria-labelledby') {
|
|
90
|
+
// Add the label texts to the data.
|
|
91
|
+
const labelerIDs = value.split(/\s+/);
|
|
92
|
+
data.refLabels = [];
|
|
93
|
+
labelerIDs.forEach(id => {
|
|
94
|
+
const labeler = document.getElementById(id);
|
|
95
|
+
if (labeler) {
|
|
96
|
+
data.refLabels!.push(compact(labeler.textContent!));
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Add data on its labels, if any, to the data.
|
|
103
|
+
const {labels} = element as HTMLInputElement;
|
|
104
|
+
if (labels && labels.length) {
|
|
105
|
+
data.labels = Array.from(labels).map(label => compact(label.textContent!));
|
|
106
|
+
}
|
|
107
|
+
// Add data on its child elements, if any, to the data.
|
|
108
|
+
if (element.childElementCount) {
|
|
109
|
+
const children = Array.from(element.children);
|
|
110
|
+
data.children = [];
|
|
111
|
+
children.forEach(child => {
|
|
112
|
+
data.children!.push(getElementData(child, true));
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return data;
|
|
117
|
+
};
|
|
118
|
+
// FUNCTION DEFINITIONS END
|
|
119
|
+
const stdText = toStandardString(text);
|
|
120
|
+
// Create a collection of the text nodes.
|
|
121
|
+
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
|
|
122
|
+
// Get their count.
|
|
123
|
+
const data: {
|
|
124
|
+
nodeCount: number;
|
|
125
|
+
items?: {text: string; ancestors?: ElementData[]}[];
|
|
126
|
+
} = {nodeCount: 0};
|
|
127
|
+
let more = true;
|
|
128
|
+
while(more) {
|
|
129
|
+
if (walker.nextNode()) {
|
|
130
|
+
const stdCurrent = toStandardString(walker.currentNode.nodeValue!);
|
|
131
|
+
if (stdCurrent.includes(stdText)) {
|
|
132
|
+
data.nodeCount++;
|
|
133
|
+
matchNodes.push(walker.currentNode);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
more = false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// If itemization is required:
|
|
141
|
+
if (detailLevel > 0) {
|
|
142
|
+
// Initialize the item data.
|
|
143
|
+
data.items = [];
|
|
144
|
+
// For each text node matching any specified text:
|
|
145
|
+
matchNodes.forEach(node => {
|
|
146
|
+
// Initialize the data on it.
|
|
147
|
+
const itemData: {text: string; ancestors?: ElementData[]} = {
|
|
148
|
+
text: compact(node.nodeValue!)
|
|
149
|
+
};
|
|
150
|
+
// If ancestral itemization is required:
|
|
151
|
+
if (detailLevel > 1) {
|
|
152
|
+
// Add the ancestral data, starting with the parent, to the item data.
|
|
153
|
+
itemData.ancestors = [];
|
|
154
|
+
let base: Node = node;
|
|
155
|
+
let currentLevel = 1;
|
|
156
|
+
// For each specified ancestral distance:
|
|
157
|
+
while(currentLevel++ < detailLevel) {
|
|
158
|
+
// Add data on it to the data on the text node.
|
|
159
|
+
const newBase = base.parentElement;
|
|
160
|
+
// Omit the text of the text node if the ancestor is its parent.
|
|
161
|
+
itemData.ancestors!.push(getElementData(newBase!, currentLevel > 2));
|
|
162
|
+
base = newBase!;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Add the node data to the itemization.
|
|
166
|
+
data.items!.push(itemData);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
return data;
|
|
170
|
+
}, [detailLevel, text] as const);
|
|
171
|
+
}
|
|
172
|
+
catch(error) {
|
|
173
|
+
console.log(`ERROR performing test (${(error as Error).message.replace(/\n.+/s, '')})`);
|
|
174
|
+
data = {
|
|
175
|
+
prevented: true,
|
|
176
|
+
error: 'Test failed'
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
// Return the result.
|
|
180
|
+
return {
|
|
181
|
+
data,
|
|
182
|
+
totals: [],
|
|
183
|
+
standardInstances: []
|
|
184
|
+
};
|
|
185
|
+
};
|
package/testaro/textSem.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
|
© 2026 Jeff Witt.
|
|
@@ -7,38 +8,34 @@
|
|
|
7
8
|
|
|
8
9
|
SPDX-License-Identifier: MIT
|
|
9
10
|
*/
|
|
10
|
-
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.reporter = void 0;
|
|
13
|
+
const testaro_1 = require("../procs/testaro");
|
|
11
14
|
/*
|
|
12
15
|
textSem
|
|
13
16
|
This test reports semantically vague inline elements: i, b, small.
|
|
17
|
+
Compiled to textSem.js by tsc (issue #73); edit this file, not the emitted one.
|
|
14
18
|
*/
|
|
15
|
-
|
|
16
|
-
// IMPORTS
|
|
17
|
-
|
|
18
|
-
const {doTest} = require('../procs/testaro');
|
|
19
|
-
|
|
20
19
|
// FUNCTIONS
|
|
21
|
-
|
|
22
20
|
// Runs the test and returns the result.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
page, report, withItems, 'textSem', selector, whats, 0, getBadWhat.toString()
|
|
43
|
-
);
|
|
21
|
+
const reporter = async (page, report, _, withItems) => {
|
|
22
|
+
const getBadWhat = element => {
|
|
23
|
+
const isVisible = element.checkVisibility({
|
|
24
|
+
contentVisibilityAuto: true,
|
|
25
|
+
opacityProperty: true,
|
|
26
|
+
visibilityProperty: true
|
|
27
|
+
});
|
|
28
|
+
// If the element is visible:
|
|
29
|
+
if (isVisible) {
|
|
30
|
+
// If it has text content:
|
|
31
|
+
if (element.textContent.trim().replace(/\s/g, '')) {
|
|
32
|
+
// Return a violation description.
|
|
33
|
+
return `Element type (${element.tagName}) is semantically vague`;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const selector = 'body i, body b, body small';
|
|
38
|
+
const whats = 'Semantically vague elements i, b, and/or small are used';
|
|
39
|
+
return await (0, testaro_1.doTest)(page, report, withItems, 'textSem', selector, whats, 0, getBadWhat.toString());
|
|
44
40
|
};
|
|
41
|
+
exports.reporter = reporter;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/*
|
|
2
|
+
© 2025 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 https://opensource.org/license/mit/ for details.
|
|
7
|
+
|
|
8
|
+
SPDX-License-Identifier: MIT
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// IMPORTS
|
|
12
|
+
|
|
13
|
+
import type {Page} from 'playwright';
|
|
14
|
+
import {doTest} from '../procs/testaro';
|
|
15
|
+
import type {GetBadWhat, Report} from '../types';
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
textSem
|
|
19
|
+
This test reports semantically vague inline elements: i, b, small.
|
|
20
|
+
Compiled to textSem.js by tsc (issue #73); edit this file, not the emitted one.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
// FUNCTIONS
|
|
24
|
+
|
|
25
|
+
// Runs the test and returns the result.
|
|
26
|
+
export const reporter = async (page: Page, report: Report, _: unknown, withItems: boolean) => {
|
|
27
|
+
const getBadWhat: GetBadWhat = element => {
|
|
28
|
+
const isVisible = element.checkVisibility({
|
|
29
|
+
contentVisibilityAuto: true,
|
|
30
|
+
opacityProperty: true,
|
|
31
|
+
visibilityProperty: true
|
|
32
|
+
});
|
|
33
|
+
// If the element is visible:
|
|
34
|
+
if (isVisible) {
|
|
35
|
+
// If it has text content:
|
|
36
|
+
if (element.textContent.trim().replace(/\s/g, '')) {
|
|
37
|
+
// Return a violation description.
|
|
38
|
+
return `Element type (${element.tagName}) is semantically vague`;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const selector = 'body i, body b, body small';
|
|
43
|
+
const whats = 'Semantically vague elements i, b, and/or small are used';
|
|
44
|
+
return await doTest(
|
|
45
|
+
page, report, withItems, 'textSem', selector, whats, 0, getBadWhat.toString()
|
|
46
|
+
);
|
|
47
|
+
};
|
package/testaro/title.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/*
|
|
2
3
|
© 2022–2023 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
4
|
© 2026 Jonathan Robert Pool.
|
|
@@ -6,21 +7,23 @@
|
|
|
6
7
|
|
|
7
8
|
SPDX-License-Identifier: MIT
|
|
8
9
|
*/
|
|
9
|
-
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.reporter = void 0;
|
|
10
12
|
/*
|
|
11
13
|
title
|
|
12
|
-
This test reports the page title.
|
|
14
|
+
This test reports the page title. Compiled to title.js by tsc (issue #73); edit this file,
|
|
15
|
+
not the emitted one.
|
|
13
16
|
*/
|
|
14
|
-
|
|
15
17
|
// Runs the test and returns the result.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
const reporter = async (page) => {
|
|
19
|
+
const title = await page.title();
|
|
20
|
+
return {
|
|
21
|
+
data: {
|
|
22
|
+
success: true,
|
|
23
|
+
title
|
|
24
|
+
},
|
|
25
|
+
totals: [],
|
|
26
|
+
standardInstances: []
|
|
27
|
+
};
|
|
26
28
|
};
|
|
29
|
+
exports.reporter = reporter;
|