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
@@ -0,0 +1,144 @@
1
+ /*
2
+ © 2023–2024 CVS Health and/or one of its affiliates. All rights reserved.
3
+ © 2026 Jeff Witt.
4
+ © 2026 Jonathan Robert Pool.
5
+
6
+ Licensed under the MIT License. See LICENSE file at the project root or https://opensource.org/license/mit/ for details.
7
+
8
+ SPDX-License-Identifier: MIT
9
+ */
10
+
11
+ // ########## IMPORTS
12
+
13
+ import type {Page} from 'playwright';
14
+ import {getSource} from '../procs/getSource';
15
+ import {getXPathCatalogIndex} from '../procs/xPath';
16
+ import type {Report, StandardInstance} from '../types';
17
+
18
+ /*
19
+ dupAtt
20
+ This test reports duplicate attributes. The test is performed on the source of the document, because browsers delete additional same-name attributes in the DOM.
21
+ Compiled to dupAtt.js by tsc (issue #73); edit this file, not the emitted one.
22
+ */
23
+
24
+ // ########## FUNCTIONS
25
+
26
+ // Returns the catalog index of the element with an ID and tag name, or of the body if none does. Duplicate attributes are found in the source, not the DOM, so the ID is the only handle on the element.
27
+ const getIDCatalogIndex = (report: Report, tagName: string, id: string): string => {
28
+ const {catalog} = report;
29
+ if (id && catalog) {
30
+ const index = Object.keys(catalog).find(
31
+ key => catalog[key].id === id && catalog[key].tagName === tagName
32
+ );
33
+ if (index !== undefined) {
34
+ return index;
35
+ }
36
+ }
37
+ return getXPathCatalogIndex(report, '/html/body');
38
+ };
39
+ // Runs the test and returns the result.
40
+ export const reporter = async (page: Page, report: Report, _: unknown, withItems: boolean) => {
41
+ // Initialize the data and standard result.
42
+ const data: {
43
+ total: number;
44
+ items?: {tagName: string; id: string; duplicatedAttribute: string}[];
45
+ prevented?: boolean;
46
+ error?: string;
47
+ } = {total: 0};
48
+ if (withItems) {
49
+ data.items = [];
50
+ }
51
+ let totals: number[] = [];
52
+ const standardInstances: StandardInstance[] = [];
53
+ // Get the source.
54
+ const sourceData = await getSource(page);
55
+ // If it was not obtained:
56
+ if (sourceData.prevented) {
57
+ // Report this.
58
+ data.prevented = true;
59
+ data.error = sourceData.error;
60
+ }
61
+ // Otherwise, i.e. if it was obtained:
62
+ else {
63
+ let rawPage = sourceData.source;
64
+ // Change any spacing character sequences in it to single spaces.
65
+ rawPage = rawPage.replace(/\s+/g, ' ');
66
+ // Delete any spaces adjacent to equal symbols in it.
67
+ rawPage = rawPage.replace(/ = | =|= /g, '=');
68
+ // Remove any escaped quotation marks from it.
69
+ rawPage = rawPage.replace(/\\"|\\'/g, '');
70
+ // Remove any script code from it.
71
+ rawPage = rawPage.replace(/<script(?: [^<>]+)?>.*?<\/script>/g, '');
72
+ rawPage = rawPage.replace(/<script(?: [^<>]+)?>/g, '');
73
+ rawPage = rawPage.replace(/<\/script>/g, '');
74
+ // Remove any comments from it.
75
+ rawPage = rawPage.replace(/<!--.*?-->/g, '');
76
+ // Extract the syntactically valid opening tags of its elements.
77
+ // A pageless source would make the match null; the original dereferenced it unguarded.
78
+ let elements: string[] = rawPage.match(/<[a-zA-Z]+(?: [^<>]+)?>/g)!;
79
+ // Delete their enclosing angle brackets and any closing slashes.
80
+ elements = elements.map(element => element.replace(/< ?| ?\/?>/g, ''));
81
+ // Delete the values of any attributes in them.
82
+ const nvElements = elements.map(element => element.replace(/="[^"]*"/g, ''));
83
+ // For each element:
84
+ nvElements.forEach((element, index) => {
85
+ // Identify its tag name and attributes.
86
+ const terms = element.split(' ');
87
+ // If it has 2 or more attributes:
88
+ if (terms.length > 2) {
89
+ // If any is duplicated:
90
+ const tagName = terms[0].toUpperCase();
91
+ const attributes = terms.slice(1);
92
+ attributes.sort();
93
+ const duplicatedAttribute = attributes.find(
94
+ (current, attIndex) => attributes[attIndex + 1] === current
95
+ );
96
+ if (duplicatedAttribute) {
97
+ // Add data on the element to the data.
98
+ const id = terms.includes('id')
99
+ ? elements[index].replace(/^.+id="/, '').replace(/".+/, '')
100
+ : '';
101
+ data.total++;
102
+ if (withItems) {
103
+ data.items!.push({
104
+ tagName,
105
+ id,
106
+ duplicatedAttribute
107
+ });
108
+ }
109
+ }
110
+ }
111
+ });
112
+ // If itemization is required and there are any instances:
113
+ if (data.items) {
114
+ // For each violator:
115
+ data.items.forEach(item => {
116
+ // Add an instance to the standard instances.
117
+ standardInstances.push({
118
+ ruleID: 'dupAtt',
119
+ what: `${item.tagName} element has 2 attributes named ${item.duplicatedAttribute}`,
120
+ ordinalSeverity: 2,
121
+ count: 1,
122
+ catalogIndex: getIDCatalogIndex(report, item.tagName, item.id)
123
+ });
124
+ });
125
+ }
126
+ // Otherwise, if itemization is not required and there are any violations:
127
+ else if (data.total) {
128
+ // Add a summary instance to the standard instances.
129
+ standardInstances.push({
130
+ ruleID: 'dupAtt',
131
+ what: 'In some elements 2 attributes have the same name',
132
+ ordinalSeverity: 2,
133
+ count: data.total
134
+ });
135
+ }
136
+ totals = [0, 0, data.total, 0];
137
+ }
138
+ // Return the data.
139
+ return {
140
+ data,
141
+ totals,
142
+ standardInstances
143
+ };
144
+ };
@@ -0,0 +1,6 @@
1
+ import type { Page } from 'playwright';
2
+ export declare const reporter: (page: Page, _0: unknown, _1: unknown, _2: unknown, detailLevel?: number, tagName?: string | null, onlyVisible?: boolean, attribute?: string) => Promise<{
3
+ data: Record<string, unknown>;
4
+ totals: never[];
5
+ standardInstances: never[];
6
+ }>;
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /*
2
3
  © 2023 CVS Health and/or one of its affiliates. All rights reserved.
3
4
  © 2026 Jonathan Robert Pool.
@@ -6,7 +7,8 @@
6
7
 
7
8
  SPDX-License-Identifier: MIT
8
9
  */
9
-
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.reporter = void 0;
10
12
  /*
11
13
  elements
12
14
  This test reports data about specified elements within the document body. Meanings of detailLevel values:
@@ -14,163 +16,161 @@
14
16
  1. Also data on each specified element.
15
17
  2. Data on each specified element also include the text content of the parent element.
16
18
  3. Data on each specified element also include data on its sibling nodes.
19
+ Compiled to elements.js by tsc (issue #73); edit this file, not the emitted one.
17
20
  */
18
-
19
21
  // FUNCTIONS
20
-
21
- exports.reporter = async (
22
- page, _, _, detailLevel = 0, tagName = null, onlyVisible = false, attribute
23
- ) => {
24
- // Determine a selector of the specified elements, including any descendants of open shadow roots.
25
- let selector = `body ${tagName ? tagName.toLowerCase() : '*'}`;
26
- if (attribute) {
27
- selector += `[${attribute}]`;
28
- }
29
- if (onlyVisible) {
30
- selector += ':visible';
31
- }
32
- let data = {};
33
- // Get the data on the elements.
34
- try {
35
- const locator = page.locator(selector);
36
- data = await locator.evaluateAll((elements, detailLevel) => {
37
- // FUNCTION DEFINITIONS START
38
- // Compacts a string.
39
- const compact = string => string.replace(/\s+/g, ' ').trim();
40
- // Gets data on a sibling node of an element.
41
- const getSibInfo = (node, nodeType, text) => {
42
- const sibInfo = {
43
- type: nodeType
44
- };
45
- // If the sibling node is an element:
46
- if (nodeType === 1) {
47
- sibInfo.tagName = node.tagName;
48
- sibInfo.attributes = [];
49
- Array.from(node.attributes).forEach(attribute => {
50
- sibInfo.attributes.push({
51
- name: attribute.name,
52
- value: attribute.value
53
- });
54
- });
55
- }
56
- else if (nodeType === 3) {
57
- sibInfo.text = compact(text);
58
- }
59
- return sibInfo;
60
- };
61
- // FUNCTION DEFINITIONS END
62
- // Initialize the data with the count of the specified elements.
63
- const data = {
64
- total: elements.length
65
- };
66
- // If no itemization is required:
67
- if (detailLevel === 0) {
68
- // Return the element count.
69
- return data;
70
- }
71
- // Otherwise, i.e. if itemization is required:
72
- else {
73
- // Initialize the item data.
74
- data.items = [];
75
- // For each specified element:
76
- elements.forEach(element => {
77
- // Initialize data on it.
78
- const parent = element.parentElement;
79
- const datum = {
80
- tagName: element.tagName,
81
- parentTagName: parent ? parent.tagName : '',
82
- code: compact(element.outerHTML),
83
- attributes: [],
84
- textContent: compact(element.textContent)
85
- };
86
- // For each of its attributes:
87
- for (const attribute of element.attributes) {
88
- // Add data on the attribute to the element data.
89
- const {name, value} = attribute;
90
- datum.attributes.push({
91
- name,
92
- value
93
- });
94
- // If the element has reference labels:
95
- if (name === 'aria-labelledby') {
96
- // Add their texts to the element data.
97
- const labelerIDs = value.split(/\s+/);
98
- const labelers = [];
99
- labelerIDs.forEach(id => {
100
- const labeler = document.getElementById(id);
101
- if (labeler) {
102
- labelers.push(compact(labeler.textContent));
22
+ const reporter = async (page, _0, _1, _2, detailLevel = 0, tagName = null, onlyVisible = false, attribute) => {
23
+ // Determine a selector of the specified elements, including any descendants of open shadow roots.
24
+ let selector = `body ${tagName ? tagName.toLowerCase() : '*'}`;
25
+ if (attribute) {
26
+ selector += `[${attribute}]`;
27
+ }
28
+ if (onlyVisible) {
29
+ selector += ':visible';
30
+ }
31
+ let data = {};
32
+ // Get the data on the elements.
33
+ try {
34
+ const locator = page.locator(selector);
35
+ data = await locator.evaluateAll((elements, detailLevel) => {
36
+ // FUNCTION DEFINITIONS START
37
+ // Compacts a string.
38
+ const compact = (string) => string.replace(/\s+/g, ' ').trim();
39
+ // Gets data on a sibling node of an element.
40
+ const getSibInfo = (node, nodeType, text) => {
41
+ const sibInfo = {
42
+ type: nodeType
43
+ };
44
+ // If the sibling node is an element:
45
+ if (nodeType === 1) {
46
+ sibInfo.tagName = node.tagName;
47
+ sibInfo.attributes = [];
48
+ Array.from(node.attributes).forEach(attribute => {
49
+ sibInfo.attributes.push({
50
+ name: attribute.name,
51
+ value: attribute.value
52
+ });
53
+ });
103
54
  }
104
- });
105
- if (labelers.length) {
106
- datum.labelers = labelers;
107
- }
108
- }
109
- }
110
- // If the element has text content:
111
- const {labels, textContent} = element;
112
- const compactContent = compact(textContent);
113
- if (compactContent) {
114
- // Add it to the element data.
115
- datum.textContent = compactContent;
116
- }
117
- // If the element has labels:
118
- if (labels && labels.length) {
119
- // Add their texts to the element data.
120
- datum.labels = Array.from(labels).map(label => compact(label.textContent));
121
- }
122
- // If the parental text content is required:
123
- if (detailLevel > 1) {
124
- // Add it (excluding any shadow-root descendants) to the element data.
125
- datum.parentTextContent = parent ? compact(parent.textContent) : '';
126
- }
127
- // If sibling itemization is required:
128
- if (detailLevel === 3) {
129
- // Add data on the siblings, excluding any descendants of shadow roots, to the data.
130
- datum.siblings = {
131
- before: [],
132
- after: []
133
- };
134
- let more = element;
135
- while (more) {
136
- more = more.previousSibling;
137
- if (more) {
138
- const {nodeType, nodeValue} = more;
139
- if (! (nodeType === 3 && nodeValue === '')) {
140
- const sibInfo = getSibInfo(more, nodeType, nodeValue);
141
- datum.siblings.before.unshift(sibInfo);
55
+ else if (nodeType === 3) {
56
+ sibInfo.text = compact(text);
142
57
  }
143
- }
58
+ return sibInfo;
59
+ };
60
+ // FUNCTION DEFINITIONS END
61
+ // Initialize the data with the count of the specified elements.
62
+ const data = {
63
+ total: elements.length
64
+ };
65
+ // If no itemization is required:
66
+ if (detailLevel === 0) {
67
+ // Return the element count.
68
+ return data;
144
69
  }
145
- more = element;
146
- while (more) {
147
- more = more.nextSibling;
148
- if (more) {
149
- const {nodeType, textContent} = more;
150
- if (! (nodeType === 3 && textContent === '')) {
151
- const sibInfo = getSibInfo(more, nodeType, compact(textContent));
152
- datum.siblings.after.push(sibInfo);
153
- }
154
- }
70
+ // Otherwise, i.e. if itemization is required:
71
+ else {
72
+ // Initialize the item data.
73
+ data.items = [];
74
+ // For each specified element:
75
+ elements.forEach(element => {
76
+ // Initialize data on it.
77
+ const parent = element.parentElement;
78
+ const datum = {
79
+ tagName: element.tagName,
80
+ parentTagName: parent ? parent.tagName : '',
81
+ code: compact(element.outerHTML),
82
+ attributes: [],
83
+ textContent: compact(element.textContent)
84
+ };
85
+ // For each of its attributes:
86
+ for (const attribute of element.attributes) {
87
+ // Add data on the attribute to the element data.
88
+ const { name, value } = attribute;
89
+ datum.attributes.push({
90
+ name,
91
+ value
92
+ });
93
+ // If the element has reference labels:
94
+ if (name === 'aria-labelledby') {
95
+ // Add their texts to the element data.
96
+ const labelerIDs = value.split(/\s+/);
97
+ const labelers = [];
98
+ labelerIDs.forEach(id => {
99
+ const labeler = document.getElementById(id);
100
+ if (labeler) {
101
+ labelers.push(compact(labeler.textContent));
102
+ }
103
+ });
104
+ if (labelers.length) {
105
+ datum.labelers = labelers;
106
+ }
107
+ }
108
+ }
109
+ // If the element has text content:
110
+ const { labels, textContent } = element;
111
+ const compactContent = compact(textContent);
112
+ if (compactContent) {
113
+ // Add it to the element data.
114
+ datum.textContent = compactContent;
115
+ }
116
+ // If the element has labels:
117
+ if (labels && labels.length) {
118
+ // Add their texts to the element data.
119
+ datum.labels = Array.from(labels).map(label => compact(label.textContent));
120
+ }
121
+ // If the parental text content is required:
122
+ if (detailLevel > 1) {
123
+ // Add it (excluding any shadow-root descendants) to the element data.
124
+ datum.parentTextContent = parent ? compact(parent.textContent) : '';
125
+ }
126
+ // If sibling itemization is required:
127
+ if (detailLevel === 3) {
128
+ // Add data on the siblings, excluding any descendants of shadow roots, to the data.
129
+ datum.siblings = {
130
+ before: [],
131
+ after: []
132
+ };
133
+ let more = element;
134
+ while (more) {
135
+ more = more.previousSibling;
136
+ if (more) {
137
+ const { nodeType, nodeValue } = more;
138
+ if (!(nodeType === 3 && nodeValue === '')) {
139
+ const sibInfo = getSibInfo(more, nodeType, nodeValue);
140
+ datum.siblings.before.unshift(sibInfo);
141
+ }
142
+ }
143
+ }
144
+ more = element;
145
+ while (more) {
146
+ more = more.nextSibling;
147
+ if (more) {
148
+ const { nodeType, textContent } = more;
149
+ if (!(nodeType === 3 && textContent === '')) {
150
+ const sibInfo = getSibInfo(more, nodeType, compact(textContent));
151
+ datum.siblings.after.push(sibInfo);
152
+ }
153
+ }
154
+ }
155
+ }
156
+ data.items.push(datum);
157
+ });
158
+ return data;
155
159
  }
156
- }
157
- data.items.push(datum);
158
- });
159
- return data;
160
- }
161
- }, detailLevel);
162
- }
163
- catch(error) {
164
- console.log(`ERROR performing test (${error.message})`);
165
- data = {
166
- prevented: true,
167
- error: 'ERROR performing test'
160
+ }, detailLevel);
161
+ }
162
+ catch (error) {
163
+ console.log(`ERROR performing test (${error.message})`);
164
+ data = {
165
+ prevented: true,
166
+ error: 'ERROR performing test'
167
+ };
168
+ }
169
+ // Return the result.
170
+ return {
171
+ data,
172
+ totals: [],
173
+ standardInstances: []
168
174
  };
169
- }
170
- // Return the result.
171
- return {
172
- data,
173
- totals: [],
174
- standardInstances: []
175
- };
176
175
  };
176
+ exports.reporter = reporter;