testaro 78.0.8 → 78.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (356) 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 +24 -18
  7. package/CONTAINERS.md +9 -6
  8. package/CONTRIBUTING.md +29 -3
  9. package/Dockerfile +1 -1
  10. package/README.md +73 -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/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 +372 -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 +312 -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 +62 -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/job.js +115 -1
  38. package/procs/launch.d.ts +40 -0
  39. package/procs/launch.js +239 -108
  40. package/procs/nu.d.ts +48 -0
  41. package/procs/scope.js +196 -0
  42. package/procs/shoot.d.ts +33 -0
  43. package/procs/standard.d.ts +18 -0
  44. package/procs/standard.js +83 -0
  45. package/procs/standard.ts +126 -0
  46. package/procs/testAct.js +145 -0
  47. package/procs/testaro.d.ts +20 -0
  48. package/procs/testaro.js +236 -189
  49. package/procs/testaro.ts +321 -0
  50. package/procs/userPath.js +126 -0
  51. package/procs/xPath.d.ts +4 -0
  52. package/procs/xPath.js +81 -69
  53. package/procs/xPath.ts +106 -0
  54. package/procs/xPathScript.d.ts +6 -0
  55. package/procs/xPathScript.js +70 -0
  56. package/run.js +3 -2
  57. package/surea11y/README.md +44 -0
  58. package/surea11y/surea11y.browser.js +14 -0
  59. package/testaro/adbID.d.ts +3 -0
  60. package/testaro/adbID.js +38 -41
  61. package/testaro/adbID.ts +66 -0
  62. package/testaro/allCapStyle.d.ts +3 -0
  63. package/testaro/allCapStyle.js +31 -34
  64. package/testaro/allCapStyle.ts +55 -0
  65. package/testaro/allCaps.d.ts +16 -0
  66. package/testaro/allCaps.js +179 -151
  67. package/testaro/allCaps.ts +228 -0
  68. package/testaro/allHidden.d.ts +13 -0
  69. package/testaro/allHidden.js +29 -30
  70. package/testaro/allHidden.ts +50 -0
  71. package/testaro/allSlanted.d.ts +3 -0
  72. package/testaro/allSlanted.js +30 -33
  73. package/testaro/allSlanted.ts +54 -0
  74. package/testaro/altScheme.d.ts +3 -0
  75. package/testaro/altScheme.js +27 -30
  76. package/testaro/altScheme.ts +50 -0
  77. package/testaro/attVal.d.ts +3 -0
  78. package/testaro/attVal.js +20 -21
  79. package/testaro/attVal.ts +52 -0
  80. package/testaro/autocomplete.d.ts +3 -0
  81. package/testaro/autocomplete.js +59 -75
  82. package/testaro/autocomplete.ts +101 -0
  83. package/testaro/bulk.d.ts +13 -0
  84. package/testaro/bulk.js +32 -33
  85. package/testaro/bulk.ts +55 -0
  86. package/testaro/buttonMenu.d.ts +9 -0
  87. package/testaro/buttonMenu.js +317 -319
  88. package/testaro/buttonMenu.ts +391 -0
  89. package/testaro/captionLoc.d.ts +3 -0
  90. package/testaro/captionLoc.js +17 -20
  91. package/testaro/captionLoc.ts +40 -0
  92. package/testaro/datalistRef.d.ts +3 -0
  93. package/testaro/datalistRef.js +33 -36
  94. package/testaro/datalistRef.ts +55 -0
  95. package/testaro/distortion.d.ts +3 -0
  96. package/testaro/distortion.js +57 -26
  97. package/testaro/distortion.ts +81 -0
  98. package/testaro/docType.d.ts +15 -0
  99. package/testaro/docType.js +25 -25
  100. package/testaro/docType.ts +45 -0
  101. package/testaro/dupAtt.d.ts +16 -0
  102. package/testaro/dupAtt.js +113 -104
  103. package/testaro/dupAtt.ts +144 -0
  104. package/testaro/elements.d.ts +6 -0
  105. package/testaro/elements.js +153 -153
  106. package/testaro/elements.ts +215 -0
  107. package/testaro/embAc.d.ts +3 -0
  108. package/testaro/embAc.js +19 -20
  109. package/testaro/embAc.ts +40 -0
  110. package/testaro/focAll.d.ts +13 -0
  111. package/testaro/focAll.js +185 -191
  112. package/testaro/focAll.ts +217 -0
  113. package/testaro/focAndOp.d.ts +3 -0
  114. package/testaro/focAndOp.js +100 -104
  115. package/testaro/focAndOp.ts +128 -0
  116. package/testaro/focInd.d.ts +3 -0
  117. package/testaro/focInd.js +64 -66
  118. package/testaro/focInd.ts +96 -0
  119. package/testaro/focVis.d.ts +3 -0
  120. package/testaro/focVis.js +28 -30
  121. package/testaro/focVis.ts +52 -0
  122. package/testaro/headEl.d.ts +10 -0
  123. package/testaro/headEl.js +61 -62
  124. package/testaro/headEl.ts +82 -0
  125. package/testaro/headingAmb.d.ts +3 -0
  126. package/testaro/headingAmb.js +54 -63
  127. package/testaro/headingAmb.ts +72 -0
  128. package/testaro/hovInd.d.ts +12 -0
  129. package/testaro/hovInd.js +163 -130
  130. package/testaro/hovInd.ts +199 -0
  131. package/testaro/hover.d.ts +3 -0
  132. package/testaro/hover.js +155 -126
  133. package/testaro/hover.ts +154 -0
  134. package/testaro/hr.d.ts +3 -0
  135. package/testaro/hr.js +14 -17
  136. package/testaro/hr.ts +36 -0
  137. package/testaro/imageLink.d.ts +3 -0
  138. package/testaro/imageLink.js +17 -20
  139. package/testaro/imageLink.ts +42 -0
  140. package/testaro/labClash.d.ts +3 -0
  141. package/testaro/labClash.js +31 -33
  142. package/testaro/labClash.ts +54 -0
  143. package/testaro/legendLoc.d.ts +3 -0
  144. package/testaro/legendLoc.js +17 -20
  145. package/testaro/legendLoc.ts +42 -0
  146. package/testaro/lineHeight.d.ts +3 -0
  147. package/testaro/lineHeight.js +43 -48
  148. package/testaro/lineHeight.ts +70 -0
  149. package/testaro/linkAmb.d.ts +7 -0
  150. package/testaro/linkAmb.js +79 -80
  151. package/testaro/linkAmb.ts +105 -0
  152. package/testaro/linkExt.d.ts +3 -0
  153. package/testaro/linkExt.js +13 -16
  154. package/testaro/linkExt.ts +35 -0
  155. package/testaro/linkOldAtt.d.ts +3 -0
  156. package/testaro/linkOldAtt.js +25 -28
  157. package/testaro/linkOldAtt.ts +48 -0
  158. package/testaro/linkTo.d.ts +3 -0
  159. package/testaro/linkTo.js +22 -22
  160. package/testaro/linkTo.ts +43 -0
  161. package/testaro/linkUl.d.ts +3 -0
  162. package/testaro/linkUl.js +30 -34
  163. package/testaro/linkUl.ts +54 -0
  164. package/testaro/miniText.d.ts +3 -0
  165. package/testaro/miniText.js +41 -44
  166. package/testaro/miniText.ts +68 -0
  167. package/testaro/motion.d.ts +10 -0
  168. package/testaro/motion.js +92 -96
  169. package/testaro/motion.ts +125 -0
  170. package/testaro/nonTable.d.ts +3 -0
  171. package/testaro/nonTable.js +39 -45
  172. package/testaro/nonTable.ts +66 -0
  173. package/testaro/optRoleSel.d.ts +3 -0
  174. package/testaro/optRoleSel.js +16 -19
  175. package/testaro/optRoleSel.ts +41 -0
  176. package/testaro/phOnly.d.ts +3 -0
  177. package/testaro/phOnly.js +18 -21
  178. package/testaro/phOnly.ts +43 -0
  179. package/testaro/pseudoP.d.ts +3 -0
  180. package/testaro/pseudoP.js +36 -38
  181. package/testaro/pseudoP.ts +59 -0
  182. package/testaro/radioSet.d.ts +3 -0
  183. package/testaro/radioSet.js +57 -59
  184. package/testaro/radioSet.ts +79 -0
  185. package/testaro/registry.d.ts +63 -0
  186. package/testaro/registry.js +67 -0
  187. package/testaro/registry.ts +141 -0
  188. package/testaro/role.d.ts +3 -0
  189. package/testaro/role.js +27 -29
  190. package/testaro/role.ts +53 -0
  191. package/testaro/secHeading.d.ts +3 -0
  192. package/testaro/secHeading.js +30 -33
  193. package/testaro/secHeading.ts +53 -0
  194. package/testaro/styleDiff.d.ts +25 -0
  195. package/testaro/styleDiff.js +248 -252
  196. package/testaro/styleDiff.ts +303 -0
  197. package/testaro/tabNav.d.ts +33 -0
  198. package/testaro/tabNav.js +272 -342
  199. package/testaro/tabNav.ts +454 -0
  200. package/testaro/targetsNear.d.ts +9 -0
  201. package/testaro/targetsNear.js +130 -132
  202. package/testaro/targetsNear.ts +160 -0
  203. package/testaro/textNodes.d.ts +6 -0
  204. package/testaro/textNodes.js +139 -135
  205. package/testaro/textNodes.ts +185 -0
  206. package/testaro/textSem.d.ts +3 -0
  207. package/testaro/textSem.js +25 -28
  208. package/testaro/textSem.ts +47 -0
  209. package/testaro/title.d.ts +9 -0
  210. package/testaro/title.js +16 -13
  211. package/testaro/title.ts +31 -0
  212. package/testaro/titledEl.d.ts +3 -0
  213. package/testaro/titledEl.js +15 -18
  214. package/testaro/titledEl.ts +38 -0
  215. package/testaro/zIndex.d.ts +3 -0
  216. package/testaro/zIndex.js +19 -22
  217. package/testaro/zIndex.ts +42 -0
  218. package/tests/alfa.d.ts +45 -0
  219. package/tests/alfa.js +138 -141
  220. package/tests/alfa.ts +214 -0
  221. package/tests/aslint.d.ts +33 -0
  222. package/tests/aslint.js +272 -249
  223. package/tests/aslint.ts +301 -0
  224. package/tests/axe.d.ts +27 -0
  225. package/tests/axe.js +199 -200
  226. package/tests/axe.ts +277 -0
  227. package/tests/ed11y.d.ts +28 -0
  228. package/tests/ed11y.js +141 -99
  229. package/tests/ed11y.ts +178 -0
  230. package/tests/htmlcs.d.ts +21 -0
  231. package/tests/htmlcs.js +174 -140
  232. package/tests/htmlcs.ts +181 -0
  233. package/tests/ibm.d.ts +52 -0
  234. package/tests/ibm.js +164 -166
  235. package/tests/ibm.ts +251 -0
  236. package/tests/nuVal.d.ts +13 -0
  237. package/tests/nuVal.js +107 -112
  238. package/tests/nuVal.ts +145 -0
  239. package/tests/nuVnu.d.ts +15 -0
  240. package/tests/nuVnu.js +141 -111
  241. package/tests/nuVnu.ts +144 -0
  242. package/tests/pour.d.ts +31 -0
  243. package/tests/pour.js +242 -0
  244. package/tests/pour.ts +273 -0
  245. package/tests/qualWeb.d.ts +39 -0
  246. package/tests/qualWeb.js +302 -272
  247. package/tests/qualWeb.ts +415 -0
  248. package/tests/surea11y.d.ts +33 -0
  249. package/tests/surea11y.js +288 -0
  250. package/tests/surea11y.ts +334 -0
  251. package/tests/testaro.d.ts +25 -0
  252. package/tests/testaro.js +745 -652
  253. package/tests/testaro.ts +862 -0
  254. package/tests/wave.d.ts +46 -0
  255. package/tests/wave.js +166 -177
  256. package/tests/wave.ts +252 -0
  257. package/tsconfig.json +17 -0
  258. package/types.d.ts +243 -0
  259. package/types.js +10 -0
  260. package/types.ts +376 -0
  261. package/validation/act/README.md +46 -0
  262. package/validation/act/capture.js +424 -0
  263. package/validation/act/chromium-issue-draft.md +66 -0
  264. package/validation/act/fp-triage-2026-08-22.md +86 -0
  265. package/validation/act/isolation-notes.md +159 -0
  266. package/validation/act/playwright-issue-draft.md +73 -0
  267. package/validation/act/propose-mappings.js +0 -0
  268. package/validation/act/repro-cdp-raw.js +105 -0
  269. package/validation/act/repro-metarefresh.js +65 -0
  270. package/validation/act/score.js +184 -0
  271. package/validation/act/stage3a-stress-report.md +69 -0
  272. package/validation/act/stage3b-mapping-proposals.md +94 -0
  273. package/validation/act/stage3b-triage-draft.md +138 -0
  274. package/validation/act/surea11y-track-a-2026-09-01.md +50 -0
  275. package/validation/executors/netWatch.js +180 -90
  276. package/validation/executors/test.js +17 -2
  277. package/validation/executors/tests.js +118 -10
  278. package/validation/jobs/reports/raw/260901T1000-surea11y-validation.json +964 -0
  279. package/validation/jobs/todo/240101T1200-simple-example.json +14 -6
  280. package/validation/jobs/todo/240101T1300-shoot-example.json +2 -1
  281. package/validation/jobs/todo/260821T1900-pour-validation.json +45 -0
  282. package/validation/jobs/todo/260901T1000-surea11y-validation.json +45 -0
  283. package/validation/knownFailures.json +1 -0
  284. package/validation/tests/jobProperties/adbID.json +27 -2
  285. package/validation/tests/jobProperties/{focOp.json → allCapStyle.json} +56 -53
  286. package/validation/tests/jobProperties/allCaps.json +25 -0
  287. package/validation/tests/jobProperties/allHidden.json +133 -13
  288. package/validation/tests/jobProperties/allSlanted.json +3 -3
  289. package/validation/tests/jobProperties/altScheme.json +23 -8
  290. package/validation/tests/jobProperties/attVal.json +57 -57
  291. package/validation/tests/jobProperties/autocomplete.json +11 -1
  292. package/validation/tests/jobProperties/bulk.json +6 -1
  293. package/validation/tests/jobProperties/buttonMenu.json +63 -42
  294. package/validation/tests/jobProperties/captionLoc.json +1 -6
  295. package/validation/tests/jobProperties/checkpoint-browser.json +401 -0
  296. package/validation/tests/jobProperties/checkpoint-page.json +397 -0
  297. package/validation/tests/jobProperties/checkpoint.json +395 -0
  298. package/validation/tests/jobProperties/datalistRef.json +20 -5
  299. package/validation/tests/jobProperties/distortion.json +28 -3
  300. package/validation/tests/jobProperties/docType.json +2 -2
  301. package/validation/tests/jobProperties/dupAtt.json +48 -33
  302. package/validation/tests/jobProperties/elements.json +28 -28
  303. package/validation/tests/jobProperties/embAc.json +36 -31
  304. package/validation/tests/jobProperties/focAndOp.json +284 -0
  305. package/validation/tests/jobProperties/focInd.json +34 -34
  306. package/validation/tests/jobProperties/focVis.json +1 -1
  307. package/validation/tests/jobProperties/hover.json +39 -37
  308. package/validation/tests/jobProperties/hr.json +13 -3
  309. package/validation/tests/jobProperties/imageLink.json +0 -5
  310. package/validation/tests/jobProperties/labClash.json +68 -33
  311. package/validation/tests/jobProperties/legendLoc.json +1 -6
  312. package/validation/tests/jobProperties/lineHeight.json +2 -2
  313. package/validation/tests/jobProperties/linkAmb.json +13 -18
  314. package/validation/tests/jobProperties/linkExt.json +1 -1
  315. package/validation/tests/jobProperties/linkOldAtt.json +12 -2
  316. package/validation/tests/jobProperties/linkTo.json +1 -1
  317. package/validation/tests/jobProperties/linkUl.json +65 -65
  318. package/validation/tests/jobProperties/miniText.json +7 -2
  319. package/validation/tests/jobProperties/motion.json +4 -50
  320. package/validation/tests/jobProperties/nonTable.json +48 -3
  321. package/validation/tests/jobProperties/optRoleSel.json +12 -2
  322. package/validation/tests/jobProperties/phOnly.json +6 -16
  323. package/validation/tests/jobProperties/pseudoP.json +17 -2
  324. package/validation/tests/jobProperties/radioSet.json +30 -30
  325. package/validation/tests/jobProperties/role.json +25 -5
  326. package/validation/tests/jobProperties/secHeading.json +26 -21
  327. package/validation/tests/jobProperties/styleDiff.json +35 -5
  328. package/validation/tests/jobProperties/tabNav.json +3 -1
  329. package/validation/tests/jobProperties/targetsNear.json +237 -0
  330. package/validation/tests/jobProperties/textNodes.json +29 -29
  331. package/validation/tests/jobProperties/textSem.json +26 -1
  332. package/validation/tests/jobProperties/title.json +12 -2
  333. package/validation/tests/jobProperties/titledEl.json +39 -9
  334. package/validation/tests/jobProperties/userPath.json +317 -0
  335. package/validation/tests/jobProperties/zIndex.json +40 -35
  336. package/validation/tests/targets/allCapStyle/index.html +26 -0
  337. package/validation/tests/targets/checkpoint/index.html +38 -0
  338. package/validation/tests/targets/datalistRef/index.html +1 -1
  339. package/validation/tests/targets/focAndOp/bad.html +29 -0
  340. package/validation/tests/targets/{focOp → focAndOp}/good.html +3 -1
  341. package/validation/tests/targets/focInd/bad.html +2 -1
  342. package/validation/tests/targets/headEl/index.html +10 -1
  343. package/validation/tests/targets/{targetSmall → targetsNear}/index.html +15 -1
  344. package/validation/tests/targets/userPath/index.html +42 -0
  345. package/validation/validateTest.js +61 -9
  346. package/.claude/settings.local.json +0 -11
  347. package/.eslintrc.json +0 -41
  348. package/htmlcs/.eslintrc.json +0 -67
  349. package/validation/tests/jobProperties/linkTitle.json +0 -127
  350. package/validation/tests/jobProperties/opFoc.json +0 -164
  351. package/validation/tests/jobProperties/targetSmall.json +0 -152
  352. package/validation/tests/jobProperties/targetTiny.json +0 -142
  353. package/validation/tests/targets/focOp/bad.html +0 -25
  354. package/validation/tests/targets/linkTitle/index.html +0 -24
  355. package/validation/tests/targets/opFoc/bad.html +0 -26
  356. package/validation/tests/targets/opFoc/good.html +0 -23
package/tests/axe.js CHANGED
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /*
2
3
  © 2021–2024 CVS Health and/or one of its affiliates. All rights reserved.
3
4
  © 2026 Jeff Witt.
@@ -8,7 +9,19 @@
8
9
 
9
10
  SPDX-License-Identifier: MIT
10
11
  */
11
-
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.reporter = void 0;
14
+ const xPath_1 = require("../procs/xPath");
15
+ const standard_1 = require("../procs/standard");
16
+ const axePlaywright = require('axe-playwright');
17
+ // CONSTANTS
18
+ const { injectAxe } = axePlaywright;
19
+ const severityWeights = {
20
+ minor: 0,
21
+ moderate: 0,
22
+ serious: 1,
23
+ critical: 1
24
+ };
12
25
  /*
13
26
  axe
14
27
  Implements the axe-core ruleset for accessibility.
@@ -28,215 +41,201 @@
28
41
  incomplete categories, node totals by severity. It does not show rule or node totals by test
29
42
  category (“tag”), such as 'wcag21aaa'. Scoring can consider test categories by getting the value
30
43
  of the 'tags' property of each rule.
44
+ Compiled to axe.js by tsc (issue #73); edit this file, not the emitted one.
31
45
  */
32
-
33
- // IMPORTS
34
-
35
- const axePlaywright = require('axe-playwright');
36
- const {getAttributeXPath, getXPathCatalogIndex} = require('../procs/xPath');
37
-
38
- // CONSTANTS
39
-
40
- const {injectAxe} = axePlaywright;
41
- const severityWeights = {
42
- minor: 0,
43
- moderate: 0,
44
- serious: 1,
45
- critical: 1
46
- };
47
-
48
46
  // FUNCTIONS
49
-
50
47
  // Conducts and reports the Axe tests.
51
- exports.reporter = async (page, report, actIndex) => {
52
- const act = report.acts[actIndex];
53
- const {detailLevel, rules} = act;
54
- // Initialize the act report.
55
- let data = {};
56
- const result = {
57
- nativeResult: {},
58
- standardResult: {}
59
- };
60
- const standard = report.standard !== 'no';
61
- // If standard results are to be reported:
62
- if (standard) {
63
- // Initialize the standard result.
64
- result.standardResult = {
65
- prevented: false,
66
- totals: [0, 0, 0, 0],
67
- instances: []
48
+ const reporter = async (page, report, actIndex) => {
49
+ const act = report.acts[actIndex];
50
+ const { detailLevel, rules } = act;
51
+ // Initialize the act report.
52
+ let data = {};
53
+ const result = {
54
+ nativeResult: {},
55
+ standardResult: {}
68
56
  };
69
- }
70
- const {nativeResult, standardResult} = result;
71
- // Inject axe-core into the page.
72
- await injectAxe(page)
73
- .catch(error => {
74
- console.log(`ERROR: Axe injection failed (${error.message})`);
75
- data.prevented = true;
76
- data.error = 'ERROR: axe injection failed';
77
- });
78
- // If the injection succeeded:
79
- if (! data.prevented) {
80
- // Get the data on the elements violating the specified axe-core rules.
81
- const axeOptions = {
82
- resultTypes: ['violations', 'incomplete']
83
- };
84
- if (rules && rules.length) {
85
- axeOptions.runOnly = rules;
86
- }
87
- else {
88
- axeOptions.runOnly = ['experimental', 'best-practice', 'wcag2a', 'wcag2aa', 'wcag2aaa', 'wcag21a', 'wcag21aa', 'wcag21aaa'];
57
+ const standard = report.standard !== 'no';
58
+ // If standard results are to be reported:
59
+ if (standard) {
60
+ // Initialize the standard result.
61
+ result.standardResult = (0, standard_1.getStandardResult)();
89
62
  }
90
- const axeReport = await axePlaywright.getAxeResults(page, null, axeOptions);
91
- const {inapplicable, passes, incomplete, violations} = axeReport;
92
- // If the test succeeded:
93
- if (violations) {
94
- // Initialize the native result.
95
- nativeResult.totals = {
96
- rulesNA: 0,
97
- rulesPassed: 0,
98
- rulesWarned: 0,
99
- rulesViolated: 0,
100
- warnings: {
101
- minor: 0,
102
- moderate: 0,
103
- serious: 0,
104
- critical: 0
105
- },
106
- violations: {
107
- minor: 0,
108
- moderate: 0,
109
- serious: 0,
110
- critical: 0
63
+ const { nativeResult, standardResult } = result;
64
+ // Inject axe-core into the page.
65
+ await injectAxe(page)
66
+ .catch(error => {
67
+ console.log(`ERROR: Axe injection failed (${error.message})`);
68
+ data.prevented = true;
69
+ data.error = 'ERROR: axe injection failed';
70
+ });
71
+ // If the injection succeeded:
72
+ if (!data.prevented) {
73
+ // Get the data on the elements violating the specified axe-core rules.
74
+ const axeOptions = {
75
+ resultTypes: ['violations', 'incomplete']
76
+ };
77
+ if (rules && rules.length) {
78
+ // A bare array would be read as tag names; rule IDs need the object form.
79
+ axeOptions.runOnly = { type: 'rule', values: rules };
111
80
  }
112
- };
113
- nativeResult.details = axeReport;
114
- // Populate the native-result totals.
115
- const {totals} = nativeResult;
116
- totals.rulesNA = inapplicable.length;
117
- totals.rulesPassed = passes.length;
118
- incomplete.forEach(rule => {
119
- totals.rulesWarned++;
120
- rule.nodes.forEach(node => {
121
- totals.warnings[node.impact]++;
122
- });
123
- });
124
- violations.forEach(rule => {
125
- totals.rulesViolated++;
126
- rule.nodes.forEach(node => {
127
- totals.violations[node.impact]++;
128
- });
129
- });
130
- // Delete irrelevant properties from the report details.
131
- const irrelevants = ['inapplicable', 'passes', 'incomplete', 'violations']
132
- .slice(0, 4 - detailLevel);
133
- irrelevants.forEach(irrelevant => {
134
- delete axeReport[irrelevant];
135
- });
136
- // If standard results are to be reported and there are any suspicions:
137
- if (standard && (totals.rulesViolated || totals.rulesWarned)) {
138
- // Resolve each suspected element's FULL data-xpath from the live DOM,
139
- // keyed by its axe target. axe-core truncates node.html (~300 chars,
140
- // appends '...'), so parsing data-xpath out of node.html yields a
141
- // truncated XPath for elements with long attribute lists. node.target
142
- // is a reliable CSS selector; read the injected data-xpath directly off
143
- // the element instead. Falls back to the node.html parse on any failure.
144
- const fullXPathByTargetKey = {};
145
- try {
146
- const suspectNodes = ['incomplete', 'violations']
147
- .filter(certainty => nativeResult?.details?.[certainty])
148
- .flatMap(certainty => nativeResult.details[certainty].flatMap(rule => rule.nodes));
149
- const targets = suspectNodes.map(node => node.target);
150
- const resolvedXPaths = await page.evaluate(targetList => targetList.map(target => {
151
- try {
152
- // axe target is an array of selectors (nested arrays for frames/
153
- // shadow roots). Use the deepest plain-string selector for the
154
- // common, non-framed case; skip otherwise.
155
- const selector = Array.isArray(target)
156
- ? (typeof target[target.length - 1] === 'string' ? target[target.length - 1] : null)
157
- : (typeof target === 'string' ? target : null);
158
- if (! selector) {
159
- return null;
160
- }
161
- const element = document.querySelector(selector);
162
- return element ? element.getAttribute('data-xpath') : null;
163
- }
164
- catch(error) {
165
- return null;
166
- }
167
- }), targets);
168
- suspectNodes.forEach((node, index) => {
169
- if (resolvedXPaths[index]) {
170
- fullXPathByTargetKey[JSON.stringify(node.target)] = resolvedXPaths[index];
81
+ else {
82
+ axeOptions.runOnly = ['experimental', 'best-practice', 'wcag2a', 'wcag2aa', 'wcag2aaa', 'wcag21a', 'wcag21aa', 'wcag21aaa'];
83
+ }
84
+ // If the act is scoped to changed subtrees, test only them (axe's include context).
85
+ const scopeRoots = report.scope?.roots;
86
+ const context = scopeRoots && scopeRoots.length
87
+ ? { include: scopeRoots }
88
+ : null;
89
+ const axeReport = await axePlaywright.getAxeResults(page, context, axeOptions);
90
+ const { inapplicable, passes, incomplete, violations } = axeReport;
91
+ // If the test succeeded:
92
+ if (violations) {
93
+ // Initialize the native result.
94
+ nativeResult.totals = {
95
+ rulesNA: 0,
96
+ rulesPassed: 0,
97
+ rulesWarned: 0,
98
+ rulesViolated: 0,
99
+ warnings: {
100
+ minor: 0,
101
+ moderate: 0,
102
+ serious: 0,
103
+ critical: 0
104
+ },
105
+ violations: {
106
+ minor: 0,
107
+ moderate: 0,
108
+ serious: 0,
109
+ critical: 0
110
+ }
111
+ };
112
+ nativeResult.details = axeReport;
113
+ // Populate the native-result totals.
114
+ const { totals } = nativeResult;
115
+ totals.rulesNA = inapplicable.length;
116
+ totals.rulesPassed = passes.length;
117
+ incomplete.forEach(rule => {
118
+ totals.rulesWarned++;
119
+ rule.nodes.forEach(node => {
120
+ totals.warnings[node.impact]++;
121
+ });
122
+ });
123
+ violations.forEach(rule => {
124
+ totals.rulesViolated++;
125
+ rule.nodes.forEach(node => {
126
+ totals.violations[node.impact]++;
127
+ });
128
+ });
129
+ // If standard results are to be reported and there are any suspicions:
130
+ if (standard && (totals.rulesViolated || totals.rulesWarned)) {
131
+ // Resolve each suspected element's FULL data-xpath from the live DOM,
132
+ // keyed by its axe target. axe-core truncates node.html (~300 chars,
133
+ // appends '...'), so parsing data-xpath out of node.html yields a
134
+ // truncated XPath for elements with long attribute lists. node.target
135
+ // is a reliable CSS selector; read the injected data-xpath directly off
136
+ // the element instead. Falls back to the node.html parse on any failure.
137
+ const fullXPathByTargetKey = {};
138
+ try {
139
+ const suspectNodes = ['incomplete', 'violations']
140
+ .filter(certainty => nativeResult?.details?.[certainty])
141
+ .flatMap(certainty => nativeResult.details[certainty].flatMap(rule => rule.nodes));
142
+ const targets = suspectNodes.map(node => node.target);
143
+ const resolvedXPaths = await page.evaluate(targetList => targetList.map(target => {
144
+ try {
145
+ // axe target is an array of selectors (nested arrays for frames/
146
+ // shadow roots). Use the deepest plain-string selector for the
147
+ // common, non-framed case; skip otherwise.
148
+ const selector = Array.isArray(target)
149
+ ? (typeof target[target.length - 1] === 'string' ? target[target.length - 1] : null)
150
+ : (typeof target === 'string' ? target : null);
151
+ if (!selector) {
152
+ return null;
153
+ }
154
+ const element = document.querySelector(selector);
155
+ return element ? element.getAttribute('data-xpath') : null;
156
+ }
157
+ catch (error) {
158
+ return null;
159
+ }
160
+ }), targets);
161
+ suspectNodes.forEach((node, index) => {
162
+ if (resolvedXPaths[index]) {
163
+ fullXPathByTargetKey[JSON.stringify(node.target)] = resolvedXPaths[index];
164
+ }
165
+ });
166
+ }
167
+ catch (error) {
168
+ // Leave the map empty; every instance falls back to node.html below.
169
+ }
170
+ // For each certainty type:
171
+ ['incomplete', 'violations'].forEach(certainty => {
172
+ // If there are any suspicions of this type:
173
+ if (nativeResult?.details?.[certainty]) {
174
+ // For each rule with any suspicions:
175
+ nativeResult.details[certainty].forEach(rule => {
176
+ // For each element suspected of violating the rule:
177
+ rule.nodes.forEach((node) => {
178
+ // Get descriptions of the rule.
179
+ const whatSet = new Set([
180
+ rule.help,
181
+ ...node.any.map(anyItem => anyItem.message),
182
+ ...node.all.map(allItem => allItem.message)
183
+ ]);
184
+ // Get the ordinal severity of the suspicion.
185
+ const ordinalSeverity = severityWeights[node.impact]
186
+ + (certainty === 'violations' ? 2 : 0);
187
+ // Get the XPath of the suspected element from its data-xpath
188
+ // attribute. Prefer the full value resolved from the live DOM
189
+ // (above); fall back to parsing it out of axe's node.html,
190
+ // which axe truncates and can corrupt the XPath.
191
+ const xPath = fullXPathByTargetKey[JSON.stringify(node.target)]
192
+ || (0, xPath_1.getAttributeXPath)(node.html);
193
+ (0, standard_1.addInstance)(standardResult, {
194
+ ruleID: rule.id,
195
+ what: Array.from(whatSet.values()).join('; '),
196
+ ordinalSeverity,
197
+ outcome: certainty === 'violations' ? 'failed' : 'cantTell',
198
+ catalogIndex: (0, xPath_1.getXPathCatalogIndex)(report, xPath)
199
+ });
200
+ });
201
+ });
202
+ }
203
+ });
171
204
  }
172
- });
205
+ // Delete the properties of the report details that the detail level excludes, after the
206
+ // standard result has been made from them, so the standard result does not depend on
207
+ // the detail level.
208
+ const irrelevants = ['inapplicable', 'passes', 'incomplete', 'violations']
209
+ .slice(0, 4 - detailLevel);
210
+ irrelevants.forEach(irrelevant => {
211
+ delete axeReport[irrelevant];
212
+ });
173
213
  }
174
- catch(error) {
175
- // Leave the map empty; every instance falls back to node.html below.
214
+ // Otherwise, i.e. if the test failed:
215
+ else {
216
+ // Report this.
217
+ data.prevented = true;
218
+ data.error = 'ERROR: Act failed';
219
+ if (standard) {
220
+ standardResult.prevented = true;
221
+ }
176
222
  }
177
- // For each certainty type:
178
- ['incomplete', 'violations'].forEach(certainty => {
179
- // If there are any suspicions of this type:
180
- if (nativeResult?.details?.[certainty]) {
181
- // For each rule with any suspicions:
182
- nativeResult.details[certainty].forEach(rule => {
183
- // For each element suspected of violating the rule:
184
- rule.nodes.forEach(node => {
185
- // Get descriptions of the rule.
186
- const whatSet = new Set([
187
- rule.help,
188
- ... node.any.map(anyItem => anyItem.message),
189
- ... node.all.map(allItem => allItem.message)
190
- ]);
191
- // Get the ordinal severity of the suspicion.
192
- const ordinalSeverity = severityWeights[node.impact]
193
- + (certainty === 'violations' ? 2 : 0);
194
- // Increment the standard total.
195
- standardResult.totals[ordinalSeverity]++;
196
- // Get the XPath of the suspected element from its data-xpath
197
- // attribute. Prefer the full value resolved from the live DOM
198
- // (above); fall back to parsing it out of axe's node.html,
199
- // which axe truncates and can corrupt the XPath.
200
- const xPath = fullXPathByTargetKey[JSON.stringify(node.target)]
201
- || getAttributeXPath(node.html);
202
- const instance = {
203
- ruleID: rule.id,
204
- what: Array.from(whatSet.values()).join('; '),
205
- ordinalSeverity,
206
- count: 1,
207
- catalogIndex: getXPathCatalogIndex(report, xPath)
208
- };
209
- standardResult.instances.push(instance);
210
- });
211
- });
212
- }
213
- });
214
- }
215
223
  }
216
- // Otherwise, i.e. if the test failed:
217
- else {
218
- // Report this.
219
- data.prevented = true;
220
- data.error = 'ERROR: Act failed';
221
- if (standard) {
222
- standardResult.prevented = true;
223
- }
224
+ // Return the result.
225
+ try {
226
+ JSON.stringify(data);
227
+ }
228
+ catch (error) {
229
+ const message = `ERROR: Axe result cannot be made JSON (${error.message})`;
230
+ console.log(message);
231
+ data = {
232
+ prevented: true,
233
+ error: message
234
+ };
224
235
  }
225
- }
226
- // Return the result.
227
- try {
228
- JSON.stringify(data);
229
- }
230
- catch(error) {
231
- const message = `ERROR: Axe result cannot be made JSON (${error.message})`;
232
- console.log(message);
233
- data = {
234
- prevented: true,
235
- error: message
236
+ return {
237
+ data,
238
+ result
236
239
  };
237
- }
238
- return {
239
- data,
240
- result
241
- };
242
240
  };
241
+ exports.reporter = reporter;