testaro 78.0.6 → 78.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (361) hide show
  1. package/.gitattributes +94 -0
  2. package/.github/workflows/ci.yml +58 -0
  3. package/.github/workflows/publish.yml +49 -0
  4. package/.github/workflows/typescript.yml +35 -0
  5. package/AGENTS.md +2 -2
  6. package/CLAUDE.md +25 -19
  7. package/CONTAINERS.md +10 -6
  8. package/CONTRIBUTING.md +29 -3
  9. package/Dockerfile +1 -1
  10. package/README.md +75 -20
  11. package/UPGRADES.md +4 -0
  12. package/actSpecs-doc.md +13 -1
  13. package/actSpecs.js +29 -5
  14. package/call.js +6 -5
  15. package/docker-compose.yml +8 -2
  16. package/docs/checkpoint-scanning.md +199 -0
  17. package/docs/standard-result-outcome.md +165 -0
  18. package/env.example +44 -10
  19. package/eslint.config.mjs +101 -0
  20. package/netWatch.js +373 -222
  21. package/package.json +46 -31
  22. package/pour/README.md +47 -0
  23. package/pour/pour.min.js +8 -0
  24. package/procs/actDo.js +808 -0
  25. package/procs/catalog.d.ts +17 -0
  26. package/procs/catalog.js +313 -221
  27. package/procs/catalog.ts +398 -0
  28. package/procs/checkpoint.js +110 -0
  29. package/procs/config.d.ts +35 -0
  30. package/procs/config.js +63 -0
  31. package/procs/dateTime.js +2 -1
  32. package/procs/doActs.js +442 -849
  33. package/procs/doTestAct.js +27 -121
  34. package/procs/flow.js +221 -0
  35. package/procs/generateRuleRegistry.js +94 -0
  36. package/procs/getSource.d.ts +26 -0
  37. package/procs/getSource.js +1 -0
  38. package/procs/job.js +116 -1
  39. package/procs/launch.d.ts +40 -0
  40. package/procs/launch.js +239 -108
  41. package/procs/nu.d.ts +48 -0
  42. package/procs/nu.js +1 -0
  43. package/procs/scope.js +196 -0
  44. package/procs/shoot.d.ts +33 -0
  45. package/procs/shoot.js +3 -1
  46. package/procs/standard.d.ts +18 -0
  47. package/procs/standard.js +83 -0
  48. package/procs/standard.ts +126 -0
  49. package/procs/testAct.js +145 -0
  50. package/procs/testaro.d.ts +20 -0
  51. package/procs/testaro.js +237 -189
  52. package/procs/testaro.ts +321 -0
  53. package/procs/userPath.js +126 -0
  54. package/procs/xPath.d.ts +4 -0
  55. package/procs/xPath.js +82 -64
  56. package/procs/xPath.ts +106 -0
  57. package/procs/xPathScript.d.ts +6 -0
  58. package/procs/xPathScript.js +70 -0
  59. package/run.js +3 -2
  60. package/surea11y/README.md +44 -0
  61. package/surea11y/surea11y.browser.js +14 -0
  62. package/testaro/adbID.d.ts +3 -0
  63. package/testaro/adbID.js +39 -41
  64. package/testaro/adbID.ts +66 -0
  65. package/testaro/allCapStyle.d.ts +3 -0
  66. package/testaro/allCapStyle.js +32 -34
  67. package/testaro/allCapStyle.ts +55 -0
  68. package/testaro/allCaps.d.ts +16 -0
  69. package/testaro/allCaps.js +179 -151
  70. package/testaro/allCaps.ts +228 -0
  71. package/testaro/allHidden.d.ts +13 -0
  72. package/testaro/allHidden.js +30 -30
  73. package/testaro/allHidden.ts +50 -0
  74. package/testaro/allSlanted.d.ts +3 -0
  75. package/testaro/allSlanted.js +31 -33
  76. package/testaro/allSlanted.ts +54 -0
  77. package/testaro/altScheme.d.ts +3 -0
  78. package/testaro/altScheme.js +28 -30
  79. package/testaro/altScheme.ts +50 -0
  80. package/testaro/attVal.d.ts +3 -0
  81. package/testaro/attVal.js +21 -21
  82. package/testaro/attVal.ts +52 -0
  83. package/testaro/autocomplete.d.ts +3 -0
  84. package/testaro/autocomplete.js +60 -75
  85. package/testaro/autocomplete.ts +101 -0
  86. package/testaro/bulk.d.ts +13 -0
  87. package/testaro/bulk.js +33 -33
  88. package/testaro/bulk.ts +55 -0
  89. package/testaro/buttonMenu.d.ts +9 -0
  90. package/testaro/buttonMenu.js +318 -319
  91. package/testaro/buttonMenu.ts +391 -0
  92. package/testaro/captionLoc.d.ts +3 -0
  93. package/testaro/captionLoc.js +18 -20
  94. package/testaro/captionLoc.ts +40 -0
  95. package/testaro/datalistRef.d.ts +3 -0
  96. package/testaro/datalistRef.js +34 -36
  97. package/testaro/datalistRef.ts +55 -0
  98. package/testaro/distortion.d.ts +3 -0
  99. package/testaro/distortion.js +58 -26
  100. package/testaro/distortion.ts +81 -0
  101. package/testaro/docType.d.ts +15 -0
  102. package/testaro/docType.js +26 -25
  103. package/testaro/docType.ts +45 -0
  104. package/testaro/dupAtt.d.ts +16 -0
  105. package/testaro/dupAtt.js +114 -104
  106. package/testaro/dupAtt.ts +144 -0
  107. package/testaro/elements.d.ts +6 -0
  108. package/testaro/elements.js +153 -153
  109. package/testaro/elements.ts +215 -0
  110. package/testaro/embAc.d.ts +3 -0
  111. package/testaro/embAc.js +20 -20
  112. package/testaro/embAc.ts +40 -0
  113. package/testaro/focAll.d.ts +13 -0
  114. package/testaro/focAll.js +186 -191
  115. package/testaro/focAll.ts +217 -0
  116. package/testaro/focAndOp.d.ts +3 -0
  117. package/testaro/focAndOp.js +101 -104
  118. package/testaro/focAndOp.ts +128 -0
  119. package/testaro/focInd.d.ts +3 -0
  120. package/testaro/focInd.js +65 -66
  121. package/testaro/focInd.ts +96 -0
  122. package/testaro/focVis.d.ts +3 -0
  123. package/testaro/focVis.js +29 -30
  124. package/testaro/focVis.ts +52 -0
  125. package/testaro/headEl.d.ts +10 -0
  126. package/testaro/headEl.js +62 -62
  127. package/testaro/headEl.ts +82 -0
  128. package/testaro/headingAmb.d.ts +3 -0
  129. package/testaro/headingAmb.js +55 -63
  130. package/testaro/headingAmb.ts +72 -0
  131. package/testaro/hovInd.d.ts +12 -0
  132. package/testaro/hovInd.js +164 -130
  133. package/testaro/hovInd.ts +199 -0
  134. package/testaro/hover.d.ts +3 -0
  135. package/testaro/hover.js +156 -126
  136. package/testaro/hover.ts +154 -0
  137. package/testaro/hr.d.ts +3 -0
  138. package/testaro/hr.js +15 -17
  139. package/testaro/hr.ts +36 -0
  140. package/testaro/imageLink.d.ts +3 -0
  141. package/testaro/imageLink.js +18 -20
  142. package/testaro/imageLink.ts +42 -0
  143. package/testaro/labClash.d.ts +3 -0
  144. package/testaro/labClash.js +32 -33
  145. package/testaro/labClash.ts +54 -0
  146. package/testaro/legendLoc.d.ts +3 -0
  147. package/testaro/legendLoc.js +18 -20
  148. package/testaro/legendLoc.ts +42 -0
  149. package/testaro/lineHeight.d.ts +3 -0
  150. package/testaro/lineHeight.js +44 -48
  151. package/testaro/lineHeight.ts +70 -0
  152. package/testaro/linkAmb.d.ts +7 -0
  153. package/testaro/linkAmb.js +80 -80
  154. package/testaro/linkAmb.ts +105 -0
  155. package/testaro/linkExt.d.ts +3 -0
  156. package/testaro/linkExt.js +14 -16
  157. package/testaro/linkExt.ts +35 -0
  158. package/testaro/linkOldAtt.d.ts +3 -0
  159. package/testaro/linkOldAtt.js +26 -28
  160. package/testaro/linkOldAtt.ts +48 -0
  161. package/testaro/linkTo.d.ts +3 -0
  162. package/testaro/linkTo.js +23 -22
  163. package/testaro/linkTo.ts +43 -0
  164. package/testaro/linkUl.d.ts +3 -0
  165. package/testaro/linkUl.js +31 -34
  166. package/testaro/linkUl.ts +54 -0
  167. package/testaro/miniText.d.ts +3 -0
  168. package/testaro/miniText.js +42 -44
  169. package/testaro/miniText.ts +68 -0
  170. package/testaro/motion.d.ts +10 -0
  171. package/testaro/motion.js +93 -96
  172. package/testaro/motion.ts +125 -0
  173. package/testaro/nonTable.d.ts +3 -0
  174. package/testaro/nonTable.js +40 -45
  175. package/testaro/nonTable.ts +66 -0
  176. package/testaro/optRoleSel.d.ts +3 -0
  177. package/testaro/optRoleSel.js +17 -19
  178. package/testaro/optRoleSel.ts +41 -0
  179. package/testaro/phOnly.d.ts +3 -0
  180. package/testaro/phOnly.js +19 -21
  181. package/testaro/phOnly.ts +43 -0
  182. package/testaro/pseudoP.d.ts +3 -0
  183. package/testaro/pseudoP.js +37 -38
  184. package/testaro/pseudoP.ts +59 -0
  185. package/testaro/radioSet.d.ts +3 -0
  186. package/testaro/radioSet.js +58 -59
  187. package/testaro/radioSet.ts +79 -0
  188. package/testaro/registry.d.ts +63 -0
  189. package/testaro/registry.js +67 -0
  190. package/testaro/registry.ts +141 -0
  191. package/testaro/role.d.ts +3 -0
  192. package/testaro/role.js +28 -29
  193. package/testaro/role.ts +53 -0
  194. package/testaro/secHeading.d.ts +3 -0
  195. package/testaro/secHeading.js +31 -33
  196. package/testaro/secHeading.ts +53 -0
  197. package/testaro/styleDiff.d.ts +25 -0
  198. package/testaro/styleDiff.js +249 -252
  199. package/testaro/styleDiff.ts +303 -0
  200. package/testaro/tabNav.d.ts +33 -0
  201. package/testaro/tabNav.js +273 -342
  202. package/testaro/tabNav.ts +454 -0
  203. package/testaro/targetsNear.d.ts +9 -0
  204. package/testaro/targetsNear.js +131 -132
  205. package/testaro/targetsNear.ts +160 -0
  206. package/testaro/textNodes.d.ts +6 -0
  207. package/testaro/textNodes.js +139 -135
  208. package/testaro/textNodes.ts +185 -0
  209. package/testaro/textSem.d.ts +3 -0
  210. package/testaro/textSem.js +26 -28
  211. package/testaro/textSem.ts +47 -0
  212. package/testaro/title.d.ts +9 -0
  213. package/testaro/title.js +16 -13
  214. package/testaro/title.ts +31 -0
  215. package/testaro/titledEl.d.ts +3 -0
  216. package/testaro/titledEl.js +16 -18
  217. package/testaro/titledEl.ts +38 -0
  218. package/testaro/zIndex.d.ts +3 -0
  219. package/testaro/zIndex.js +20 -22
  220. package/testaro/zIndex.ts +42 -0
  221. package/tests/alfa.d.ts +45 -0
  222. package/tests/alfa.js +139 -141
  223. package/tests/alfa.ts +214 -0
  224. package/tests/aslint.d.ts +33 -0
  225. package/tests/aslint.js +273 -249
  226. package/tests/aslint.ts +301 -0
  227. package/tests/axe.d.ts +27 -0
  228. package/tests/axe.js +200 -200
  229. package/tests/axe.ts +277 -0
  230. package/tests/ed11y.d.ts +28 -0
  231. package/tests/ed11y.js +142 -99
  232. package/tests/ed11y.ts +178 -0
  233. package/tests/htmlcs.d.ts +21 -0
  234. package/tests/htmlcs.js +175 -140
  235. package/tests/htmlcs.ts +181 -0
  236. package/tests/ibm.d.ts +52 -0
  237. package/tests/ibm.js +165 -166
  238. package/tests/ibm.ts +251 -0
  239. package/tests/nuVal.d.ts +13 -0
  240. package/tests/nuVal.js +107 -112
  241. package/tests/nuVal.ts +145 -0
  242. package/tests/nuVnu.d.ts +15 -0
  243. package/tests/nuVnu.js +142 -111
  244. package/tests/nuVnu.ts +144 -0
  245. package/tests/pour.d.ts +31 -0
  246. package/tests/pour.js +242 -0
  247. package/tests/pour.ts +273 -0
  248. package/tests/qualWeb.d.ts +39 -0
  249. package/tests/qualWeb.js +303 -272
  250. package/tests/qualWeb.ts +415 -0
  251. package/tests/surea11y.d.ts +33 -0
  252. package/tests/surea11y.js +288 -0
  253. package/tests/surea11y.ts +334 -0
  254. package/tests/testaro.d.ts +25 -0
  255. package/tests/testaro.js +746 -652
  256. package/tests/testaro.ts +862 -0
  257. package/tests/wave.d.ts +46 -0
  258. package/tests/wave.js +167 -177
  259. package/tests/wave.ts +252 -0
  260. package/tsconfig.json +17 -0
  261. package/types.d.ts +243 -0
  262. package/types.js +10 -0
  263. package/types.ts +376 -0
  264. package/validation/act/README.md +46 -0
  265. package/validation/act/capture.js +424 -0
  266. package/validation/act/chromium-issue-draft.md +66 -0
  267. package/validation/act/fp-triage-2026-08-22.md +86 -0
  268. package/validation/act/isolation-notes.md +159 -0
  269. package/validation/act/playwright-issue-draft.md +73 -0
  270. package/validation/act/propose-mappings.js +0 -0
  271. package/validation/act/repro-cdp-raw.js +105 -0
  272. package/validation/act/repro-metarefresh.js +65 -0
  273. package/validation/act/score.js +184 -0
  274. package/validation/act/stage3a-stress-report.md +69 -0
  275. package/validation/act/stage3b-mapping-proposals.md +94 -0
  276. package/validation/act/stage3b-triage-draft.md +138 -0
  277. package/validation/act/surea11y-track-a-2026-09-01.md +50 -0
  278. package/validation/executors/netWatch.js +180 -90
  279. package/validation/executors/test.js +17 -2
  280. package/validation/executors/tests.js +118 -10
  281. package/validation/jobs/reports/raw/260901T1000-surea11y-validation.json +964 -0
  282. package/validation/jobs/todo/240101T1200-simple-example.json +14 -6
  283. package/validation/jobs/todo/240101T1300-shoot-example.json +2 -1
  284. package/validation/jobs/todo/260821T1900-pour-validation.json +45 -0
  285. package/validation/jobs/todo/260901T1000-surea11y-validation.json +45 -0
  286. package/validation/knownFailures.json +1 -0
  287. package/validation/tests/jobProperties/adbID.json +27 -2
  288. package/validation/tests/jobProperties/{focOp.json → allCapStyle.json} +56 -53
  289. package/validation/tests/jobProperties/allCaps.json +25 -0
  290. package/validation/tests/jobProperties/allHidden.json +133 -13
  291. package/validation/tests/jobProperties/allSlanted.json +3 -3
  292. package/validation/tests/jobProperties/altScheme.json +23 -8
  293. package/validation/tests/jobProperties/attVal.json +57 -57
  294. package/validation/tests/jobProperties/autocomplete.json +11 -1
  295. package/validation/tests/jobProperties/bulk.json +6 -1
  296. package/validation/tests/jobProperties/buttonMenu.json +63 -42
  297. package/validation/tests/jobProperties/captionLoc.json +1 -6
  298. package/validation/tests/jobProperties/checkpoint-browser.json +401 -0
  299. package/validation/tests/jobProperties/checkpoint-page.json +397 -0
  300. package/validation/tests/jobProperties/checkpoint.json +395 -0
  301. package/validation/tests/jobProperties/datalistRef.json +20 -5
  302. package/validation/tests/jobProperties/distortion.json +28 -3
  303. package/validation/tests/jobProperties/docType.json +2 -2
  304. package/validation/tests/jobProperties/dupAtt.json +48 -33
  305. package/validation/tests/jobProperties/elements.json +28 -28
  306. package/validation/tests/jobProperties/embAc.json +36 -31
  307. package/validation/tests/jobProperties/focAndOp.json +284 -0
  308. package/validation/tests/jobProperties/focInd.json +34 -34
  309. package/validation/tests/jobProperties/focVis.json +1 -1
  310. package/validation/tests/jobProperties/hover.json +39 -37
  311. package/validation/tests/jobProperties/hr.json +13 -3
  312. package/validation/tests/jobProperties/imageLink.json +0 -5
  313. package/validation/tests/jobProperties/labClash.json +68 -33
  314. package/validation/tests/jobProperties/legendLoc.json +1 -6
  315. package/validation/tests/jobProperties/lineHeight.json +2 -2
  316. package/validation/tests/jobProperties/linkAmb.json +13 -18
  317. package/validation/tests/jobProperties/linkExt.json +1 -1
  318. package/validation/tests/jobProperties/linkOldAtt.json +12 -2
  319. package/validation/tests/jobProperties/linkTo.json +1 -1
  320. package/validation/tests/jobProperties/linkUl.json +65 -65
  321. package/validation/tests/jobProperties/miniText.json +7 -2
  322. package/validation/tests/jobProperties/motion.json +4 -50
  323. package/validation/tests/jobProperties/nonTable.json +48 -3
  324. package/validation/tests/jobProperties/optRoleSel.json +12 -2
  325. package/validation/tests/jobProperties/phOnly.json +6 -16
  326. package/validation/tests/jobProperties/pseudoP.json +17 -2
  327. package/validation/tests/jobProperties/radioSet.json +30 -30
  328. package/validation/tests/jobProperties/role.json +25 -5
  329. package/validation/tests/jobProperties/secHeading.json +26 -21
  330. package/validation/tests/jobProperties/styleDiff.json +35 -5
  331. package/validation/tests/jobProperties/tabNav.json +3 -1
  332. package/validation/tests/jobProperties/targetsNear.json +237 -0
  333. package/validation/tests/jobProperties/textNodes.json +29 -29
  334. package/validation/tests/jobProperties/textSem.json +26 -1
  335. package/validation/tests/jobProperties/title.json +12 -2
  336. package/validation/tests/jobProperties/titledEl.json +39 -9
  337. package/validation/tests/jobProperties/userPath.json +317 -0
  338. package/validation/tests/jobProperties/zIndex.json +40 -35
  339. package/validation/tests/targets/allCapStyle/index.html +26 -0
  340. package/validation/tests/targets/checkpoint/index.html +38 -0
  341. package/validation/tests/targets/datalistRef/index.html +1 -1
  342. package/validation/tests/targets/focAndOp/bad.html +29 -0
  343. package/validation/tests/targets/{focOp → focAndOp}/good.html +3 -1
  344. package/validation/tests/targets/focInd/bad.html +2 -1
  345. package/validation/tests/targets/headEl/index.html +10 -1
  346. package/validation/tests/targets/{targetSmall → targetsNear}/index.html +15 -1
  347. package/validation/tests/targets/userPath/index.html +42 -0
  348. package/validation/validateTest.js +62 -10
  349. package/.claude/settings.local.json +0 -11
  350. package/.eslintrc.json +0 -41
  351. package/htmlcs/.eslintrc.json +0 -67
  352. package/memory/MEMORY.md +0 -3
  353. package/memory/project_validation_pause.md +0 -10
  354. package/validation/tests/jobProperties/linkTitle.json +0 -127
  355. package/validation/tests/jobProperties/opFoc.json +0 -164
  356. package/validation/tests/jobProperties/targetSmall.json +0 -152
  357. package/validation/tests/jobProperties/targetTiny.json +0 -142
  358. package/validation/tests/targets/focOp/bad.html +0 -25
  359. package/validation/tests/targets/linkTitle/index.html +0 -24
  360. package/validation/tests/targets/opFoc/bad.html +0 -26
  361. package/validation/tests/targets/opFoc/good.html +0 -23
package/tests/qualWeb.js CHANGED
@@ -1,5 +1,7 @@
1
+ "use strict";
1
2
  /*
2
3
  © 2023–2024 CVS Health and/or one of its affiliates. All rights reserved.
4
+ © 2026 Jeff Witt.
3
5
  © 2025–2026 Jonathan Robert Pool.
4
6
 
5
7
  Licensed under the MIT License. See LICENSE file at the project root or
@@ -7,297 +9,326 @@
7
9
 
8
10
  SPDX-License-Identifier: MIT
9
11
  */
10
-
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");
11
16
  /*
12
- qualWeb
13
- Implements the QualWeb ruleset for accessibility.
17
+ The @qualweb packages declare their types only in package-exports maps, which
18
+ this project's node10 module resolution cannot read, so the imports stay
19
+ requires and are untyped.
14
20
  */
15
-
16
- // IMPORTS
17
-
18
- const {QualWeb} = require('@qualweb/core');
19
- const {ACTRules} = require('@qualweb/act-rules');
20
- const {WCAGTechniques} = require('@qualweb/wcag-techniques');
21
- const {BestPractices} = require('@qualweb/best-practices');
22
- const {PlaywrightDriver} = require('@qualweb/playwright-driver');
23
- const {getAttributeXPath, getXPathCatalogIndex} = require('../procs/xPath');
24
-
25
- // CONSTANTS
26
-
27
- // QualWeb core engine with Playwright as driver.
28
- const qualWeb = new QualWeb(undefined, new PlaywrightDriver({
29
- adBlock: true,
30
- stealth: true
31
- }));
21
+ const { QualWeb } = require('@qualweb/core');
22
+ const { ACTRules } = require('@qualweb/act-rules');
23
+ const { WCAGTechniques } = require('@qualweb/wcag-techniques');
24
+ const { BestPractices } = require('@qualweb/best-practices');
25
+ const { PlaywrightDriver } = require('@qualweb/playwright-driver');
26
+ const config_1 = require("../procs/config");
27
+ const qualWebInstances = {};
28
+ const getQualWeb = (options) => {
29
+ const key = `${options.stealth}:${options.adBlock}`;
30
+ if (!qualWebInstances[key]) {
31
+ let launcher;
32
+ if (options.stealth) {
33
+ const { chromium } = require('playwright-extra');
34
+ chromium.use(require('puppeteer-extra-plugin-stealth')());
35
+ launcher = chromium;
36
+ }
37
+ const qualWeb = new QualWeb(undefined, new PlaywrightDriver(launcher ? { launcher } : {}));
38
+ if (options.adBlock) {
39
+ const { PlaywrightBlocker } = require('@ghostery/adblocker-playwright');
40
+ let blockerPromise = null;
41
+ qualWeb.use({
42
+ async beforePageLoad(page) {
43
+ blockerPromise ??= PlaywrightBlocker.fromPrebuiltAdsAndTracking(fetch, {
44
+ path: require('path').join(require('os').tmpdir(), 'qualweb-adblocker-engine.bin'),
45
+ read: require('fs').promises.readFile,
46
+ write: require('fs').promises.writeFile
47
+ }).catch((error) => {
48
+ console.log(`qualWeb: ad blocker unavailable, continuing without it (${error.message})`);
49
+ return null;
50
+ });
51
+ const blocker = await blockerPromise;
52
+ if (blocker) {
53
+ await blocker.enableBlockingInPage(page.nativePage);
54
+ }
55
+ }
56
+ });
57
+ }
58
+ qualWebInstances[key] = qualWeb;
59
+ }
60
+ return qualWebInstances[key];
61
+ };
32
62
  const actRulesModule = new ACTRules({});
33
63
  const wcagModule = new WCAGTechniques({});
34
64
  const bpModule = new BestPractices({});
35
65
  // Mapping of QualWeb module violation types to ordinal severities.
36
66
  const ordinalSeverities = {
37
- 'act-rules': {
38
- 'warning': 1,
39
- 'failed': 3
40
- },
41
- 'wcag-techniques': {
42
- 'warning': 0,
43
- 'failed': 2
44
- },
45
- 'best-practices': {
46
- 'warning': 0,
47
- 'failed': 1
48
- }
49
- }
50
-
67
+ 'act-rules': {
68
+ 'warning': 1,
69
+ 'failed': 3
70
+ },
71
+ 'wcag-techniques': {
72
+ 'warning': 0,
73
+ 'failed': 2
74
+ },
75
+ 'best-practices': {
76
+ 'warning': 0,
77
+ 'failed': 1
78
+ }
79
+ };
80
+ /*
81
+ qualWeb
82
+ Implements the QualWeb ruleset for accessibility.
83
+ Compiled to qualWeb.js by tsc (issue #73); edit this file, not the emitted one.
84
+ */
51
85
  // FUNCTIONS
52
-
53
86
  // Conducts and reports the QualWeb tests.
54
- exports.reporter = async (page, report, actIndex, timeLimit) => {
55
- const act = report.acts[actIndex];
56
- const {rules} = act;
57
- const clusterOptions = {
58
- maxConcurrency: 1,
59
- timeout: timeLimit * 1000,
60
- monitor: false
61
- };
62
- // Initialize the act report.
63
- const data = {};
64
- const result = {
65
- nativeResult: {},
66
- standardResult: {}
67
- };
68
- const standard = report.standard !== 'no';
69
- // If standard results are to be reported:
70
- if (standard) {
71
- // Initialize the standard result.
72
- result.standardResult = {
73
- prevented: false,
74
- totals: [0, 0, 0, 0],
75
- instances: []
87
+ const reporter = async (page, report, actIndex, timeLimit) => {
88
+ const qualWebAct = report.acts[actIndex];
89
+ const qualWeb = getQualWeb({
90
+ stealth: qualWebAct.stealth ?? config_1.qualWebDefaults.stealth,
91
+ adBlock: qualWebAct.adBlock ?? config_1.qualWebDefaults.adBlock
92
+ });
93
+ const act = report.acts[actIndex];
94
+ const { rules } = act;
95
+ const clusterOptions = {
96
+ maxConcurrency: 1,
97
+ timeout: timeLimit * 1000,
98
+ monitor: false
76
99
  };
77
- }
78
- try {
79
- // Start the QualWeb core engine, which launches a Playwright browser.
80
- await qualWeb.start(clusterOptions);
81
- }
82
- // If the start fails:
83
- catch(error) {
84
- return {
85
- data: {
86
- prevented: true,
87
- error: `Core engine start failed (${error.message})`
88
- },
89
- result
100
+ // Initialize the act report.
101
+ const data = {};
102
+ const result = {
103
+ nativeResult: {},
104
+ standardResult: {}
90
105
  };
91
- }
92
- // Otherwise, i.e. if the start succeeds, specify the invariant test options.
93
- const qualWebOptions = {
94
- log: {
95
- console: false,
96
- file: false
97
- },
98
- crawlOptions: {
99
- maxDepth: 0,
100
- maxUrls: 1,
101
- timeout: timeLimit * 1000,
102
- maxParallelCrawls: 1,
103
- logging: true
104
- },
105
- execute: {
106
- counter: true
107
- },
108
- modules: []
109
- };
110
- try {
111
- // Provide the page content, including the data-xpath attributes.
112
- qualWebOptions.html = await page.content();
113
- // Specify which rules to test for, adding a custom execute property for report processing.
114
- const actSpec = rules ? rules.find(typeRules => typeRules.startsWith('act:')) : null;
115
- const wcagSpec = rules ? rules.find(typeRules => typeRules.startsWith('wcag:')) : null;
116
- const bestSpec = rules ? rules.find(typeRules => typeRules.startsWith('best:')) : null;
117
- if (actSpec) {
118
- if (actSpec === 'act:') {
119
- qualWebOptions.execute.act = false;
120
- }
121
- else {
122
- const actRules = actSpec.slice(4).split(',').map(num => `QW-ACT-R${num}`);
123
- qualWebOptions['act-rules'] = {rules: actRules};
124
- qualWebOptions.modules.push(actRulesModule);
125
- qualWebOptions.execute.act = true;
126
- }
127
- }
128
- else {
129
- qualWebOptions['act-rules'] = {
130
- levels: ['A', 'AA', 'AAA'],
131
- principles: ['Perceivable', 'Operable', 'Understandable', 'Robust']
132
- };
133
- qualWebOptions.modules.push(actRulesModule);
134
- qualWebOptions.execute.act = true;
135
- }
136
- if (wcagSpec) {
137
- if (wcagSpec === 'wcag:') {
138
- qualWebOptions.execute.wcag = false;
139
- }
140
- else {
141
- const wcagTechniques = wcagSpec.slice(5).split(',').map(num => `QW-WCAG-T${num}`);
142
- qualWebOptions['wcag-techniques'] = {techniques: wcagTechniques};
143
- qualWebOptions.modules.push(wcagModule);
144
- qualWebOptions.execute.wcag = true;
145
- }
106
+ const standard = report.standard !== 'no';
107
+ // If standard results are to be reported:
108
+ if (standard) {
109
+ // Initialize the standard result.
110
+ result.standardResult = (0, standard_1.getStandardResult)();
146
111
  }
147
- else {
148
- qualWebOptions['wcag-techniques'] = {
149
- levels: ['A', 'AA', 'AAA'],
150
- principles: ['Perceivable', 'Operable', 'Understandable', 'Robust']
151
- };
152
- qualWebOptions.modules.push(wcagModule);
153
- qualWebOptions.execute.wcag = true;
154
- }
155
- if (bestSpec) {
156
- if (bestSpec === 'best:') {
157
- qualWebOptions.execute.bp = false;
158
- }
159
- else {
160
- const bestPractices = bestSpec.slice(5).split(',').map(num => `QW-BP${num}`);
161
- qualWebOptions['best-practices'] = {bestPractices};
162
- qualWebOptions.modules.push(bpModule);
163
- qualWebOptions.execute.bp = true;
164
- }
165
- }
166
- else {
167
- qualWebOptions['best-practices'] = {};
168
- qualWebOptions.modules.push(bpModule);
169
- qualWebOptions.execute.bp = true;
170
- }
171
- let qwReport;
172
112
  try {
173
- // Get the report.
174
- qwReport = await qualWeb.evaluate(qualWebOptions);
113
+ // Start the QualWeb core engine, which launches a Playwright browser.
114
+ await qualWeb.start(clusterOptions);
175
115
  }
176
- catch(error) {
177
- return {
178
- data: {
179
- prevented: true,
180
- error: `qualWeb evaluation failed (${error.message})`
181
- },
182
- result
183
- };
116
+ // If the start fails:
117
+ catch (error) {
118
+ return {
119
+ data: {
120
+ prevented: true,
121
+ error: `Core engine start failed (${error.message})`
122
+ },
123
+ result
124
+ };
184
125
  }
185
- // Add the report to the result.
186
- result.nativeResult = qwReport.customHtml;
187
- const {nativeResult, standardResult} = result;
188
- // If the report contains, as it should, a copy of the DOM:
189
- if (nativeResult?.system?.page?.dom) {
190
- // Delete the copy for parsimony.
191
- delete nativeResult.system.page.dom;
192
- const {modules} = nativeResult;
193
- // If the report contains, as it should, a modules property:
194
- if (modules) {
195
- // For each test section in it:
196
- for (const section of ['act-rules', 'wcag-techniques', 'best-practices']) {
197
- // If testing in the section was specified:
198
- if (qualWebOptions[section]) {
199
- // If the section exists:
200
- if (modules[section]) {
201
- const {assertions} = modules[section];
202
- // If it contains assertions (test results):
203
- if (assertions) {
204
- const ruleIDs = Object.keys(assertions);
205
- // For each rule:
206
- for (const ruleID of ruleIDs) {
207
- const ruleAssertions = assertions[ruleID];
208
- const {metadata} = ruleAssertions;
209
- // If there were any warnings or failures:
210
- if (metadata?.warning || metadata?.failed) {
211
- // Delete nonviolations from the results.
212
- ruleAssertions.results = ruleAssertions.results.filter(
213
- raResult => raResult.verdict !== 'passed'
214
- );
215
- // For each test result:
216
- for (const raResult of ruleAssertions.results) {
217
- const {elements, verdict} = raResult;
218
- // If any violations are reported:
219
- if (elements?.length) {
220
- // For each violating element:
221
- for (const element of elements) {
222
- // Limit the size of its reported excerpt.
223
- if (element.htmlCode?.length > 2000) {
224
- element.htmlCode = `${element.htmlCode.slice(0, 2000)} …`;
225
- }
226
- // If standard results are to be reported:
227
- if (standard) {
228
- const ordinalSeverity = ordinalSeverities[section][verdict];
229
- // Increment the applicable total.
230
- standardResult.totals[ordinalSeverity]++;
231
- // Initialize a standard instance.
232
- const what = `[${verdict}] ${raResult.description}`;
233
- const xPath = getAttributeXPath(element.htmlCode);
234
- const instance = {
235
- ruleID,
236
- what,
237
- ordinalSeverity: ordinalSeverities[section][verdict],
238
- count: 1,
239
- catalogIndex: getXPathCatalogIndex(report, xPath)
240
- };
241
- // Add the instance to the standard result.
242
- standardResult.instances.push(instance);
243
- }
244
- };
245
- }
246
- };
247
- }
248
- // Otherwise, i.e. if there were no warnings or failures:
249
- else {
250
- // Delete the rule.
251
- delete assertions[ruleID];
252
- }
253
- };
254
- }
255
- // Otherwise, i.e. if it contains no assertions:
256
- else {
257
- // Report this.
258
- data.prevented = true;
259
- data.error = 'No assertions';
260
- }
126
+ // Otherwise, i.e. if the start succeeds, specify the invariant test options.
127
+ const qualWebOptions = {
128
+ log: {
129
+ console: false,
130
+ file: false
131
+ },
132
+ crawlOptions: {
133
+ maxDepth: 0,
134
+ maxUrls: 1,
135
+ timeout: timeLimit * 1000,
136
+ maxParallelCrawls: 1,
137
+ logging: true
138
+ },
139
+ execute: {
140
+ counter: true
141
+ },
142
+ modules: []
143
+ };
144
+ try {
145
+ // Provide the page content, including the data-xpath attributes.
146
+ qualWebOptions.html = await page.content();
147
+ // Specify which rules to test for, adding a custom execute property for report processing.
148
+ const actSpec = rules ? rules.find(typeRules => typeRules.startsWith('act:')) : null;
149
+ const wcagSpec = rules ? rules.find(typeRules => typeRules.startsWith('wcag:')) : null;
150
+ const bestSpec = rules ? rules.find(typeRules => typeRules.startsWith('best:')) : null;
151
+ if (actSpec) {
152
+ if (actSpec === 'act:') {
153
+ qualWebOptions.execute.act = false;
261
154
  }
262
- // Otherwise, i.e. if the section is missing:
263
155
  else {
264
- // Report this.
265
- data.prevented = true;
266
- data.error = `No ${section} section`;
156
+ const actRules = actSpec.slice(4).split(',').map(num => `QW-ACT-R${num}`);
157
+ qualWebOptions['act-rules'] = { rules: actRules };
158
+ qualWebOptions.modules.push(actRulesModule);
159
+ qualWebOptions.execute.act = true;
267
160
  }
268
- }
269
161
  }
270
- }
271
- // Otherwise, i.e. if the report does not contain a modules property:
272
- else {
273
- // Report this.
274
- data.prevented = true;
275
- data.error = 'No modules';
276
- }
277
- }
278
- // Otherwise, i.e. if the report does not contain a copy of the DOM:
279
- else {
280
- // Report this.
281
- data.prevented = true;
282
- data.error = 'No DOM';
283
- }
284
- // Stop the QualWeb core engine.
285
- await qualWeb.stop();
286
- // Test whether the result is an object.
287
- try {
288
- JSON.stringify(result);
162
+ else {
163
+ qualWebOptions['act-rules'] = {
164
+ levels: ['A', 'AA', 'AAA'],
165
+ principles: ['Perceivable', 'Operable', 'Understandable', 'Robust']
166
+ };
167
+ qualWebOptions.modules.push(actRulesModule);
168
+ qualWebOptions.execute.act = true;
169
+ }
170
+ if (wcagSpec) {
171
+ if (wcagSpec === 'wcag:') {
172
+ qualWebOptions.execute.wcag = false;
173
+ }
174
+ else {
175
+ const wcagTechniques = wcagSpec.slice(5).split(',').map(num => `QW-WCAG-T${num}`);
176
+ qualWebOptions['wcag-techniques'] = { techniques: wcagTechniques };
177
+ qualWebOptions.modules.push(wcagModule);
178
+ qualWebOptions.execute.wcag = true;
179
+ }
180
+ }
181
+ else {
182
+ qualWebOptions['wcag-techniques'] = {
183
+ levels: ['A', 'AA', 'AAA'],
184
+ principles: ['Perceivable', 'Operable', 'Understandable', 'Robust']
185
+ };
186
+ qualWebOptions.modules.push(wcagModule);
187
+ qualWebOptions.execute.wcag = true;
188
+ }
189
+ if (bestSpec) {
190
+ if (bestSpec === 'best:') {
191
+ qualWebOptions.execute.bp = false;
192
+ }
193
+ else {
194
+ const bestPractices = bestSpec.slice(5).split(',').map(num => `QW-BP${num}`);
195
+ qualWebOptions['best-practices'] = { bestPractices };
196
+ qualWebOptions.modules.push(bpModule);
197
+ qualWebOptions.execute.bp = true;
198
+ }
199
+ }
200
+ else {
201
+ qualWebOptions['best-practices'] = {};
202
+ qualWebOptions.modules.push(bpModule);
203
+ qualWebOptions.execute.bp = true;
204
+ }
205
+ let qwReport;
206
+ try {
207
+ // Get the report.
208
+ qwReport = await qualWeb.evaluate(qualWebOptions);
209
+ }
210
+ catch (error) {
211
+ return {
212
+ data: {
213
+ prevented: true,
214
+ error: `qualWeb evaluation failed (${error.message})`
215
+ },
216
+ result
217
+ };
218
+ }
219
+ // Add the report to the result.
220
+ result.nativeResult = qwReport.customHtml;
221
+ const { nativeResult, standardResult } = result;
222
+ // If the report contains, as it should, a copy of the DOM:
223
+ if (nativeResult?.system?.page?.dom) {
224
+ // Delete the copy for parsimony.
225
+ delete nativeResult.system.page.dom;
226
+ const { modules } = nativeResult;
227
+ // If the report contains, as it should, a modules property:
228
+ if (modules) {
229
+ // For each test section in it:
230
+ for (const section of ['act-rules', 'wcag-techniques', 'best-practices']) {
231
+ // If testing in the section was specified:
232
+ if (qualWebOptions[section]) {
233
+ // If the section exists:
234
+ if (modules[section]) {
235
+ const { assertions } = modules[section];
236
+ // If it contains assertions (test results):
237
+ if (assertions) {
238
+ const ruleIDs = Object.keys(assertions);
239
+ // For each rule:
240
+ for (const ruleID of ruleIDs) {
241
+ const ruleAssertions = assertions[ruleID];
242
+ const { metadata } = ruleAssertions;
243
+ // If there were any warnings or failures:
244
+ if (metadata?.warning || metadata?.failed) {
245
+ // Delete nonviolations from the results.
246
+ ruleAssertions.results = ruleAssertions.results.filter(raResult => raResult.verdict !== 'passed');
247
+ // For each test result:
248
+ for (const raResult of ruleAssertions.results) {
249
+ const { elements, verdict } = raResult;
250
+ // If any violations are reported:
251
+ if (elements?.length) {
252
+ // For each violating element:
253
+ for (const element of elements) {
254
+ // Limit the size of its reported excerpt.
255
+ if (element.htmlCode?.length > 2000) {
256
+ element.htmlCode = `${element.htmlCode.slice(0, 2000)} …`;
257
+ }
258
+ // If standard results are to be reported:
259
+ if (standard) {
260
+ const what = `[${verdict}] ${raResult.description}`;
261
+ const xPath = (0, xPath_1.getAttributeXPath)(element.htmlCode);
262
+ // Add an instance to the standard result.
263
+ (0, standard_1.addInstance)(standardResult, {
264
+ ruleID,
265
+ what,
266
+ ordinalSeverity: ordinalSeverities[section][verdict],
267
+ outcome: verdict === 'warning' ? 'cantTell' : 'failed',
268
+ catalogIndex: (0, xPath_1.getXPathCatalogIndex)(report, xPath)
269
+ });
270
+ }
271
+ }
272
+ ;
273
+ }
274
+ }
275
+ ;
276
+ }
277
+ // Otherwise, i.e. if there were no warnings or failures:
278
+ else {
279
+ // Delete the rule.
280
+ delete assertions[ruleID];
281
+ }
282
+ }
283
+ ;
284
+ }
285
+ // Otherwise, i.e. if it contains no assertions:
286
+ else {
287
+ // Report this.
288
+ data.prevented = true;
289
+ data.error = 'No assertions';
290
+ }
291
+ }
292
+ // Otherwise, i.e. if the section is missing:
293
+ else {
294
+ // Report this.
295
+ data.prevented = true;
296
+ data.error = `No ${section} section`;
297
+ }
298
+ }
299
+ }
300
+ }
301
+ // Otherwise, i.e. if the report does not contain a modules property:
302
+ else {
303
+ // Report this.
304
+ data.prevented = true;
305
+ data.error = 'No modules';
306
+ }
307
+ }
308
+ // Otherwise, i.e. if the report does not contain a copy of the DOM:
309
+ else {
310
+ // Report this.
311
+ data.prevented = true;
312
+ data.error = 'No DOM';
313
+ }
314
+ // Stop the QualWeb core engine.
315
+ await qualWeb.stop();
316
+ // Test whether the result is an object.
317
+ try {
318
+ JSON.stringify(result);
319
+ }
320
+ catch (error) {
321
+ data.prevented = true;
322
+ data.error = `QualWeb result cannot be made JSON (${error.message})`;
323
+ }
289
324
  }
290
- catch(error) {
291
- data.prevented = true;
292
- data.error = `QualWeb result cannot be made JSON (${error.message})`;
325
+ catch (error) {
326
+ data.prevented = true;
327
+ data.error = `QualWeb failed (${error.message})`;
293
328
  }
294
- }
295
- catch(error) {
296
- data.prevented = true;
297
- data.error = `QualWeb failed (${error.message})`;
298
- }
299
- return {
300
- data,
301
- result
302
- };
329
+ return {
330
+ data,
331
+ result
332
+ };
303
333
  };
334
+ exports.reporter = reporter;