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/buttonMenu.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,356 +9,353 @@
|
|
|
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
|
buttonMenu
|
|
14
17
|
This test reports nonstandard navigation among menu items of button-controlled menus. Standards are based on https://www.w3.org/TR/wai-aria-practices-1.1/#menu. The trialKeys argument is an array of strings, each of which may be 'Home', 'End', '+', or '-'. The '+' string represents the ArrowDown or ArrowRight key, and the '-' string represents the ArrowUp or ArrowLeft key, depending on the orientation of the current menu. When the trialKeys argument is missing or is an empty array, 12 keys are selected at random.
|
|
18
|
+
Compiled to buttonMenu.js by tsc (issue #73); edit this file, not the emitted one.
|
|
15
19
|
*/
|
|
16
|
-
|
|
17
|
-
// IMPORTS
|
|
18
|
-
|
|
19
|
-
const {getXPathCatalogIndex} = require('../procs/xPath');
|
|
20
|
-
|
|
21
20
|
// ########## FUNCTIONS
|
|
22
|
-
|
|
23
21
|
// Returns data about the element referenced by a locator.
|
|
24
|
-
const getLocatorData = async loc => {
|
|
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
|
-
// If an ID-based selector could not be defined:
|
|
81
|
-
if (data.location.type === 'box') {
|
|
82
|
-
// Define a bounding-box-based location.
|
|
83
|
-
const rawSpec = await loc.boundingBox();
|
|
84
|
-
// If there is a bounding box (i.e. the element is visible):
|
|
85
|
-
if (rawSpec) {
|
|
86
|
-
// Populate the location.
|
|
87
|
-
Object.keys(rawSpec).forEach(specName => {
|
|
88
|
-
data.location.spec[specName] = Math.round(rawSpec[specName]);
|
|
22
|
+
const getLocatorData = async (loc) => {
|
|
23
|
+
const locCount = await loc.count();
|
|
24
|
+
// If the locator identifies exactly 1 element:
|
|
25
|
+
if (locCount === 1) {
|
|
26
|
+
// Get the facts obtainable from the browser.
|
|
27
|
+
const data = await loc.evaluate((element) => {
|
|
28
|
+
// Tag name.
|
|
29
|
+
const tagName = element.tagName;
|
|
30
|
+
// ID.
|
|
31
|
+
const id = element.id || '';
|
|
32
|
+
// Texts.
|
|
33
|
+
const { textContent } = element;
|
|
34
|
+
const alts = Array.from(element.querySelectorAll('img[alt]:not([alt=""])'));
|
|
35
|
+
const altTexts = alts.map(alt => alt.getAttribute('alt'));
|
|
36
|
+
const altsText = altTexts.join(' ');
|
|
37
|
+
const ariaLabelText = element.ariaLabel || '';
|
|
38
|
+
const refLabelID = element.getAttribute('aria-labelledby');
|
|
39
|
+
const refLabel = refLabelID ? document.getElementById(refLabelID) : '';
|
|
40
|
+
const refLabelText = refLabel ? refLabel.textContent : '';
|
|
41
|
+
let labelsText = '';
|
|
42
|
+
if (tagName === 'INPUT') {
|
|
43
|
+
const labels = element.labels || [];
|
|
44
|
+
const labelTexts = [];
|
|
45
|
+
labels.forEach(label => {
|
|
46
|
+
labelTexts.push(label.textContent);
|
|
47
|
+
});
|
|
48
|
+
labelsText = labelTexts.join(' ');
|
|
49
|
+
}
|
|
50
|
+
let text = [textContent, altsText, ariaLabelText, refLabelText, labelsText]
|
|
51
|
+
.join(' ')
|
|
52
|
+
.replace(/\s+/g, ' ')
|
|
53
|
+
.trim();
|
|
54
|
+
if (!text) {
|
|
55
|
+
text = element.outerHTML.replace(/\s+/g, ' ').trim();
|
|
56
|
+
}
|
|
57
|
+
if (/^<[^<>]+>$/.test(text)) {
|
|
58
|
+
text = element.parentElement.outerHTML.replace(/\s+/g, ' ').trim();
|
|
59
|
+
}
|
|
60
|
+
// Location.
|
|
61
|
+
let location = {
|
|
62
|
+
doc: 'dom',
|
|
63
|
+
type: 'box',
|
|
64
|
+
spec: {}
|
|
65
|
+
};
|
|
66
|
+
if (id) {
|
|
67
|
+
location.type = 'selector';
|
|
68
|
+
location.spec = `#${id}`;
|
|
69
|
+
}
|
|
70
|
+
// Return the data.
|
|
71
|
+
return {
|
|
72
|
+
tagName,
|
|
73
|
+
id,
|
|
74
|
+
location,
|
|
75
|
+
excerpt: text
|
|
76
|
+
};
|
|
89
77
|
});
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
78
|
+
// If an ID-based selector could not be defined:
|
|
79
|
+
if (data.location.type === 'box') {
|
|
80
|
+
// Define a bounding-box-based location.
|
|
81
|
+
const rawSpec = await loc.boundingBox();
|
|
82
|
+
// If there is a bounding box (i.e. the element is visible):
|
|
83
|
+
if (rawSpec) {
|
|
84
|
+
// Populate the location.
|
|
85
|
+
Object.keys(rawSpec).forEach(specName => {
|
|
86
|
+
data.location.spec[specName] = Math.round(rawSpec[specName]);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
// Otherwise, i.e. if there is no bounding box:
|
|
90
|
+
else {
|
|
91
|
+
// Empty the location.
|
|
92
|
+
data.location.doc = '';
|
|
93
|
+
data.location.type = '';
|
|
94
|
+
data.location.spec = '';
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// If the text is long:
|
|
98
|
+
if (data.excerpt.length > 400) {
|
|
99
|
+
// Truncate its middle.
|
|
100
|
+
data.excerpt = `${data.excerpt.slice(0, 200)} … ${data.excerpt.slice(-200)}`;
|
|
101
|
+
}
|
|
102
|
+
// Return the data.
|
|
103
|
+
return data;
|
|
98
104
|
}
|
|
99
|
-
//
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
105
|
+
// Otherwise, i.e. if it does not identify exactly 1 element:
|
|
106
|
+
else {
|
|
107
|
+
// Report this.
|
|
108
|
+
console.log(`ERROR: Locator count to get data from is ${locCount} instead of 1`);
|
|
109
|
+
return null;
|
|
103
110
|
}
|
|
104
|
-
// Return the data.
|
|
105
|
-
return data;
|
|
106
|
-
}
|
|
107
|
-
// Otherwise, i.e. if it does not identify exactly 1 element:
|
|
108
|
-
else {
|
|
109
|
-
// Report this.
|
|
110
|
-
console.log(`ERROR: Locator count to get data from is ${locCount} instead of 1`);
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
111
|
};
|
|
114
112
|
// Returns an adjacent index, with wrapping.
|
|
115
113
|
const getAdjacentIndexWithWrap = (groupSize, startIndex, increment) => {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
114
|
+
let newIndex = startIndex + increment;
|
|
115
|
+
if (newIndex < 0) {
|
|
116
|
+
newIndex = groupSize - 1;
|
|
117
|
+
}
|
|
118
|
+
else if (newIndex > groupSize - 1) {
|
|
119
|
+
newIndex = 0;
|
|
120
|
+
}
|
|
121
|
+
return newIndex;
|
|
124
122
|
};
|
|
125
123
|
// Returns whether a key created the expected effective focus.
|
|
126
124
|
const focusSuccess = async (miLocsDir, priorIndex, key, isPseudo) => {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
else {
|
|
147
|
-
return document.activeElement === el;
|
|
148
|
-
}
|
|
149
|
-
}, isPseudo);
|
|
150
|
-
// If it is:
|
|
151
|
-
if (hasFocus) {
|
|
152
|
-
// Get whether the effective focus is as expected and update the result.
|
|
153
|
-
const miFocIndex = miLocsDir.indexOf(miLocDir);
|
|
154
|
-
const miCount = miLocsDir.length;
|
|
155
|
-
if (key === 'Home' && miFocIndex === 0) {
|
|
156
|
-
result.isOK = true;
|
|
157
|
-
result.newFocIndex = 0;
|
|
158
|
-
}
|
|
159
|
-
else if (key === 'End' && miFocIndex === miCount - 1) {
|
|
160
|
-
result.isOK = true;
|
|
161
|
-
result.newFocIndex = miCount - 1;
|
|
162
|
-
}
|
|
163
|
-
else if (['ArrowLeft', 'ArrowUp'].includes(key)) {
|
|
164
|
-
const expectedIndex = getAdjacentIndexWithWrap(miCount, priorIndex, -1);
|
|
165
|
-
if (miFocIndex === expectedIndex) {
|
|
166
|
-
result.isOK = true;
|
|
167
|
-
result.newFocIndex = expectedIndex;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
else if (['ArrowRight', 'ArrowDown'].includes(key)) {
|
|
171
|
-
const expectedIndex = getAdjacentIndexWithWrap(miCount, priorIndex, 1);
|
|
172
|
-
if (miFocIndex === expectedIndex) {
|
|
173
|
-
result.isOK = true;
|
|
174
|
-
result.newFocIndex = expectedIndex;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
break;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
// Return the result.
|
|
181
|
-
return result;
|
|
182
|
-
};
|
|
183
|
-
// Performs the test and reports the result.
|
|
184
|
-
exports.reporter = async (page, report, _0, withItems, trialKeySpecs = []) => {
|
|
185
|
-
// Initialize the result.
|
|
186
|
-
const data = {};
|
|
187
|
-
const totals = [0, 0, 0, 0];
|
|
188
|
-
const standardInstances = [];
|
|
189
|
-
// Get locators for all menu buttons.
|
|
190
|
-
const mbLocAll = page.locator(
|
|
191
|
-
'button[aria-controls][aria-expanded][aria-haspopup=true], button[aria-controls][aria-expanded][aria-haspopup=menu]'
|
|
192
|
-
);
|
|
193
|
-
const mbLocsAll = await mbLocAll.all();
|
|
194
|
-
// For each menu button:
|
|
195
|
-
for (const mbLoc of mbLocsAll) {
|
|
196
|
-
// Get a locator for its menu.
|
|
197
|
-
const menuID = await mbLoc.getAttribute('aria-controls');
|
|
198
|
-
const menuLoc = page.locator(`[id=${menuID}][role=menu], [id=${menuID}][role=menubar]`);
|
|
199
|
-
// If the button controls exactly 1 menu:
|
|
200
|
-
if (menuLoc && await menuLoc.count() === 1) {
|
|
201
|
-
// Get data on the menu.
|
|
202
|
-
const elData = await getLocatorData(menuLoc);
|
|
203
|
-
// If data were obtained:
|
|
204
|
-
if (elData) {
|
|
205
|
-
// Get the orientation and focus-management type of the menu.
|
|
206
|
-
const extraData = await menuLoc.evaluate(element => {
|
|
207
|
-
const extraData = {};
|
|
208
|
-
let orientation = element.getAttribute('aria-orientation');
|
|
209
|
-
if (! orientation) {
|
|
210
|
-
const role = element.getAttribute('role');
|
|
211
|
-
if (role === 'menubar') {
|
|
212
|
-
orientation = 'horizontal';
|
|
213
|
-
}
|
|
214
|
-
else if (role === 'menu') {
|
|
215
|
-
orientation = 'vertical';
|
|
125
|
+
// Initialize the result.
|
|
126
|
+
const result = {
|
|
127
|
+
isOK: false,
|
|
128
|
+
newFocIndex: null
|
|
129
|
+
};
|
|
130
|
+
// For each of the menu items directly descending from the menu:
|
|
131
|
+
for (const miLocDir of miLocsDir) {
|
|
132
|
+
// Get whether it is effectively focused.
|
|
133
|
+
const hasFocus = await miLocDir.evaluate((el, isPseudo) => {
|
|
134
|
+
if (isPseudo) {
|
|
135
|
+
// The page has an active element whenever this runs; verbatim from the original.
|
|
136
|
+
const effectiveID = document.activeElement.getAttribute('aria-activeDescendant');
|
|
137
|
+
if (effectiveID) {
|
|
138
|
+
const effectiveEl = document.getElementById(effectiveID);
|
|
139
|
+
return effectiveEl === el;
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
216
144
|
}
|
|
217
145
|
else {
|
|
218
|
-
|
|
146
|
+
return document.activeElement === el;
|
|
219
147
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
// If there are at least 2 of them:
|
|
240
|
-
if (miLocsDir.length > 1) {
|
|
241
|
-
// Ensure that the menu is collapsed.
|
|
242
|
-
await menuLoc.evaluate(element => {
|
|
243
|
-
element.setAttribute('aria-expanded', false);
|
|
244
|
-
});
|
|
245
|
-
// Focus the menu button and press the key that opens its menu from the top.
|
|
246
|
-
await mbLoc.press(extraData.orientation === 'horizontal' ? 'ArrowRight' : 'ArrowDown');
|
|
247
|
-
// If trial keys have been specified:
|
|
248
|
-
const trialKeys = [];
|
|
249
|
-
if (trialKeySpecs.length) {
|
|
250
|
-
// Implement them.
|
|
251
|
-
trialKeySpecs.forEach(spec => {
|
|
252
|
-
if (['Home', 'End'].includes(spec)) {
|
|
253
|
-
trialKeys.push(spec);
|
|
148
|
+
}, isPseudo);
|
|
149
|
+
// If it is:
|
|
150
|
+
if (hasFocus) {
|
|
151
|
+
// Get whether the effective focus is as expected and update the result.
|
|
152
|
+
const miFocIndex = miLocsDir.indexOf(miLocDir);
|
|
153
|
+
const miCount = miLocsDir.length;
|
|
154
|
+
if (key === 'Home' && miFocIndex === 0) {
|
|
155
|
+
result.isOK = true;
|
|
156
|
+
result.newFocIndex = 0;
|
|
157
|
+
}
|
|
158
|
+
else if (key === 'End' && miFocIndex === miCount - 1) {
|
|
159
|
+
result.isOK = true;
|
|
160
|
+
result.newFocIndex = miCount - 1;
|
|
161
|
+
}
|
|
162
|
+
else if (['ArrowLeft', 'ArrowUp'].includes(key)) {
|
|
163
|
+
const expectedIndex = getAdjacentIndexWithWrap(miCount, priorIndex, -1);
|
|
164
|
+
if (miFocIndex === expectedIndex) {
|
|
165
|
+
result.isOK = true;
|
|
166
|
+
result.newFocIndex = expectedIndex;
|
|
254
167
|
}
|
|
255
|
-
|
|
256
|
-
|
|
168
|
+
}
|
|
169
|
+
else if (['ArrowRight', 'ArrowDown'].includes(key)) {
|
|
170
|
+
const expectedIndex = getAdjacentIndexWithWrap(miCount, priorIndex, 1);
|
|
171
|
+
if (miFocIndex === expectedIndex) {
|
|
172
|
+
result.isOK = true;
|
|
173
|
+
result.newFocIndex = expectedIndex;
|
|
257
174
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
175
|
+
}
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Return the result.
|
|
180
|
+
return result;
|
|
181
|
+
};
|
|
182
|
+
// Performs the test and reports the result.
|
|
183
|
+
const reporter = async (page, report, _0, withItems, trialKeySpecs = []) => {
|
|
184
|
+
// Initialize the result.
|
|
185
|
+
const data = {};
|
|
186
|
+
const totals = [0, 0, 0, 0];
|
|
187
|
+
const standardInstances = [];
|
|
188
|
+
// Get locators for all menu buttons.
|
|
189
|
+
const mbLocAll = page.locator('button[aria-controls][aria-expanded][aria-haspopup=true], button[aria-controls][aria-expanded][aria-haspopup=menu]');
|
|
190
|
+
const mbLocsAll = await mbLocAll.all();
|
|
191
|
+
// For each menu button:
|
|
192
|
+
for (const mbLoc of mbLocsAll) {
|
|
193
|
+
// Get a locator for its menu.
|
|
194
|
+
const menuID = await mbLoc.getAttribute('aria-controls');
|
|
195
|
+
const menuLoc = page.locator(`[id=${menuID}][role=menu], [id=${menuID}][role=menubar]`);
|
|
196
|
+
// If the button controls exactly 1 menu:
|
|
197
|
+
if (menuLoc && await menuLoc.count() === 1) {
|
|
198
|
+
// Get data on the menu.
|
|
199
|
+
const elData = await getLocatorData(menuLoc);
|
|
200
|
+
// If data were obtained:
|
|
201
|
+
if (elData) {
|
|
202
|
+
// Get the orientation and focus-management type of the menu.
|
|
203
|
+
const extraData = await menuLoc.evaluate(element => {
|
|
204
|
+
const extraData = {};
|
|
205
|
+
let orientation = element.getAttribute('aria-orientation');
|
|
206
|
+
if (!orientation) {
|
|
207
|
+
const role = element.getAttribute('role');
|
|
208
|
+
if (role === 'menubar') {
|
|
209
|
+
orientation = 'horizontal';
|
|
210
|
+
}
|
|
211
|
+
else if (role === 'menu') {
|
|
212
|
+
orientation = 'vertical';
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
orientation = null;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
extraData.orientation = orientation;
|
|
219
|
+
const isPseudo = !!element.getAttribute('aria-activedescendant');
|
|
220
|
+
extraData.isPseudo = isPseudo;
|
|
221
|
+
return extraData;
|
|
222
|
+
});
|
|
223
|
+
// If they were obtained:
|
|
224
|
+
if (extraData) {
|
|
225
|
+
// Get locators for its descendant non-menu menu items.
|
|
226
|
+
const miLocAll = menuLoc.locator('[role=menuitem]:not([role=menu], [role=menubar])');
|
|
227
|
+
// Get which of them are direct descendants.
|
|
228
|
+
const areDirect = await miLocAll.evaluateAll((els, menuID) => {
|
|
229
|
+
return els.map(el => {
|
|
230
|
+
// Menu items are inside a menu by definition; verbatim from the original.
|
|
231
|
+
const itsMenu = el.closest('[role=menu], [role=menubar]');
|
|
232
|
+
return itsMenu.id && itsMenu.id === menuID;
|
|
233
|
+
});
|
|
234
|
+
}, menuID);
|
|
235
|
+
const miLocsAll = await miLocAll.all();
|
|
236
|
+
const miLocsDir = miLocsAll.filter((loc, index) => areDirect[index]);
|
|
237
|
+
// If there are at least 2 of them:
|
|
238
|
+
if (miLocsDir.length > 1) {
|
|
239
|
+
// Ensure that the menu is collapsed.
|
|
240
|
+
await menuLoc.evaluate(element => {
|
|
241
|
+
// The boolean is coerced to 'false' at runtime; verbatim from the original.
|
|
242
|
+
element.setAttribute('aria-expanded', false);
|
|
243
|
+
});
|
|
244
|
+
// Focus the menu button and press the key that opens its menu from the top.
|
|
245
|
+
await mbLoc.press(extraData.orientation === 'horizontal' ? 'ArrowRight' : 'ArrowDown');
|
|
246
|
+
// If trial keys have been specified:
|
|
247
|
+
const trialKeys = [];
|
|
248
|
+
if (trialKeySpecs.length) {
|
|
249
|
+
// Implement them.
|
|
250
|
+
trialKeySpecs.forEach(spec => {
|
|
251
|
+
if (['Home', 'End'].includes(spec)) {
|
|
252
|
+
trialKeys.push(spec);
|
|
253
|
+
}
|
|
254
|
+
else if (spec === '-') {
|
|
255
|
+
trialKeys.push(extraData.orientation === 'horizontal' ? 'ArrowLeft' : 'ArrowUp');
|
|
256
|
+
}
|
|
257
|
+
else if (spec === '+') {
|
|
258
|
+
trialKeys.push(extraData.orientation === 'horizontal' ? 'ArrowRight' : 'ArrowDown');
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
// Otherwise, i.e. if trial keys have not been specified:
|
|
263
|
+
else {
|
|
264
|
+
// Randomly draw 12 keys from Home, End, and the applicable arrow keys.
|
|
265
|
+
const keys = ['Home', 'End'];
|
|
266
|
+
if (extraData.orientation === 'horizontal') {
|
|
267
|
+
keys.push('ArrowLeft', 'ArrowRight');
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
keys.push('ArrowUp', 'ArrowDown');
|
|
271
|
+
}
|
|
272
|
+
let trialKeyCount = 0;
|
|
273
|
+
while (trialKeyCount++ < 12) {
|
|
274
|
+
trialKeys.push(keys[Math.floor(4 * Math.random())]);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
// Add the list of trial keys to the result.
|
|
278
|
+
data.trialKeys = trialKeys;
|
|
279
|
+
let focIndex = 0;
|
|
280
|
+
// For each key in the trial:
|
|
281
|
+
for (const key of trialKeys) {
|
|
282
|
+
// Press it.
|
|
283
|
+
await page.keyboard.press(key);
|
|
284
|
+
// Get whether the expected focus occurred.
|
|
285
|
+
const focData = await focusSuccess(miLocsDir, focIndex, key, extraData.isPseudo);
|
|
286
|
+
// If so:
|
|
287
|
+
if (focData.isOK) {
|
|
288
|
+
// Update the index of the effective focus.
|
|
289
|
+
focIndex = focData.newFocIndex;
|
|
290
|
+
}
|
|
291
|
+
// Otherwise, i.e. if the expected focus did not occur:
|
|
292
|
+
else {
|
|
293
|
+
// Add to the totals.
|
|
294
|
+
totals[2]++;
|
|
295
|
+
// If itemization is required:
|
|
296
|
+
if (withItems) {
|
|
297
|
+
// Get the XPath of the menu button.
|
|
298
|
+
const mbXPath = await mbLoc.evaluate(element => window.getXPath(element));
|
|
299
|
+
// Add an instance to the standard instances.
|
|
300
|
+
standardInstances.push({
|
|
301
|
+
ruleID: 'buttonMenu',
|
|
302
|
+
what: `Menu responds nonstandardly to the ${key} key`,
|
|
303
|
+
ordinalSeverity: 2,
|
|
304
|
+
count: 1,
|
|
305
|
+
catalogIndex: (0, xPath_1.getXPathCatalogIndex)(report, mbXPath)
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
// Stop testing the menu button.
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// Otherwise, i.e. if the orientation and focus-management type were not obtained:
|
|
315
|
+
else {
|
|
316
|
+
// Report this.
|
|
317
|
+
console.log('ERROR: Menu orientation and focus-management type not obtained');
|
|
262
318
|
}
|
|
263
|
-
});
|
|
264
319
|
}
|
|
265
|
-
// Otherwise, i.e. if
|
|
320
|
+
// Otherwise, i.e. if the data were not obtained:
|
|
266
321
|
else {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
if (extraData.orientation === 'horizontal') {
|
|
270
|
-
keys.push('ArrowLeft', 'ArrowRight');
|
|
271
|
-
}
|
|
272
|
-
else {
|
|
273
|
-
keys.push('ArrowUp', 'ArrowDown');
|
|
274
|
-
}
|
|
275
|
-
let trialKeyCount = 0;
|
|
276
|
-
while (trialKeyCount++ < 12) {
|
|
277
|
-
trialKeys.push(keys[Math.floor(4 * Math.random())]);
|
|
278
|
-
}
|
|
322
|
+
// Report this.
|
|
323
|
+
console.log('ERROR: Menu data not obtained');
|
|
279
324
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
//
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
// Update the index of the effective focus.
|
|
292
|
-
focIndex = focData.newFocIndex;
|
|
293
|
-
}
|
|
294
|
-
// Otherwise, i.e. if the expected focus did not occur:
|
|
295
|
-
else {
|
|
296
|
-
// Add to the totals.
|
|
297
|
-
totals[2]++;
|
|
298
|
-
// If itemization is required:
|
|
299
|
-
if (withItems) {
|
|
300
|
-
// Get the XPath of the menu button.
|
|
301
|
-
const mbXPath = await mbLoc.evaluate(element => window.getXPath(element));
|
|
302
|
-
// Add an instance to the standard instances.
|
|
303
|
-
standardInstances.push({
|
|
325
|
+
}
|
|
326
|
+
// Otherwise, i.e. if it does not control exactly 1 menu:
|
|
327
|
+
else {
|
|
328
|
+
// Add to the totals.
|
|
329
|
+
totals[2]++;
|
|
330
|
+
// If itemization is required:
|
|
331
|
+
if (withItems) {
|
|
332
|
+
// Get the XPath of the menu button.
|
|
333
|
+
const mbXPath = await mbLoc.evaluate(element => window.getXPath(element));
|
|
334
|
+
// Add an instance to the standard instances.
|
|
335
|
+
standardInstances.push({
|
|
304
336
|
ruleID: 'buttonMenu',
|
|
305
|
-
what:
|
|
337
|
+
what: 'Menu button does not control exactly 1 menu',
|
|
306
338
|
ordinalSeverity: 2,
|
|
307
339
|
count: 1,
|
|
308
|
-
catalogIndex: getXPathCatalogIndex(report, mbXPath)
|
|
309
|
-
|
|
310
|
-
}
|
|
311
|
-
// Stop testing the menu button.
|
|
312
|
-
break;
|
|
313
|
-
}
|
|
340
|
+
catalogIndex: (0, xPath_1.getXPathCatalogIndex)(report, mbXPath)
|
|
341
|
+
});
|
|
314
342
|
}
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
// Otherwise, i.e. if the orientation and focus-management type were not obtained:
|
|
318
|
-
else {
|
|
319
|
-
// Report this.
|
|
320
|
-
console.log('ERROR: Menu orientation and focus-management type not obtained');
|
|
321
343
|
}
|
|
322
|
-
}
|
|
323
|
-
// Otherwise, i.e. if the data were not obtained:
|
|
324
|
-
else {
|
|
325
|
-
// Report this.
|
|
326
|
-
console.log('ERROR: Menu data not obtained');
|
|
327
|
-
}
|
|
328
344
|
}
|
|
329
|
-
//
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
totals[2]++;
|
|
333
|
-
// If itemization is required:
|
|
334
|
-
if (withItems) {
|
|
335
|
-
// Get the XPath of the menu button.
|
|
336
|
-
const mbXPath = await mbLoc.evaluate(element => window.getXPath(element));
|
|
337
|
-
// Add an instance to the standard instances.
|
|
345
|
+
// If itemization is not required and there are any instances:
|
|
346
|
+
if (!withItems && totals[2]) {
|
|
347
|
+
// Add a summary instance to the result.
|
|
338
348
|
standardInstances.push({
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
catalogIndex: getXPathCatalogIndex(report, mbXPath)
|
|
349
|
+
ruleID: 'buttonMenu',
|
|
350
|
+
what: 'Menu buttons and menus behave nonstandardly',
|
|
351
|
+
count: totals[2],
|
|
352
|
+
ordinalSeverity: 2
|
|
344
353
|
});
|
|
345
|
-
}
|
|
346
354
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
ruleID: 'buttonMenu',
|
|
353
|
-
what: 'Menu buttons and menus behave nonstandardly',
|
|
354
|
-
count: totals[2],
|
|
355
|
-
ordinalSeverity: 2
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
return {
|
|
359
|
-
data,
|
|
360
|
-
totals,
|
|
361
|
-
standardInstances
|
|
362
|
-
};
|
|
355
|
+
return {
|
|
356
|
+
data,
|
|
357
|
+
totals,
|
|
358
|
+
standardInstances
|
|
359
|
+
};
|
|
363
360
|
};
|
|
361
|
+
exports.reporter = reporter;
|