testaro 78.0.6 → 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.
Files changed (361) hide show
  1. package/.gitattributes +94 -0
  2. package/.github/workflows/ci.yml +58 -0
  3. package/.github/workflows/publish.yml +49 -0
  4. package/.github/workflows/typescript.yml +35 -0
  5. package/AGENTS.md +2 -2
  6. package/CLAUDE.md +25 -19
  7. package/CONTAINERS.md +10 -6
  8. package/CONTRIBUTING.md +29 -3
  9. package/Dockerfile +1 -1
  10. package/README.md +75 -20
  11. package/UPGRADES.md +4 -0
  12. package/actSpecs-doc.md +13 -1
  13. package/actSpecs.js +29 -5
  14. package/call.js +6 -5
  15. package/docker-compose.yml +8 -2
  16. package/docs/checkpoint-scanning.md +199 -0
  17. package/docs/standard-result-outcome.md +165 -0
  18. package/env.example +44 -10
  19. package/eslint.config.mjs +101 -0
  20. package/netWatch.js +373 -222
  21. package/package.json +46 -31
  22. package/pour/README.md +47 -0
  23. package/pour/pour.min.js +8 -0
  24. package/procs/actDo.js +808 -0
  25. package/procs/catalog.d.ts +17 -0
  26. package/procs/catalog.js +313 -221
  27. package/procs/catalog.ts +398 -0
  28. package/procs/checkpoint.js +110 -0
  29. package/procs/config.d.ts +35 -0
  30. package/procs/config.js +63 -0
  31. package/procs/dateTime.js +2 -1
  32. package/procs/doActs.js +442 -849
  33. package/procs/doTestAct.js +27 -121
  34. package/procs/flow.js +221 -0
  35. package/procs/generateRuleRegistry.js +94 -0
  36. package/procs/getSource.d.ts +26 -0
  37. package/procs/getSource.js +1 -0
  38. package/procs/job.js +116 -1
  39. package/procs/launch.d.ts +40 -0
  40. package/procs/launch.js +239 -108
  41. package/procs/nu.d.ts +48 -0
  42. package/procs/nu.js +1 -0
  43. package/procs/scope.js +196 -0
  44. package/procs/shoot.d.ts +33 -0
  45. package/procs/shoot.js +3 -1
  46. package/procs/standard.d.ts +18 -0
  47. package/procs/standard.js +83 -0
  48. package/procs/standard.ts +126 -0
  49. package/procs/testAct.js +145 -0
  50. package/procs/testaro.d.ts +20 -0
  51. package/procs/testaro.js +237 -189
  52. package/procs/testaro.ts +321 -0
  53. package/procs/userPath.js +126 -0
  54. package/procs/xPath.d.ts +4 -0
  55. package/procs/xPath.js +82 -64
  56. package/procs/xPath.ts +106 -0
  57. package/procs/xPathScript.d.ts +6 -0
  58. package/procs/xPathScript.js +70 -0
  59. package/run.js +3 -2
  60. package/surea11y/README.md +44 -0
  61. package/surea11y/surea11y.browser.js +14 -0
  62. package/testaro/adbID.d.ts +3 -0
  63. package/testaro/adbID.js +39 -41
  64. package/testaro/adbID.ts +66 -0
  65. package/testaro/allCapStyle.d.ts +3 -0
  66. package/testaro/allCapStyle.js +32 -34
  67. package/testaro/allCapStyle.ts +55 -0
  68. package/testaro/allCaps.d.ts +16 -0
  69. package/testaro/allCaps.js +179 -151
  70. package/testaro/allCaps.ts +228 -0
  71. package/testaro/allHidden.d.ts +13 -0
  72. package/testaro/allHidden.js +30 -30
  73. package/testaro/allHidden.ts +50 -0
  74. package/testaro/allSlanted.d.ts +3 -0
  75. package/testaro/allSlanted.js +31 -33
  76. package/testaro/allSlanted.ts +54 -0
  77. package/testaro/altScheme.d.ts +3 -0
  78. package/testaro/altScheme.js +28 -30
  79. package/testaro/altScheme.ts +50 -0
  80. package/testaro/attVal.d.ts +3 -0
  81. package/testaro/attVal.js +21 -21
  82. package/testaro/attVal.ts +52 -0
  83. package/testaro/autocomplete.d.ts +3 -0
  84. package/testaro/autocomplete.js +60 -75
  85. package/testaro/autocomplete.ts +101 -0
  86. package/testaro/bulk.d.ts +13 -0
  87. package/testaro/bulk.js +33 -33
  88. package/testaro/bulk.ts +55 -0
  89. package/testaro/buttonMenu.d.ts +9 -0
  90. package/testaro/buttonMenu.js +318 -319
  91. package/testaro/buttonMenu.ts +391 -0
  92. package/testaro/captionLoc.d.ts +3 -0
  93. package/testaro/captionLoc.js +18 -20
  94. package/testaro/captionLoc.ts +40 -0
  95. package/testaro/datalistRef.d.ts +3 -0
  96. package/testaro/datalistRef.js +34 -36
  97. package/testaro/datalistRef.ts +55 -0
  98. package/testaro/distortion.d.ts +3 -0
  99. package/testaro/distortion.js +58 -26
  100. package/testaro/distortion.ts +81 -0
  101. package/testaro/docType.d.ts +15 -0
  102. package/testaro/docType.js +26 -25
  103. package/testaro/docType.ts +45 -0
  104. package/testaro/dupAtt.d.ts +16 -0
  105. package/testaro/dupAtt.js +114 -104
  106. package/testaro/dupAtt.ts +144 -0
  107. package/testaro/elements.d.ts +6 -0
  108. package/testaro/elements.js +153 -153
  109. package/testaro/elements.ts +215 -0
  110. package/testaro/embAc.d.ts +3 -0
  111. package/testaro/embAc.js +20 -20
  112. package/testaro/embAc.ts +40 -0
  113. package/testaro/focAll.d.ts +13 -0
  114. package/testaro/focAll.js +186 -191
  115. package/testaro/focAll.ts +217 -0
  116. package/testaro/focAndOp.d.ts +3 -0
  117. package/testaro/focAndOp.js +101 -104
  118. package/testaro/focAndOp.ts +128 -0
  119. package/testaro/focInd.d.ts +3 -0
  120. package/testaro/focInd.js +65 -66
  121. package/testaro/focInd.ts +96 -0
  122. package/testaro/focVis.d.ts +3 -0
  123. package/testaro/focVis.js +29 -30
  124. package/testaro/focVis.ts +52 -0
  125. package/testaro/headEl.d.ts +10 -0
  126. package/testaro/headEl.js +62 -62
  127. package/testaro/headEl.ts +82 -0
  128. package/testaro/headingAmb.d.ts +3 -0
  129. package/testaro/headingAmb.js +55 -63
  130. package/testaro/headingAmb.ts +72 -0
  131. package/testaro/hovInd.d.ts +12 -0
  132. package/testaro/hovInd.js +164 -130
  133. package/testaro/hovInd.ts +199 -0
  134. package/testaro/hover.d.ts +3 -0
  135. package/testaro/hover.js +156 -126
  136. package/testaro/hover.ts +154 -0
  137. package/testaro/hr.d.ts +3 -0
  138. package/testaro/hr.js +15 -17
  139. package/testaro/hr.ts +36 -0
  140. package/testaro/imageLink.d.ts +3 -0
  141. package/testaro/imageLink.js +18 -20
  142. package/testaro/imageLink.ts +42 -0
  143. package/testaro/labClash.d.ts +3 -0
  144. package/testaro/labClash.js +32 -33
  145. package/testaro/labClash.ts +54 -0
  146. package/testaro/legendLoc.d.ts +3 -0
  147. package/testaro/legendLoc.js +18 -20
  148. package/testaro/legendLoc.ts +42 -0
  149. package/testaro/lineHeight.d.ts +3 -0
  150. package/testaro/lineHeight.js +44 -48
  151. package/testaro/lineHeight.ts +70 -0
  152. package/testaro/linkAmb.d.ts +7 -0
  153. package/testaro/linkAmb.js +80 -80
  154. package/testaro/linkAmb.ts +105 -0
  155. package/testaro/linkExt.d.ts +3 -0
  156. package/testaro/linkExt.js +14 -16
  157. package/testaro/linkExt.ts +35 -0
  158. package/testaro/linkOldAtt.d.ts +3 -0
  159. package/testaro/linkOldAtt.js +26 -28
  160. package/testaro/linkOldAtt.ts +48 -0
  161. package/testaro/linkTo.d.ts +3 -0
  162. package/testaro/linkTo.js +23 -22
  163. package/testaro/linkTo.ts +43 -0
  164. package/testaro/linkUl.d.ts +3 -0
  165. package/testaro/linkUl.js +31 -34
  166. package/testaro/linkUl.ts +54 -0
  167. package/testaro/miniText.d.ts +3 -0
  168. package/testaro/miniText.js +42 -44
  169. package/testaro/miniText.ts +68 -0
  170. package/testaro/motion.d.ts +10 -0
  171. package/testaro/motion.js +93 -96
  172. package/testaro/motion.ts +125 -0
  173. package/testaro/nonTable.d.ts +3 -0
  174. package/testaro/nonTable.js +40 -45
  175. package/testaro/nonTable.ts +66 -0
  176. package/testaro/optRoleSel.d.ts +3 -0
  177. package/testaro/optRoleSel.js +17 -19
  178. package/testaro/optRoleSel.ts +41 -0
  179. package/testaro/phOnly.d.ts +3 -0
  180. package/testaro/phOnly.js +19 -21
  181. package/testaro/phOnly.ts +43 -0
  182. package/testaro/pseudoP.d.ts +3 -0
  183. package/testaro/pseudoP.js +37 -38
  184. package/testaro/pseudoP.ts +59 -0
  185. package/testaro/radioSet.d.ts +3 -0
  186. package/testaro/radioSet.js +58 -59
  187. package/testaro/radioSet.ts +79 -0
  188. package/testaro/registry.d.ts +63 -0
  189. package/testaro/registry.js +67 -0
  190. package/testaro/registry.ts +141 -0
  191. package/testaro/role.d.ts +3 -0
  192. package/testaro/role.js +28 -29
  193. package/testaro/role.ts +53 -0
  194. package/testaro/secHeading.d.ts +3 -0
  195. package/testaro/secHeading.js +31 -33
  196. package/testaro/secHeading.ts +53 -0
  197. package/testaro/styleDiff.d.ts +25 -0
  198. package/testaro/styleDiff.js +249 -252
  199. package/testaro/styleDiff.ts +303 -0
  200. package/testaro/tabNav.d.ts +33 -0
  201. package/testaro/tabNav.js +273 -342
  202. package/testaro/tabNav.ts +454 -0
  203. package/testaro/targetsNear.d.ts +9 -0
  204. package/testaro/targetsNear.js +131 -132
  205. package/testaro/targetsNear.ts +160 -0
  206. package/testaro/textNodes.d.ts +6 -0
  207. package/testaro/textNodes.js +139 -135
  208. package/testaro/textNodes.ts +185 -0
  209. package/testaro/textSem.d.ts +3 -0
  210. package/testaro/textSem.js +26 -28
  211. package/testaro/textSem.ts +47 -0
  212. package/testaro/title.d.ts +9 -0
  213. package/testaro/title.js +16 -13
  214. package/testaro/title.ts +31 -0
  215. package/testaro/titledEl.d.ts +3 -0
  216. package/testaro/titledEl.js +16 -18
  217. package/testaro/titledEl.ts +38 -0
  218. package/testaro/zIndex.d.ts +3 -0
  219. package/testaro/zIndex.js +20 -22
  220. package/testaro/zIndex.ts +42 -0
  221. package/tests/alfa.d.ts +45 -0
  222. package/tests/alfa.js +139 -141
  223. package/tests/alfa.ts +214 -0
  224. package/tests/aslint.d.ts +33 -0
  225. package/tests/aslint.js +273 -249
  226. package/tests/aslint.ts +301 -0
  227. package/tests/axe.d.ts +27 -0
  228. package/tests/axe.js +200 -200
  229. package/tests/axe.ts +277 -0
  230. package/tests/ed11y.d.ts +28 -0
  231. package/tests/ed11y.js +142 -99
  232. package/tests/ed11y.ts +178 -0
  233. package/tests/htmlcs.d.ts +21 -0
  234. package/tests/htmlcs.js +175 -140
  235. package/tests/htmlcs.ts +181 -0
  236. package/tests/ibm.d.ts +52 -0
  237. package/tests/ibm.js +165 -166
  238. package/tests/ibm.ts +251 -0
  239. package/tests/nuVal.d.ts +13 -0
  240. package/tests/nuVal.js +107 -112
  241. package/tests/nuVal.ts +145 -0
  242. package/tests/nuVnu.d.ts +15 -0
  243. package/tests/nuVnu.js +142 -111
  244. package/tests/nuVnu.ts +144 -0
  245. package/tests/pour.d.ts +31 -0
  246. package/tests/pour.js +242 -0
  247. package/tests/pour.ts +273 -0
  248. package/tests/qualWeb.d.ts +39 -0
  249. package/tests/qualWeb.js +303 -272
  250. package/tests/qualWeb.ts +415 -0
  251. package/tests/surea11y.d.ts +33 -0
  252. package/tests/surea11y.js +288 -0
  253. package/tests/surea11y.ts +334 -0
  254. package/tests/testaro.d.ts +25 -0
  255. package/tests/testaro.js +746 -652
  256. package/tests/testaro.ts +862 -0
  257. package/tests/wave.d.ts +46 -0
  258. package/tests/wave.js +167 -177
  259. package/tests/wave.ts +252 -0
  260. package/tsconfig.json +17 -0
  261. package/types.d.ts +243 -0
  262. package/types.js +10 -0
  263. package/types.ts +376 -0
  264. package/validation/act/README.md +46 -0
  265. package/validation/act/capture.js +424 -0
  266. package/validation/act/chromium-issue-draft.md +66 -0
  267. package/validation/act/fp-triage-2026-08-22.md +86 -0
  268. package/validation/act/isolation-notes.md +159 -0
  269. package/validation/act/playwright-issue-draft.md +73 -0
  270. package/validation/act/propose-mappings.js +0 -0
  271. package/validation/act/repro-cdp-raw.js +105 -0
  272. package/validation/act/repro-metarefresh.js +65 -0
  273. package/validation/act/score.js +184 -0
  274. package/validation/act/stage3a-stress-report.md +69 -0
  275. package/validation/act/stage3b-mapping-proposals.md +94 -0
  276. package/validation/act/stage3b-triage-draft.md +138 -0
  277. package/validation/act/surea11y-track-a-2026-09-01.md +50 -0
  278. package/validation/executors/netWatch.js +180 -90
  279. package/validation/executors/test.js +17 -2
  280. package/validation/executors/tests.js +118 -10
  281. package/validation/jobs/reports/raw/260901T1000-surea11y-validation.json +964 -0
  282. package/validation/jobs/todo/240101T1200-simple-example.json +14 -6
  283. package/validation/jobs/todo/240101T1300-shoot-example.json +2 -1
  284. package/validation/jobs/todo/260821T1900-pour-validation.json +45 -0
  285. package/validation/jobs/todo/260901T1000-surea11y-validation.json +45 -0
  286. package/validation/knownFailures.json +1 -0
  287. package/validation/tests/jobProperties/adbID.json +27 -2
  288. package/validation/tests/jobProperties/{focOp.json → allCapStyle.json} +56 -53
  289. package/validation/tests/jobProperties/allCaps.json +25 -0
  290. package/validation/tests/jobProperties/allHidden.json +133 -13
  291. package/validation/tests/jobProperties/allSlanted.json +3 -3
  292. package/validation/tests/jobProperties/altScheme.json +23 -8
  293. package/validation/tests/jobProperties/attVal.json +57 -57
  294. package/validation/tests/jobProperties/autocomplete.json +11 -1
  295. package/validation/tests/jobProperties/bulk.json +6 -1
  296. package/validation/tests/jobProperties/buttonMenu.json +63 -42
  297. package/validation/tests/jobProperties/captionLoc.json +1 -6
  298. package/validation/tests/jobProperties/checkpoint-browser.json +401 -0
  299. package/validation/tests/jobProperties/checkpoint-page.json +397 -0
  300. package/validation/tests/jobProperties/checkpoint.json +395 -0
  301. package/validation/tests/jobProperties/datalistRef.json +20 -5
  302. package/validation/tests/jobProperties/distortion.json +28 -3
  303. package/validation/tests/jobProperties/docType.json +2 -2
  304. package/validation/tests/jobProperties/dupAtt.json +48 -33
  305. package/validation/tests/jobProperties/elements.json +28 -28
  306. package/validation/tests/jobProperties/embAc.json +36 -31
  307. package/validation/tests/jobProperties/focAndOp.json +284 -0
  308. package/validation/tests/jobProperties/focInd.json +34 -34
  309. package/validation/tests/jobProperties/focVis.json +1 -1
  310. package/validation/tests/jobProperties/hover.json +39 -37
  311. package/validation/tests/jobProperties/hr.json +13 -3
  312. package/validation/tests/jobProperties/imageLink.json +0 -5
  313. package/validation/tests/jobProperties/labClash.json +68 -33
  314. package/validation/tests/jobProperties/legendLoc.json +1 -6
  315. package/validation/tests/jobProperties/lineHeight.json +2 -2
  316. package/validation/tests/jobProperties/linkAmb.json +13 -18
  317. package/validation/tests/jobProperties/linkExt.json +1 -1
  318. package/validation/tests/jobProperties/linkOldAtt.json +12 -2
  319. package/validation/tests/jobProperties/linkTo.json +1 -1
  320. package/validation/tests/jobProperties/linkUl.json +65 -65
  321. package/validation/tests/jobProperties/miniText.json +7 -2
  322. package/validation/tests/jobProperties/motion.json +4 -50
  323. package/validation/tests/jobProperties/nonTable.json +48 -3
  324. package/validation/tests/jobProperties/optRoleSel.json +12 -2
  325. package/validation/tests/jobProperties/phOnly.json +6 -16
  326. package/validation/tests/jobProperties/pseudoP.json +17 -2
  327. package/validation/tests/jobProperties/radioSet.json +30 -30
  328. package/validation/tests/jobProperties/role.json +25 -5
  329. package/validation/tests/jobProperties/secHeading.json +26 -21
  330. package/validation/tests/jobProperties/styleDiff.json +35 -5
  331. package/validation/tests/jobProperties/tabNav.json +3 -1
  332. package/validation/tests/jobProperties/targetsNear.json +237 -0
  333. package/validation/tests/jobProperties/textNodes.json +29 -29
  334. package/validation/tests/jobProperties/textSem.json +26 -1
  335. package/validation/tests/jobProperties/title.json +12 -2
  336. package/validation/tests/jobProperties/titledEl.json +39 -9
  337. package/validation/tests/jobProperties/userPath.json +317 -0
  338. package/validation/tests/jobProperties/zIndex.json +40 -35
  339. package/validation/tests/targets/allCapStyle/index.html +26 -0
  340. package/validation/tests/targets/checkpoint/index.html +38 -0
  341. package/validation/tests/targets/datalistRef/index.html +1 -1
  342. package/validation/tests/targets/focAndOp/bad.html +29 -0
  343. package/validation/tests/targets/{focOp → focAndOp}/good.html +3 -1
  344. package/validation/tests/targets/focInd/bad.html +2 -1
  345. package/validation/tests/targets/headEl/index.html +10 -1
  346. package/validation/tests/targets/{targetSmall → targetsNear}/index.html +15 -1
  347. package/validation/tests/targets/userPath/index.html +42 -0
  348. package/validation/validateTest.js +62 -10
  349. package/.claude/settings.local.json +0 -11
  350. package/.eslintrc.json +0 -41
  351. package/htmlcs/.eslintrc.json +0 -67
  352. package/memory/MEMORY.md +0 -3
  353. package/memory/project_validation_pause.md +0 -10
  354. package/validation/tests/jobProperties/linkTitle.json +0 -127
  355. package/validation/tests/jobProperties/opFoc.json +0 -164
  356. package/validation/tests/jobProperties/targetSmall.json +0 -152
  357. package/validation/tests/jobProperties/targetTiny.json +0 -142
  358. package/validation/tests/targets/focOp/bad.html +0 -25
  359. package/validation/tests/targets/linkTitle/index.html +0 -24
  360. package/validation/tests/targets/opFoc/bad.html +0 -26
  361. package/validation/tests/targets/opFoc/good.html +0 -23
package/procs/testaro.js CHANGED
@@ -1,214 +1,262 @@
1
+ "use strict";
1
2
  /*
2
3
  © 2023–2024 CVS Health and/or one of its affiliates. All rights reserved.
4
+ © 2026 Jeff Witt.
3
5
  © 2025–2026 Jonathan Robert Pool.
4
6
 
5
7
  Licensed under the MIT License. See LICENSE file at the project root or https://opensource.org/license/mit/ for details.
6
8
 
7
9
  SPDX-License-Identifier: MIT
8
10
  */
9
-
10
- /*
11
- testaro
12
- Utilities for Testaro tests.
13
- */
14
-
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.getBasicResult = exports.doTest = void 0;
15
13
  // ########## IMPORTS
16
-
17
14
  // Function to get a catalog index from an XPath.
18
- const {getXPathCatalogIndex} = require('./xPath');
19
-
15
+ const xPath_1 = require("./xPath");
16
+ // Function to build a standard instance.
17
+ const standard_1 = require("./standard");
20
18
  // ########## FUNCTIONS
21
-
19
+ // Returns a standard instance, leaving the outcome unset if the violation did not specify one, so
20
+ // that the testaro tool can apply the rule's default outcome.
21
+ const getRuleInstance = (spec) => {
22
+ const instance = (0, standard_1.getInstance)(spec);
23
+ if (!spec.outcome) {
24
+ instance.outcome = undefined;
25
+ }
26
+ return instance;
27
+ };
22
28
  // Tests for a testaro rule.
23
- exports.doTest = async (
24
- page,
25
- report,
26
- withItems,
27
- ruleID,
28
- candidateSelector,
29
- whats,
30
- severity,
31
- getBadWhatString
32
- ) => {
33
- const ruleData = await page.evaluate(async args => {
34
- // Get the arguments.
35
- const [
36
- withItems,
37
- candidateSelector,
38
- severity,
39
- getBadWhatString
40
- ] = args;
41
- // Get all violator candidates.
42
- const candidates = document.querySelectorAll(candidateSelector);
43
- let violationCount = 0;
44
- // Initialize proto-instances.
45
- const protoInstances = [];
46
- // Parse the supplied string to get the classifier.
47
- const getBadWhat = eval(`(${getBadWhatString})`);
48
- // Initialize data on the rule.
49
- let data = {};
50
- const totals = [0, 0, 0, 0];
51
- // For each candidate:
52
- for (const candidate of candidates) {
53
- // Classify it as and get a violation description if a violator or undefined if not.
54
- const violationWhat = await getBadWhat(candidate);
55
- // If the candidate violates the rule:
56
- if (violationWhat) {
57
- // Increment the violation count.
58
- violationCount++;
59
- let ruleWhat;
60
- const violationType = typeof violationWhat;
61
- // If data on the violation were provided (unusual):
62
- if (violationType === 'object') {
63
- // Get the description and add the data to the rule data.
64
- ruleWhat = violationWhat.description;
65
- data[violationCount - 1] = violationWhat.data;
29
+ const doTest = async (page, report, withItems, ruleID, candidateSelector, whats, severity, getBadWhatString) => {
30
+ // The subtree roots the rule is restricted to, if the test act has scope changed and the
31
+ // testaro tool judged the rule element-local (set per rule by tests/testaro.ts).
32
+ const scopeRoots = report.ruleScopeRoots ?? null;
33
+ const ruleData = await page.evaluate(async (args) => {
34
+ // Get the arguments.
35
+ const [withItems, candidateSelector, severity, getBadWhatString, scopeRoots] = args;
36
+ // Get all violator candidates, within the scope roots if any.
37
+ let candidates = Array.from(document.querySelectorAll(candidateSelector));
38
+ if (scopeRoots && scopeRoots.length) {
39
+ const roots = scopeRoots
40
+ .map(selector => {
41
+ try {
42
+ return document.querySelector(selector);
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ })
48
+ .filter((root) => Boolean(root));
49
+ candidates = candidates.filter(candidate => roots.some(root => root.contains(candidate)));
66
50
  }
67
- // Otherwise, i.e. if only a description of the violation was provided:
68
- else if (violationType === 'string') {
69
- // Get it.
70
- ruleWhat = violationWhat;
51
+ let violationCount = 0;
52
+ // Initialize proto-instances.
53
+ const protoInstances = [];
54
+ // Initialize counts of cantTell violations by ordinal severity, for summary instances.
55
+ const cantTellTotals = [0, 0, 0, 0];
56
+ /*
57
+ Parse the supplied string to get the classifier. The predicate travels as
58
+ source text (serialized with toString() by the rule module) because it
59
+ must run inside the page; this cast is the single point where its type is
60
+ asserted rather than checked (issue #73, RFC decision 4). The eval input
61
+ is first-party rule-module source from this repository, never target-page
62
+ or user data; replacing the eval pipeline with a bundled artifact is the
63
+ Phase 3 reassessment recorded on issue #73.
64
+ */
65
+ const getBadWhat = eval(`(${getBadWhatString})`);
66
+ // Initialize data on the rule.
67
+ let data = {};
68
+ const totals = [0, 0, 0, 0];
69
+ // For each candidate:
70
+ for (const candidate of candidates) {
71
+ // Classify it as and get a violation description if a violator or undefined if not.
72
+ const violationWhat = await getBadWhat(candidate);
73
+ // If the candidate violates the rule:
74
+ if (violationWhat) {
75
+ // Increment the violation count.
76
+ violationCount++;
77
+ let ruleWhat;
78
+ const violationType = typeof violationWhat;
79
+ // If data on the violation were provided (unusual):
80
+ if (violationType === 'object') {
81
+ // Get the description and add the data to the rule data.
82
+ ruleWhat = violationWhat.description;
83
+ data[violationCount - 1] = violationWhat.data;
84
+ }
85
+ // Otherwise, i.e. if only a description of the violation was provided:
86
+ else if (violationType === 'string') {
87
+ // Get it.
88
+ ruleWhat = violationWhat;
89
+ }
90
+ let ordinalSeverity = severity;
91
+ let outcome;
92
+ // A predicate that returns a truthy non-object non-string would make this throw,
93
+ // exactly as in the JavaScript original.
94
+ // If this violation has a custom severity or outcome prefix (e.g. 2:, 2?:, or ?:):
95
+ const prefixMatch = ruleWhat.match(/^([0-3])?(\?)?:/);
96
+ if (prefixMatch) {
97
+ // If the prefix has a severity, get it.
98
+ if (prefixMatch[1]) {
99
+ ordinalSeverity = Number(prefixMatch[1]);
100
+ }
101
+ // If the prefix marks the violation as uncertain, record this.
102
+ if (prefixMatch[2]) {
103
+ outcome = 'cantTell';
104
+ cantTellTotals[ordinalSeverity]++;
105
+ }
106
+ // Remove the prefix from the violation description.
107
+ ruleWhat = ruleWhat.slice(prefixMatch[0].length);
108
+ }
109
+ // Increment the applicable rule-violation total.
110
+ totals[ordinalSeverity]++;
111
+ // If itemization is required:
112
+ if (withItems) {
113
+ const protoInstance = {
114
+ what: ruleWhat,
115
+ ordinalSeverity,
116
+ outcome,
117
+ xPath: window.getXPath(candidate) ?? '/html'
118
+ };
119
+ // Add a proto-instance to the proto-instances.
120
+ protoInstances.push(protoInstance);
121
+ }
122
+ }
71
123
  }
72
- const ruleWhatStart = ruleWhat.slice(0, 2);
73
- let ordinalSeverity = severity;
74
- // If this violation has a custom severity:
75
- if (/[0-3]:/.test(ruleWhatStart)) {
76
- // Get it.
77
- ordinalSeverity = Number(ruleWhat[0]);
78
- // Remove it from the violation description.
79
- ruleWhat = ruleWhat.slice(2);
80
- }
81
- // Increment the applicable rule-violation total.
82
- totals[ordinalSeverity]++;
83
- // If itemization is required:
84
- if (withItems) {
85
- const protoInstance = {
86
- what: ruleWhat,
87
- ordinalSeverity,
88
- xPath: window.getXPath(candidate) ?? '/html'
89
- };
90
- // Add a proto-instance to the proto-instances.
91
- protoInstances.push(protoInstance);
92
- }
93
- }
94
- }
95
- return {
96
- data,
97
- totals,
98
- protoInstances
124
+ return {
125
+ data,
126
+ totals,
127
+ cantTellTotals,
128
+ protoInstances
129
+ };
130
+ }, [
131
+ withItems,
132
+ candidateSelector,
133
+ severity,
134
+ getBadWhatString,
135
+ scopeRoots
136
+ ]);
137
+ // Initialize the standard instances. Any instance without an outcome gets the rule's default
138
+ // outcome from the testaro tool.
139
+ let standardInstances = [];
140
+ const { data, totals, cantTellTotals, protoInstances } = ruleData;
141
+ // If itemization is required:
142
+ if (withItems) {
143
+ // For each proto-instance:
144
+ protoInstances.forEach(protoInstance => {
145
+ const { what, ordinalSeverity, outcome, xPath } = protoInstance;
146
+ // Add a standard instance to the standard instances.
147
+ standardInstances.push(getRuleInstance({
148
+ ruleID,
149
+ what,
150
+ ordinalSeverity,
151
+ outcome,
152
+ catalogIndex: xPath ? (0, xPath_1.getXPathCatalogIndex)(report, xPath) : undefined
153
+ }));
154
+ });
99
155
  }
100
- }, [
101
- withItems,
102
- candidateSelector,
103
- severity,
104
- getBadWhatString
105
- ]
106
- );
107
- // Initialize the standard instances.
108
- let standardInstances = [];
109
- const {data, totals, protoInstances} = ruleData;
110
- // If itemization is required:
111
- if (withItems) {
112
- // For each proto-instance:
113
- protoInstances.forEach(protoInstance => {
114
- const {what, ordinalSeverity, xPath} = protoInstance;
115
- // Initialize a standard instance.
116
- const standardInstance = {
117
- ruleID,
118
- what,
119
- ordinalSeverity,
120
- count: 1
121
- };
122
- // If the proto-instance includes an XPath:
123
- if (xPath) {
124
- // Add the catalog index to the standard instance.
125
- standardInstance.catalogIndex = getXPathCatalogIndex(report, xPath);
126
- }
127
- // Add the standard instance to the standard instances.
128
- standardInstances.push(standardInstance);
129
- });
130
- }
131
- // Otherwise, i.e. if itemization is not required:
132
- else {
133
- // For each ordinal severity:
134
- for (const index in totals) {
135
- // If there were any violations at that severity:
136
- if (totals[index]) {
137
- // Add a summary standard instance to the standard instances.
138
- standardInstances.push({
139
- ruleID,
140
- what: whats,
141
- ordinalSeverity: index,
142
- count: totals[index]
156
+ // Otherwise, i.e. if itemization is not required:
157
+ else {
158
+ // For each ordinal severity:
159
+ totals.forEach((total, ordinalSeverity) => {
160
+ const cantTellTotal = cantTellTotals[ordinalSeverity];
161
+ // If there were any asserted violations at that severity:
162
+ if (total - cantTellTotal) {
163
+ // Add a summary standard instance to the standard instances.
164
+ standardInstances.push(getRuleInstance({
165
+ ruleID,
166
+ what: whats,
167
+ ordinalSeverity,
168
+ count: total - cantTellTotal
169
+ }));
170
+ }
171
+ // If there were any uncertain violations at that severity:
172
+ if (cantTellTotal) {
173
+ // Add a summary standard instance for them.
174
+ standardInstances.push(getRuleInstance({
175
+ ruleID,
176
+ what: whats,
177
+ ordinalSeverity,
178
+ outcome: 'cantTell',
179
+ count: cantTellTotal
180
+ }));
181
+ }
143
182
  });
144
- }
145
183
  }
146
- }
147
- // Return the data, totals, and standard instances.
148
- return {
149
- data,
150
- totals,
151
- standardInstances
152
- };
184
+ // Return the data, totals, and standard instances.
185
+ return {
186
+ data,
187
+ totals: totals,
188
+ standardInstances
189
+ };
153
190
  };
191
+ exports.doTest = doTest;
154
192
  // Adds a catalog index or, if necessary, an XPath to a proto-instance.
155
193
  const addCatalogIndex = async (protoInstance, locator, report) => {
156
- // Get the XPath of the element referenced by the locator.
157
- const xPath = await locator.evaluate(element => window.getXPath(element) ?? '/html');
158
- // Add a catalog index to the proto-instance.
159
- protoInstance.catalogIndex = getXPathCatalogIndex(report, xPath);
160
- // Return the proto-instance with any modification.
161
- return protoInstance;
194
+ // Get the XPath of the element referenced by the locator.
195
+ const xPath = await locator.evaluate(element => window.getXPath(element) ?? '/html');
196
+ // Add a catalog index to the proto-instance.
197
+ protoInstance.catalogIndex = (0, xPath_1.getXPathCatalogIndex)(report, xPath);
198
+ // Return the proto-instance with any modification.
199
+ return protoInstance;
162
200
  };
163
201
  // Tests for a doTest-ineligible Testaro rule.
164
- exports.getBasicResult = async (
165
- report, withItems, ruleID, ordinalSeverity, whats, data, violations
166
- ) => {
167
- // If the test was prevented:
168
- if (data.prevented) {
169
- // Return this.
202
+ const getBasicResult = async (report, withItems, ruleID, ordinalSeverity, whats, data, violations) => {
203
+ // If the test was prevented:
204
+ if (data.prevented) {
205
+ // Return this.
206
+ return {
207
+ data,
208
+ totals: [0, 0, 0, 0],
209
+ standardInstances: []
210
+ };
211
+ }
212
+ // Otherwise, i.e. if the test was not prevented:
213
+ const totals = [0, 0, 0, 0];
214
+ totals[ordinalSeverity] = violations.length;
215
+ const standardInstances = [];
216
+ // If itemization is required:
217
+ if (withItems) {
218
+ // For each violation:
219
+ for (const violation of violations) {
220
+ const { loc, what, outcome, uncertainty, needed } = violation;
221
+ // Initialize a standard instance.
222
+ const protoInstance = getRuleInstance({
223
+ ruleID,
224
+ what,
225
+ ordinalSeverity,
226
+ outcome,
227
+ uncertainty,
228
+ needed
229
+ });
230
+ // Add a catalog index to it, awaited so the index is present before the
231
+ // report can be serialized (issue #100).
232
+ await addCatalogIndex(protoInstance, loc, report);
233
+ // Add the standard instance to the standard instances.
234
+ standardInstances.push(protoInstance);
235
+ }
236
+ }
237
+ // Otherwise, i.e. if itemization is not required:
238
+ else {
239
+ // Add a summary instance per outcome to the instances.
240
+ const outcomeCounts = {};
241
+ violations.forEach(violation => {
242
+ const outcome = violation.outcome || 'failed';
243
+ outcomeCounts[outcome] = (outcomeCounts[outcome] || 0) + 1;
244
+ });
245
+ Object.keys(outcomeCounts).forEach(outcome => {
246
+ standardInstances.push(getRuleInstance({
247
+ ruleID,
248
+ what: whats,
249
+ ordinalSeverity,
250
+ outcome,
251
+ count: outcomeCounts[outcome]
252
+ }));
253
+ });
254
+ }
255
+ // Return the result.
170
256
  return {
171
- data,
172
- totals: [0, 0, 0, 0],
173
- standardInstances: []
257
+ data,
258
+ totals,
259
+ standardInstances
174
260
  };
175
- }
176
- // Otherwise, i.e. if the test was not prevented:
177
- const totals = [0, 0, 0, 0];
178
- totals[ordinalSeverity] = violations.length;
179
- const standardInstances = [];
180
- // If itemization is required:
181
- if (withItems) {
182
- // For each violation:
183
- for (const violation of violations) {
184
- const {loc, what} = violation;
185
- // Initialize a standard instance.
186
- const protoInstance = {
187
- ruleID,
188
- what,
189
- ordinalSeverity,
190
- count: 1
191
- };
192
- // Add a catalog index to it.
193
- addCatalogIndex(protoInstance, loc, report);
194
- // Add the standard instance to the standard instances.
195
- standardInstances.push(protoInstance);
196
- }
197
- }
198
- // Otherwise, i.e. if itemization is not required:
199
- else {
200
- // Add a summary instance to the instances.
201
- standardInstances.push({
202
- ruleID,
203
- what: whats,
204
- ordinalSeverity,
205
- count: violations.length
206
- });
207
- }
208
- // Return the result.
209
- return {
210
- data,
211
- totals,
212
- standardInstances
213
- };
214
261
  };
262
+ exports.getBasicResult = getBasicResult;