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
@@ -0,0 +1,301 @@
1
+ /*
2
+ © 2023–2024 CVS Health and/or one of its affiliates. All rights reserved.
3
+ © 2026 Jeff Witt.
4
+ © 2025–2026 Jonathan Robert Pool.
5
+
6
+ Licensed under the MIT License. See LICENSE file at the project root or
7
+ https://opensource.org/license/mit/ for details.
8
+
9
+ SPDX-License-Identifier: MIT
10
+ */
11
+
12
+ // IMPORTS
13
+
14
+ import * as fs from 'fs/promises';
15
+ import type {Page} from 'playwright';
16
+ // Shared configuration for timeout multiplier.
17
+ import {applyMultiplier} from '../procs/config';
18
+ import {getNormalizedXPath, getXPathCatalogIndex} from '../procs/xPath';
19
+ import {getStandardResult, addInstance} from '../procs/standard';
20
+ import type {Act, Report, StandardResult} from '../types';
21
+
22
+ // TYPES
23
+
24
+ // The aslint-act properties this reporter consumes.
25
+ interface AslintAct extends Act {
26
+ rules?: string[];
27
+ }
28
+ // One violation of a rule in an ASLint result.
29
+ interface AslintResultItem {
30
+ message?: {actual?: {description?: string}};
31
+ element?: {xpath?: string};
32
+ }
33
+ // The report of one rule in an ASLint result.
34
+ interface AslintRuleData {
35
+ issueType: string;
36
+ status: {type: string};
37
+ results: AslintResultItem[];
38
+ }
39
+ // The native result: the parsed ASLint report.
40
+ interface AslintNativeResult {
41
+ rules?: Record<string, AslintRuleData>;
42
+ }
43
+
44
+ // CONSTANTS
45
+
46
+ /*
47
+ Differentiates some rule IDs of aslint.
48
+ If the purported rule ID is a key and the what property contains all of the strings except the
49
+ last of any array item of the value of that key, then the final rule ID is the last item of that
50
+ array item.
51
+ */
52
+ const aslintData: Record<string, string[][]> = {
53
+ 'misused_required_attribute': [
54
+ ['not needed', 'misused_required_attributeR']
55
+ ],
56
+ 'accessible_svg': [
57
+ ['associated', 'accessible_svgI'],
58
+ ['tabindex', 'accessible_svgT']
59
+ ],
60
+ 'audio_alternative': [
61
+ ['track', 'audio_alternativeT'],
62
+ ['alternative', 'audio_alternativeA'],
63
+ ['bgsound', 'audio_alternativeB']
64
+ ],
65
+ 'table_missing_description': [
66
+ ['describedby', 'associated', 'table_missing_descriptionDM'],
67
+ ['labeledby', 'associated', 'table_missing_descriptionLM'],
68
+ ['caption', 'not been defined', 'table_missing_descriptionC'],
69
+ ['summary', 'empty', 'table_missing_descriptionS'],
70
+ ['describedby', 'empty', 'table_missing_descriptionDE'],
71
+ ['labeledby', 'empty', 'table_missing_descriptionLE'],
72
+ ['caption', 'no content', 'table_missing_descriptionE']
73
+ ],
74
+ 'label_implicitly_associated': [
75
+ ['only whice spaces', 'label_implicitly_associatedW'],
76
+ ['more than one', 'label_implicitly_associatedM']
77
+ ],
78
+ 'label_inappropriate_association': [
79
+ ['Missing', 'label_inappropriate_associationM'],
80
+ ['non-form', 'label_inappropriate_associationN']
81
+ ],
82
+ 'table_row_and_column_headers': [
83
+ ['headers', 'table_row_and_column_headersRC'],
84
+ ['Content', 'table_row_and_column_headersB'],
85
+ ['head of the columns', 'table_row_and_column_headersH']
86
+ ],
87
+ 'color_contrast_state_pseudo_classes_abstract': [
88
+ ['position: fixed', 'color_contrast_state_pseudo_classes_abstractF'],
89
+ ['transparent', 'color_contrast_state_pseudo_classes_abstractB'],
90
+ ['least 3:1', 'color_contrast_state_pseudo_classes_abstract3'],
91
+ ['least 4.5:1', 'color_contrast_state_pseudo_classes_abstract4']
92
+ ],
93
+ 'color_contrast_state_pseudo_classes_active': [
94
+ ['position: fixed', 'color_contrast_state_pseudo_classes_abstractF'],
95
+ ['transparent', 'color_contrast_state_pseudo_classes_abstractB'],
96
+ ['least 3:1', 'color_contrast_state_pseudo_classes_abstract3'],
97
+ ['least 4.5:1', 'color_contrast_state_pseudo_classes_abstract4']
98
+ ],
99
+ 'color_contrast_state_pseudo_classes_focus': [
100
+ ['position: fixed', 'color_contrast_state_pseudo_classes_abstractF'],
101
+ ['transparent', 'color_contrast_state_pseudo_classes_abstractB'],
102
+ ['least 3:1', 'color_contrast_state_pseudo_classes_abstract3'],
103
+ ['least 4.5:1', 'color_contrast_state_pseudo_classes_abstract4']
104
+ ],
105
+ 'color_contrast_state_pseudo_classes_hover': [
106
+ ['position: fixed', 'color_contrast_state_pseudo_classes_abstractF'],
107
+ ['transparent', 'color_contrast_state_pseudo_classes_abstractB'],
108
+ ['least 3:1', 'color_contrast_state_pseudo_classes_abstract3'],
109
+ ['least 4.5:1', 'color_contrast_state_pseudo_classes_abstract4']
110
+ ],
111
+ 'color_contrast_aaa': [
112
+ ['transparent', 'color_contrast_aaaB'],
113
+ ['least 4.5:1', 'color_contrast_aaa4'],
114
+ ['least 7:1', 'color_contrast_aaa7']
115
+ ],
116
+ 'animation': [
117
+ ['duration', 'animationD'],
118
+ ['iteration', 'animationI'],
119
+ ['mechanism', 'animationM']
120
+ ],
121
+ 'page_title': [
122
+ ['empty', 'page_titleN'],
123
+ ['not identify', 'page_titleU']
124
+ ],
125
+ 'aria_labelledby_association': [
126
+ ['exist', 'aria_labelledby_associationN'],
127
+ ['empty', 'aria_labelledby_associationE']
128
+ ],
129
+ 'html_lang_attr': [
130
+ ['parameters', 'html_lang_attrP'],
131
+ ['nothing', 'html_lang_attrN'],
132
+ ['empty', 'html_lang_attrE']
133
+ ],
134
+ 'missing_label': [
135
+ ['associated', 'missing_labelI'],
136
+ ['defined', 'missing_labelN'],
137
+ ['multiple labels', 'missing_labelM']
138
+ ],
139
+ 'orientation': [
140
+ ['loaded', 'orientationT']
141
+ ]
142
+ };
143
+
144
+ /*
145
+ aslint
146
+ Implements the ASLint ruleset for accessibility.
147
+ Compiled to aslint.js by tsc (issue #73); edit this file, not the emitted one.
148
+ */
149
+
150
+ // FUNCTIONS
151
+
152
+ // Conducts and reports the ASLint tests.
153
+ export const reporter = async (page: Page, report: Report, actIndex: number) => {
154
+ // Initialize the act report.
155
+ let data: {prevented?: boolean; error?: string} = {};
156
+ const result: {nativeResult: AslintNativeResult; standardResult: StandardResult} = {
157
+ nativeResult: {},
158
+ standardResult: {}
159
+ };
160
+ const standard = report.standard !== 'no';
161
+ // If standard results are to be reported:
162
+ if (standard) {
163
+ // Initialize the standard result.
164
+ result.standardResult = getStandardResult();
165
+ }
166
+ const {standardResult} = result;
167
+ // Get the ASLint runner and bundle scripts.
168
+ const aslintRunner = await fs.readFile(`${__dirname}/../procs/aslint.js`, 'utf8');
169
+ const aslintBundlePath = require.resolve('aslint-testaro/aslint.bundle.js');
170
+ const aslintBundle = await fs.readFile(aslintBundlePath, 'utf8');
171
+ // Get the nonce, if any.
172
+ const act = report.acts[actIndex] as AslintAct;
173
+ const {jobData} = report;
174
+ const scriptNonce = (jobData && jobData.lastScriptNonce) as string | undefined;
175
+ // Inject the ASLint bundle and runner into the head of the page.
176
+ await page.evaluate(args => {
177
+ const {scriptNonce, aslintBundle, aslintRunner} = args;
178
+ // Bundle.
179
+ const bundleEl = document.createElement('script');
180
+ bundleEl.id = 'aslintBundle';
181
+ if (scriptNonce) {
182
+ bundleEl.nonce = scriptNonce;
183
+ console.log(`Added nonce ${scriptNonce} to bundle`);
184
+ }
185
+ bundleEl.textContent = aslintBundle;
186
+ document.head.insertAdjacentElement('beforeend', bundleEl);
187
+ // Runner.
188
+ const runnerEl = document.createElement('script');
189
+ if (scriptNonce) {
190
+ runnerEl.nonce = scriptNonce;
191
+ console.log(`Added nonce ${scriptNonce} to runner`);
192
+ }
193
+ runnerEl.textContent = aslintRunner;
194
+ document.body.insertAdjacentElement('beforeend', runnerEl);
195
+ }, {scriptNonce, aslintBundle, aslintRunner})
196
+ .catch(error => {
197
+ const message = `ERROR: ASLint injection failed (${error.message.slice(0, 400)})`;
198
+ console.log(message);
199
+ data.prevented = true;
200
+ data.error = message;
201
+ if (standard) {
202
+ standardResult.prevented = true;
203
+ }
204
+ });
205
+ const reportLoc = page.locator('#aslintResult');
206
+ // If the injection succeeded:
207
+ if (! data.prevented) {
208
+ try {
209
+ // Wait for the test results to be attached to the page.
210
+ const waitOptions = {
211
+ state: 'attached' as const,
212
+ timeout: applyMultiplier(20000)
213
+ };
214
+ await reportLoc.waitFor(waitOptions);
215
+ }
216
+ catch(error) {
217
+ const message = 'Attachment of test results to page failed';
218
+ console.log(message);
219
+ data.prevented = true;
220
+ data.error = `${message} (${(error as Error).message})`;
221
+ };
222
+ }
223
+ // If the injection and the result attachment both succeeded:
224
+ if (! data.prevented) {
225
+ // Get their text.
226
+ const actReport = await reportLoc.textContent();
227
+ try {
228
+ const nativeResult = result.nativeResult = JSON.parse(actReport as string);
229
+ // If any rules were reported violated:
230
+ if (nativeResult.rules) {
231
+ const {rules} = nativeResult as Required<AslintNativeResult>;
232
+ // For each such rule:
233
+ for (const ruleID of Object.keys(rules)) {
234
+ const ruleData = rules[ruleID];
235
+ const {issueType, status} = ruleData;
236
+ const excluded = act.rules && ! act.rules.includes(ruleID);
237
+ const {type} = status;
238
+ // If rule is not an error or warning or is not to be tested:
239
+ if (
240
+ excluded
241
+ || ['passed', 'skipped'].includes(type)
242
+ || ! ['error', 'warning'].includes(issueType)
243
+ ) {
244
+ // Delete the rule report.
245
+ delete rules[ruleID];
246
+ }
247
+ }
248
+ // If standard results are to be reported:
249
+ if (standard) {
250
+ const ruleIDs = Object.keys(rules);
251
+ // For each violated rule:
252
+ for (let ruleID of ruleIDs) {
253
+ const ruleData = rules[ruleID];
254
+ const {issueType, results} = ruleData;
255
+ // For each violation:
256
+ for (const result of results) {
257
+ const {message, element} = result;
258
+ // Get a description of the violated rule.
259
+ const what = message?.actual?.description ?? '';
260
+ const changer = aslintData[ruleID]?.find(
261
+ specs => specs.slice(0, -1).every(matcher => what.includes(matcher))
262
+ );
263
+ // If the rule ID is differentiatable:
264
+ if (changer) {
265
+ // Differentiate it.
266
+ ruleID = changer[changer.length - 1];
267
+ }
268
+ // Get the ordinal severity of the violation.
269
+ const ordinalSeverity = issueType === 'warning' ? 1 : 2;
270
+ // Get the pathID of the element.
271
+ const {xpath} = element!;
272
+ const pathID = getNormalizedXPath(xpath);
273
+ // Use it to get the index of the element in the catalog.
274
+ const catalogIndex = getXPathCatalogIndex(report, pathID);
275
+ // Add an instance to the standard result.
276
+ addInstance(standardResult, {
277
+ ruleID,
278
+ what,
279
+ ordinalSeverity,
280
+ outcome: issueType === 'warning' ? 'cantTell' : 'failed',
281
+ catalogIndex
282
+ });
283
+ }
284
+ }
285
+ }
286
+ }
287
+ }
288
+ // If the results are not JSON:
289
+ catch(error) {
290
+ const message = `Result processing failed (${(error as Error).message})`;
291
+ console.log(`ERROR: ${message}`);
292
+ // Report this.
293
+ data.prevented = true;
294
+ data.error = message;
295
+ }
296
+ }
297
+ return {
298
+ data,
299
+ result
300
+ };
301
+ };
package/tests/axe.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ import type { Page } from 'playwright';
2
+ import type { AxeResults } from 'axe-core';
3
+ import type { Report, StandardResult } from '../types';
4
+ type AxeImpact = 'minor' | 'moderate' | 'serious' | 'critical';
5
+ interface AxeNativeResult {
6
+ totals?: {
7
+ rulesNA: number;
8
+ rulesPassed: number;
9
+ rulesWarned: number;
10
+ rulesViolated: number;
11
+ warnings: Record<AxeImpact, number>;
12
+ violations: Record<AxeImpact, number>;
13
+ };
14
+ details?: AxeResults;
15
+ }
16
+ interface AxeData {
17
+ prevented?: boolean;
18
+ error?: string;
19
+ }
20
+ export declare const reporter: (page: Page, report: Report, actIndex: number) => Promise<{
21
+ data: AxeData;
22
+ result: {
23
+ nativeResult: AxeNativeResult;
24
+ standardResult: StandardResult;
25
+ };
26
+ }>;
27
+ export {};