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