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/distortion.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/*
|
|
2
3
|
© 2023 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
4
|
© 2026 Jeff Witt.
|
|
@@ -8,37 +9,67 @@
|
|
|
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
|
distortion
|
|
14
17
|
Related to Tenon rule 271.
|
|
15
18
|
This test reports elements whose transform style properties distort the content. Distortion makes text difficult to read.
|
|
19
|
+
Compiled to distortion.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
|
-
|
|
23
|
+
const reporter = async (page, report, _, withItems) => {
|
|
24
|
+
const getBadWhat = element => {
|
|
25
|
+
const { transform } = window.getComputedStyle(element);
|
|
26
|
+
// If the element has a transform (a computed value is always a matrix or matrix3d function):
|
|
27
|
+
if (transform && transform !== 'none') {
|
|
28
|
+
// Get the numeric arguments of the matrix function (its name is excluded, since it may contain a digit).
|
|
29
|
+
const argumentString = transform.slice(transform.indexOf('(') + 1);
|
|
30
|
+
const values = (argumentString.match(/-?\d*\.?\d+(?:e[+-]?\d+)?/g) || []).map(Number);
|
|
31
|
+
const isNear = (value0, value1) => Math.abs(value0 - value1) < 1e-6;
|
|
32
|
+
// Returns the type of a 2-dimensional transformation, or null if it only translates.
|
|
33
|
+
const get2DType = (a, b, c, d) => {
|
|
34
|
+
if (isNear(a, 1) && isNear(b, 0) && isNear(c, 0) && isNear(d, 1)) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
if (isNear(b, 0) && isNear(c, 0)) {
|
|
38
|
+
return 'scale';
|
|
39
|
+
}
|
|
40
|
+
if (isNear(a, d) && isNear(b, -c)) {
|
|
41
|
+
return 'rotation';
|
|
42
|
+
}
|
|
43
|
+
return 'skew';
|
|
44
|
+
};
|
|
45
|
+
let type = 'nonstandard';
|
|
46
|
+
// If the transform is 2-dimensional:
|
|
47
|
+
if (values.length === 6) {
|
|
48
|
+
type = get2DType(values[0], values[1], values[2], values[3]);
|
|
49
|
+
}
|
|
50
|
+
// Otherwise, if it is 3-dimensional:
|
|
51
|
+
else if (values.length === 16) {
|
|
52
|
+
const [m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, , , m43, m44] = values;
|
|
53
|
+
const is2D = [m13, m14, m23, m24, m31, m32, m34, m43].every(value => isNear(value, 0))
|
|
54
|
+
&& isNear(m33, 1)
|
|
55
|
+
&& isNear(m44, 1);
|
|
56
|
+
// If it is equivalent to a 2-dimensional transform, classify it as one.
|
|
57
|
+
if (is2D) {
|
|
58
|
+
type = get2DType(m11, m12, m21, m22);
|
|
59
|
+
}
|
|
60
|
+
// Otherwise, classify it as a perspective or other 3-dimensional transformation.
|
|
61
|
+
else {
|
|
62
|
+
type = isNear(m34, 0) ? '3-dimensional' : 'perspective';
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// If the transformation is distortive, i.e. not a pure translation:
|
|
66
|
+
if (type) {
|
|
67
|
+
// Return a violation description.
|
|
68
|
+
return `Element distorts its text with a ${type} transformation`;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const whats = 'Elements distort their texts';
|
|
73
|
+
return await (0, testaro_1.doTest)(page, report, withItems, 'distortion', 'body, body *', whats, 0, getBadWhat.toString());
|
|
44
74
|
};
|
|
75
|
+
exports.reporter = reporter;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/*
|
|
2
|
+
© 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 {GetBadWhat, Report} from '../types';
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
distortion
|
|
20
|
+
Related to Tenon rule 271.
|
|
21
|
+
This test reports elements whose transform style properties distort the content. Distortion makes text difficult to read.
|
|
22
|
+
Compiled to distortion.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
|
+
const {transform} = window.getComputedStyle(element);
|
|
31
|
+
// If the element has a transform (a computed value is always a matrix or matrix3d function):
|
|
32
|
+
if (transform && transform !== 'none') {
|
|
33
|
+
// Get the numeric arguments of the matrix function (its name is excluded, since it may contain a digit).
|
|
34
|
+
const argumentString = transform.slice(transform.indexOf('(') + 1);
|
|
35
|
+
const values = (argumentString.match(/-?\d*\.?\d+(?:e[+-]?\d+)?/g) || []).map(Number);
|
|
36
|
+
const isNear = (value0: number, value1: number) => Math.abs(value0 - value1) < 1e-6;
|
|
37
|
+
// Returns the type of a 2-dimensional transformation, or null if it only translates.
|
|
38
|
+
const get2DType = (a: number, b: number, c: number, d: number) => {
|
|
39
|
+
if (isNear(a, 1) && isNear(b, 0) && isNear(c, 0) && isNear(d, 1)) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
if (isNear(b, 0) && isNear(c, 0)) {
|
|
43
|
+
return 'scale';
|
|
44
|
+
}
|
|
45
|
+
if (isNear(a, d) && isNear(b, -c)) {
|
|
46
|
+
return 'rotation';
|
|
47
|
+
}
|
|
48
|
+
return 'skew';
|
|
49
|
+
};
|
|
50
|
+
let type: string | null = 'nonstandard';
|
|
51
|
+
// If the transform is 2-dimensional:
|
|
52
|
+
if (values.length === 6) {
|
|
53
|
+
type = get2DType(values[0], values[1], values[2], values[3]);
|
|
54
|
+
}
|
|
55
|
+
// Otherwise, if it is 3-dimensional:
|
|
56
|
+
else if (values.length === 16) {
|
|
57
|
+
const [m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, , , m43, m44] = values;
|
|
58
|
+
const is2D = [m13, m14, m23, m24, m31, m32, m34, m43].every(value => isNear(value, 0))
|
|
59
|
+
&& isNear(m33, 1)
|
|
60
|
+
&& isNear(m44, 1);
|
|
61
|
+
// If it is equivalent to a 2-dimensional transform, classify it as one.
|
|
62
|
+
if (is2D) {
|
|
63
|
+
type = get2DType(m11, m12, m21, m22);
|
|
64
|
+
}
|
|
65
|
+
// Otherwise, classify it as a perspective or other 3-dimensional transformation.
|
|
66
|
+
else {
|
|
67
|
+
type = isNear(m34, 0) ? '3-dimensional' : 'perspective';
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// If the transformation is distortive, i.e. not a pure translation:
|
|
71
|
+
if (type) {
|
|
72
|
+
// Return a violation description.
|
|
73
|
+
return `Element distorts its text with a ${type} transformation`;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
const whats = 'Elements distort their texts';
|
|
78
|
+
return await doTest(
|
|
79
|
+
page, report, withItems, 'distortion', 'body, body *', whats, 0, getBadWhat.toString()
|
|
80
|
+
);
|
|
81
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Page } from 'playwright';
|
|
2
|
+
import type { Report } from '../types';
|
|
3
|
+
export declare const reporter: (page: Page, report: Report) => Promise<{
|
|
4
|
+
data: {
|
|
5
|
+
docHasType: boolean | "";
|
|
6
|
+
};
|
|
7
|
+
totals: number[];
|
|
8
|
+
standardInstances: {
|
|
9
|
+
ruleID: string;
|
|
10
|
+
what: string;
|
|
11
|
+
ordinalSeverity: number;
|
|
12
|
+
count: number;
|
|
13
|
+
catalogIndex: string;
|
|
14
|
+
}[];
|
|
15
|
+
}>;
|
package/testaro/docType.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 Jeff Witt.
|
|
@@ -8,35 +9,34 @@
|
|
|
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
|
docType
|
|
14
17
|
Derived from the bbc-a11y allDocumentsMustHaveAW3cRecommendedDoctype test.
|
|
15
18
|
This test reports a failure to equip the page document with a W3C-recommended HTML doctype.
|
|
19
|
+
Compiled to docType.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
|
// 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
|
-
|
|
22
|
+
const reporter = async (page, report) => {
|
|
23
|
+
// Returns whether the page declares a document type.
|
|
24
|
+
const docHasType = await page.evaluate(() => {
|
|
25
|
+
const docType = document.doctype;
|
|
26
|
+
const docHasType = !!docType && docType.name && docType.name.toLowerCase() === 'html';
|
|
27
|
+
return docHasType;
|
|
28
|
+
});
|
|
29
|
+
// Return data, totals, and, if no document type is declared, a standard instance.
|
|
30
|
+
return {
|
|
31
|
+
data: { docHasType },
|
|
32
|
+
totals: [0, 0, 0, docHasType ? 0 : 1],
|
|
33
|
+
standardInstances: docHasType ? [] : [{
|
|
34
|
+
ruleID: 'docType',
|
|
35
|
+
what: 'Document has no standard HTML doctype preamble',
|
|
36
|
+
ordinalSeverity: 3,
|
|
37
|
+
count: 1,
|
|
38
|
+
catalogIndex: (0, xPath_1.getXPathCatalogIndex)(report, '/html')
|
|
39
|
+
}]
|
|
40
|
+
};
|
|
42
41
|
};
|
|
42
|
+
exports.reporter = reporter;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/*
|
|
2
|
+
© 2022–2023 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
+
© 2026 Jeff Witt.
|
|
4
|
+
© 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 {getXPathCatalogIndex} from '../procs/xPath';
|
|
16
|
+
import type {Report} from '../types';
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
docType
|
|
20
|
+
Derived from the bbc-a11y allDocumentsMustHaveAW3cRecommendedDoctype test.
|
|
21
|
+
This test reports a failure to equip the page document with a W3C-recommended HTML doctype.
|
|
22
|
+
Compiled to docType.js by tsc (issue #73); edit this file, not the emitted one.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
// Runs the test and returns the result.
|
|
26
|
+
export const reporter = async (page: Page, report: Report) => {
|
|
27
|
+
// Returns whether the page declares a document type.
|
|
28
|
+
const docHasType = await page.evaluate(() => {
|
|
29
|
+
const docType = document.doctype;
|
|
30
|
+
const docHasType = !! docType && docType.name && docType.name.toLowerCase() === 'html';
|
|
31
|
+
return docHasType;
|
|
32
|
+
});
|
|
33
|
+
// Return data, totals, and, if no document type is declared, a standard instance.
|
|
34
|
+
return {
|
|
35
|
+
data: {docHasType},
|
|
36
|
+
totals: [0, 0, 0, docHasType ? 0 : 1],
|
|
37
|
+
standardInstances: docHasType ? [] : [{
|
|
38
|
+
ruleID: 'docType',
|
|
39
|
+
what: 'Document has no standard HTML doctype preamble',
|
|
40
|
+
ordinalSeverity: 3,
|
|
41
|
+
count: 1,
|
|
42
|
+
catalogIndex: getXPathCatalogIndex(report, '/html')
|
|
43
|
+
}]
|
|
44
|
+
};
|
|
45
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
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
|
+
total: number;
|
|
6
|
+
items?: {
|
|
7
|
+
tagName: string;
|
|
8
|
+
id: string;
|
|
9
|
+
duplicatedAttribute: string;
|
|
10
|
+
}[];
|
|
11
|
+
prevented?: boolean;
|
|
12
|
+
error?: string;
|
|
13
|
+
};
|
|
14
|
+
totals: number[];
|
|
15
|
+
standardInstances: StandardInstance[];
|
|
16
|
+
}>;
|
package/testaro/dupAtt.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.
|
|
@@ -7,116 +8,124 @@
|
|
|
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 getSource_1 = require("../procs/getSource");
|
|
14
|
+
const xPath_1 = require("../procs/xPath");
|
|
11
15
|
/*
|
|
12
|
-
dupAtt
|
|
16
|
+
dupAtt
|
|
13
17
|
This test reports duplicate attributes. The test is performed on the source of the document, because browsers delete additional same-name attributes in the DOM.
|
|
18
|
+
Compiled to dupAtt.js by tsc (issue #73); edit this file, not the emitted one.
|
|
14
19
|
*/
|
|
15
|
-
|
|
16
|
-
// ########## IMPORTS
|
|
17
|
-
|
|
18
|
-
const {getSource} = require('../procs/getSource');
|
|
19
|
-
const {getXPathCatalogIndex} = require('../procs/xPath');
|
|
20
|
-
|
|
21
20
|
// ########## FUNCTIONS
|
|
22
|
-
|
|
21
|
+
// Returns the catalog index of the element with an ID and tag name, or of the body if none does. Duplicate attributes are found in the source, not the DOM, so the ID is the only handle on the element.
|
|
22
|
+
const getIDCatalogIndex = (report, tagName, id) => {
|
|
23
|
+
const { catalog } = report;
|
|
24
|
+
if (id && catalog) {
|
|
25
|
+
const index = Object.keys(catalog).find(key => catalog[key].id === id && catalog[key].tagName === tagName);
|
|
26
|
+
if (index !== undefined) {
|
|
27
|
+
return index;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return (0, xPath_1.getXPathCatalogIndex)(report, '/html/body');
|
|
31
|
+
};
|
|
23
32
|
// 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
|
-
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
33
|
+
const reporter = async (page, report, _, withItems) => {
|
|
34
|
+
// Initialize the data and standard result.
|
|
35
|
+
const data = { total: 0 };
|
|
36
|
+
if (withItems) {
|
|
37
|
+
data.items = [];
|
|
38
|
+
}
|
|
39
|
+
let totals = [];
|
|
40
|
+
const standardInstances = [];
|
|
41
|
+
// Get the source.
|
|
42
|
+
const sourceData = await (0, getSource_1.getSource)(page);
|
|
43
|
+
// If it was not obtained:
|
|
44
|
+
if (sourceData.prevented) {
|
|
45
|
+
// Report this.
|
|
46
|
+
data.prevented = true;
|
|
47
|
+
data.error = sourceData.error;
|
|
48
|
+
}
|
|
49
|
+
// Otherwise, i.e. if it was obtained:
|
|
50
|
+
else {
|
|
51
|
+
let rawPage = sourceData.source;
|
|
52
|
+
// Change any spacing character sequences in it to single spaces.
|
|
53
|
+
rawPage = rawPage.replace(/\s+/g, ' ');
|
|
54
|
+
// Delete any spaces adjacent to equal symbols in it.
|
|
55
|
+
rawPage = rawPage.replace(/ = | =|= /g, '=');
|
|
56
|
+
// Remove any escaped quotation marks from it.
|
|
57
|
+
rawPage = rawPage.replace(/\\"|\\'/g, '');
|
|
58
|
+
// Remove any script code from it.
|
|
59
|
+
rawPage = rawPage.replace(/<script(?: [^<>]+)?>.*?<\/script>/g, '');
|
|
60
|
+
rawPage = rawPage.replace(/<script(?: [^<>]+)?>/g, '');
|
|
61
|
+
rawPage = rawPage.replace(/<\/script>/g, '');
|
|
62
|
+
// Remove any comments from it.
|
|
63
|
+
rawPage = rawPage.replace(/<!--.*?-->/g, '');
|
|
64
|
+
// Extract the syntactically valid opening tags of its elements.
|
|
65
|
+
// A pageless source would make the match null; the original dereferenced it unguarded.
|
|
66
|
+
let elements = rawPage.match(/<[a-zA-Z]+(?: [^<>]+)?>/g);
|
|
67
|
+
// Delete their enclosing angle brackets and any closing slashes.
|
|
68
|
+
elements = elements.map(element => element.replace(/< ?| ?\/?>/g, ''));
|
|
69
|
+
// Delete the values of any attributes in them.
|
|
70
|
+
const nvElements = elements.map(element => element.replace(/="[^"]*"/g, ''));
|
|
71
|
+
// For each element:
|
|
72
|
+
nvElements.forEach((element, index) => {
|
|
73
|
+
// Identify its tag name and attributes.
|
|
74
|
+
const terms = element.split(' ');
|
|
75
|
+
// If it has 2 or more attributes:
|
|
76
|
+
if (terms.length > 2) {
|
|
77
|
+
// If any is duplicated:
|
|
78
|
+
const tagName = terms[0].toUpperCase();
|
|
79
|
+
const attributes = terms.slice(1);
|
|
80
|
+
attributes.sort();
|
|
81
|
+
const duplicatedAttribute = attributes.find((current, attIndex) => attributes[attIndex + 1] === current);
|
|
82
|
+
if (duplicatedAttribute) {
|
|
83
|
+
// Add data on the element to the data.
|
|
84
|
+
const id = terms.includes('id')
|
|
85
|
+
? elements[index].replace(/^.+id="/, '').replace(/".+/, '')
|
|
86
|
+
: '';
|
|
87
|
+
data.total++;
|
|
88
|
+
if (withItems) {
|
|
89
|
+
data.items.push({
|
|
90
|
+
tagName,
|
|
91
|
+
id,
|
|
92
|
+
duplicatedAttribute
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
// If itemization is required and there are any instances:
|
|
99
|
+
if (data.items) {
|
|
100
|
+
// For each violator:
|
|
101
|
+
data.items.forEach(item => {
|
|
102
|
+
// Add an instance to the standard instances.
|
|
103
|
+
standardInstances.push({
|
|
104
|
+
ruleID: 'dupAtt',
|
|
105
|
+
what: `${item.tagName} element has 2 attributes named ${item.duplicatedAttribute}`,
|
|
106
|
+
ordinalSeverity: 2,
|
|
107
|
+
count: 1,
|
|
108
|
+
catalogIndex: getIDCatalogIndex(report, item.tagName, item.id)
|
|
109
|
+
});
|
|
85
110
|
});
|
|
86
|
-
}
|
|
87
111
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
count: 1,
|
|
100
|
-
catalogIndex: getXPathCatalogIndex(report, '/html/body')
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
// Otherwise, if itemization is not required and there are any violations:
|
|
105
|
-
else if (data.total) {
|
|
106
|
-
// Add a summary instance to the standard instances.
|
|
107
|
-
standardInstances.push({
|
|
108
|
-
ruleID: 'dupAtt',
|
|
109
|
-
what: 'In some elements 2 attributes have the same name',
|
|
110
|
-
ordinalSeverity: 2,
|
|
111
|
-
count: data.total
|
|
112
|
-
});
|
|
112
|
+
// Otherwise, if itemization is not required and there are any violations:
|
|
113
|
+
else if (data.total) {
|
|
114
|
+
// Add a summary instance to the standard instances.
|
|
115
|
+
standardInstances.push({
|
|
116
|
+
ruleID: 'dupAtt',
|
|
117
|
+
what: 'In some elements 2 attributes have the same name',
|
|
118
|
+
ordinalSeverity: 2,
|
|
119
|
+
count: data.total
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
totals = [0, 0, data.total, 0];
|
|
113
123
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
standardInstances
|
|
121
|
-
};
|
|
124
|
+
// Return the data.
|
|
125
|
+
return {
|
|
126
|
+
data,
|
|
127
|
+
totals,
|
|
128
|
+
standardInstances
|
|
129
|
+
};
|
|
122
130
|
};
|
|
131
|
+
exports.reporter = reporter;
|