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.
- package/.gitattributes +94 -0
- package/.github/workflows/ci.yml +58 -0
- package/.github/workflows/publish.yml +49 -0
- package/.github/workflows/typescript.yml +35 -0
- package/AGENTS.md +2 -2
- package/CLAUDE.md +24 -18
- package/CONTAINERS.md +9 -6
- package/CONTRIBUTING.md +29 -3
- package/Dockerfile +1 -1
- package/README.md +73 -19
- package/UPGRADES.md +4 -0
- package/actSpecs-doc.md +13 -1
- package/actSpecs.js +29 -5
- package/call.js +6 -5
- package/docker-compose.yml +8 -2
- package/docs/checkpoint-scanning.md +199 -0
- package/docs/standard-result-outcome.md +165 -0
- package/env.example +44 -10
- package/eslint.config.mjs +101 -0
- package/netWatch.js +372 -222
- package/package.json +46 -31
- package/pour/README.md +47 -0
- package/pour/pour.min.js +8 -0
- package/procs/actDo.js +808 -0
- package/procs/catalog.d.ts +17 -0
- package/procs/catalog.js +312 -221
- package/procs/catalog.ts +398 -0
- package/procs/checkpoint.js +110 -0
- package/procs/config.d.ts +35 -0
- package/procs/config.js +62 -0
- package/procs/dateTime.js +2 -1
- package/procs/doActs.js +442 -849
- package/procs/doTestAct.js +27 -121
- package/procs/flow.js +221 -0
- package/procs/generateRuleRegistry.js +94 -0
- package/procs/getSource.d.ts +26 -0
- package/procs/job.js +115 -1
- package/procs/launch.d.ts +40 -0
- package/procs/launch.js +239 -108
- package/procs/nu.d.ts +48 -0
- package/procs/scope.js +196 -0
- package/procs/shoot.d.ts +33 -0
- package/procs/standard.d.ts +18 -0
- package/procs/standard.js +83 -0
- package/procs/standard.ts +126 -0
- package/procs/testAct.js +145 -0
- package/procs/testaro.d.ts +20 -0
- package/procs/testaro.js +236 -189
- package/procs/testaro.ts +321 -0
- package/procs/userPath.js +126 -0
- package/procs/xPath.d.ts +4 -0
- package/procs/xPath.js +81 -69
- package/procs/xPath.ts +106 -0
- package/procs/xPathScript.d.ts +6 -0
- package/procs/xPathScript.js +70 -0
- package/run.js +3 -2
- package/surea11y/README.md +44 -0
- package/surea11y/surea11y.browser.js +14 -0
- package/testaro/adbID.d.ts +3 -0
- package/testaro/adbID.js +38 -41
- package/testaro/adbID.ts +66 -0
- package/testaro/allCapStyle.d.ts +3 -0
- package/testaro/allCapStyle.js +31 -34
- package/testaro/allCapStyle.ts +55 -0
- package/testaro/allCaps.d.ts +16 -0
- package/testaro/allCaps.js +179 -151
- package/testaro/allCaps.ts +228 -0
- package/testaro/allHidden.d.ts +13 -0
- package/testaro/allHidden.js +29 -30
- package/testaro/allHidden.ts +50 -0
- package/testaro/allSlanted.d.ts +3 -0
- package/testaro/allSlanted.js +30 -33
- package/testaro/allSlanted.ts +54 -0
- package/testaro/altScheme.d.ts +3 -0
- package/testaro/altScheme.js +27 -30
- package/testaro/altScheme.ts +50 -0
- package/testaro/attVal.d.ts +3 -0
- package/testaro/attVal.js +20 -21
- package/testaro/attVal.ts +52 -0
- package/testaro/autocomplete.d.ts +3 -0
- package/testaro/autocomplete.js +59 -75
- package/testaro/autocomplete.ts +101 -0
- package/testaro/bulk.d.ts +13 -0
- package/testaro/bulk.js +32 -33
- package/testaro/bulk.ts +55 -0
- package/testaro/buttonMenu.d.ts +9 -0
- package/testaro/buttonMenu.js +317 -319
- package/testaro/buttonMenu.ts +391 -0
- package/testaro/captionLoc.d.ts +3 -0
- package/testaro/captionLoc.js +17 -20
- package/testaro/captionLoc.ts +40 -0
- package/testaro/datalistRef.d.ts +3 -0
- package/testaro/datalistRef.js +33 -36
- package/testaro/datalistRef.ts +55 -0
- package/testaro/distortion.d.ts +3 -0
- package/testaro/distortion.js +57 -26
- package/testaro/distortion.ts +81 -0
- package/testaro/docType.d.ts +15 -0
- package/testaro/docType.js +25 -25
- package/testaro/docType.ts +45 -0
- package/testaro/dupAtt.d.ts +16 -0
- package/testaro/dupAtt.js +113 -104
- package/testaro/dupAtt.ts +144 -0
- package/testaro/elements.d.ts +6 -0
- package/testaro/elements.js +153 -153
- package/testaro/elements.ts +215 -0
- package/testaro/embAc.d.ts +3 -0
- package/testaro/embAc.js +19 -20
- package/testaro/embAc.ts +40 -0
- package/testaro/focAll.d.ts +13 -0
- package/testaro/focAll.js +185 -191
- package/testaro/focAll.ts +217 -0
- package/testaro/focAndOp.d.ts +3 -0
- package/testaro/focAndOp.js +100 -104
- package/testaro/focAndOp.ts +128 -0
- package/testaro/focInd.d.ts +3 -0
- package/testaro/focInd.js +64 -66
- package/testaro/focInd.ts +96 -0
- package/testaro/focVis.d.ts +3 -0
- package/testaro/focVis.js +28 -30
- package/testaro/focVis.ts +52 -0
- package/testaro/headEl.d.ts +10 -0
- package/testaro/headEl.js +61 -62
- package/testaro/headEl.ts +82 -0
- package/testaro/headingAmb.d.ts +3 -0
- package/testaro/headingAmb.js +54 -63
- package/testaro/headingAmb.ts +72 -0
- package/testaro/hovInd.d.ts +12 -0
- package/testaro/hovInd.js +163 -130
- package/testaro/hovInd.ts +199 -0
- package/testaro/hover.d.ts +3 -0
- package/testaro/hover.js +155 -126
- package/testaro/hover.ts +154 -0
- package/testaro/hr.d.ts +3 -0
- package/testaro/hr.js +14 -17
- package/testaro/hr.ts +36 -0
- package/testaro/imageLink.d.ts +3 -0
- package/testaro/imageLink.js +17 -20
- package/testaro/imageLink.ts +42 -0
- package/testaro/labClash.d.ts +3 -0
- package/testaro/labClash.js +31 -33
- package/testaro/labClash.ts +54 -0
- package/testaro/legendLoc.d.ts +3 -0
- package/testaro/legendLoc.js +17 -20
- package/testaro/legendLoc.ts +42 -0
- package/testaro/lineHeight.d.ts +3 -0
- package/testaro/lineHeight.js +43 -48
- package/testaro/lineHeight.ts +70 -0
- package/testaro/linkAmb.d.ts +7 -0
- package/testaro/linkAmb.js +79 -80
- package/testaro/linkAmb.ts +105 -0
- package/testaro/linkExt.d.ts +3 -0
- package/testaro/linkExt.js +13 -16
- package/testaro/linkExt.ts +35 -0
- package/testaro/linkOldAtt.d.ts +3 -0
- package/testaro/linkOldAtt.js +25 -28
- package/testaro/linkOldAtt.ts +48 -0
- package/testaro/linkTo.d.ts +3 -0
- package/testaro/linkTo.js +22 -22
- package/testaro/linkTo.ts +43 -0
- package/testaro/linkUl.d.ts +3 -0
- package/testaro/linkUl.js +30 -34
- package/testaro/linkUl.ts +54 -0
- package/testaro/miniText.d.ts +3 -0
- package/testaro/miniText.js +41 -44
- package/testaro/miniText.ts +68 -0
- package/testaro/motion.d.ts +10 -0
- package/testaro/motion.js +92 -96
- package/testaro/motion.ts +125 -0
- package/testaro/nonTable.d.ts +3 -0
- package/testaro/nonTable.js +39 -45
- package/testaro/nonTable.ts +66 -0
- package/testaro/optRoleSel.d.ts +3 -0
- package/testaro/optRoleSel.js +16 -19
- package/testaro/optRoleSel.ts +41 -0
- package/testaro/phOnly.d.ts +3 -0
- package/testaro/phOnly.js +18 -21
- package/testaro/phOnly.ts +43 -0
- package/testaro/pseudoP.d.ts +3 -0
- package/testaro/pseudoP.js +36 -38
- package/testaro/pseudoP.ts +59 -0
- package/testaro/radioSet.d.ts +3 -0
- package/testaro/radioSet.js +57 -59
- package/testaro/radioSet.ts +79 -0
- package/testaro/registry.d.ts +63 -0
- package/testaro/registry.js +67 -0
- package/testaro/registry.ts +141 -0
- package/testaro/role.d.ts +3 -0
- package/testaro/role.js +27 -29
- package/testaro/role.ts +53 -0
- package/testaro/secHeading.d.ts +3 -0
- package/testaro/secHeading.js +30 -33
- package/testaro/secHeading.ts +53 -0
- package/testaro/styleDiff.d.ts +25 -0
- package/testaro/styleDiff.js +248 -252
- package/testaro/styleDiff.ts +303 -0
- package/testaro/tabNav.d.ts +33 -0
- package/testaro/tabNav.js +272 -342
- package/testaro/tabNav.ts +454 -0
- package/testaro/targetsNear.d.ts +9 -0
- package/testaro/targetsNear.js +130 -132
- package/testaro/targetsNear.ts +160 -0
- package/testaro/textNodes.d.ts +6 -0
- package/testaro/textNodes.js +139 -135
- package/testaro/textNodes.ts +185 -0
- package/testaro/textSem.d.ts +3 -0
- package/testaro/textSem.js +25 -28
- package/testaro/textSem.ts +47 -0
- package/testaro/title.d.ts +9 -0
- package/testaro/title.js +16 -13
- package/testaro/title.ts +31 -0
- package/testaro/titledEl.d.ts +3 -0
- package/testaro/titledEl.js +15 -18
- package/testaro/titledEl.ts +38 -0
- package/testaro/zIndex.d.ts +3 -0
- package/testaro/zIndex.js +19 -22
- package/testaro/zIndex.ts +42 -0
- package/tests/alfa.d.ts +45 -0
- package/tests/alfa.js +138 -141
- package/tests/alfa.ts +214 -0
- package/tests/aslint.d.ts +33 -0
- package/tests/aslint.js +272 -249
- package/tests/aslint.ts +301 -0
- package/tests/axe.d.ts +27 -0
- package/tests/axe.js +199 -200
- package/tests/axe.ts +277 -0
- package/tests/ed11y.d.ts +28 -0
- package/tests/ed11y.js +141 -99
- package/tests/ed11y.ts +178 -0
- package/tests/htmlcs.d.ts +21 -0
- package/tests/htmlcs.js +174 -140
- package/tests/htmlcs.ts +181 -0
- package/tests/ibm.d.ts +52 -0
- package/tests/ibm.js +164 -166
- package/tests/ibm.ts +251 -0
- package/tests/nuVal.d.ts +13 -0
- package/tests/nuVal.js +107 -112
- package/tests/nuVal.ts +145 -0
- package/tests/nuVnu.d.ts +15 -0
- package/tests/nuVnu.js +141 -111
- package/tests/nuVnu.ts +144 -0
- package/tests/pour.d.ts +31 -0
- package/tests/pour.js +242 -0
- package/tests/pour.ts +273 -0
- package/tests/qualWeb.d.ts +39 -0
- package/tests/qualWeb.js +302 -272
- package/tests/qualWeb.ts +415 -0
- package/tests/surea11y.d.ts +33 -0
- package/tests/surea11y.js +288 -0
- package/tests/surea11y.ts +334 -0
- package/tests/testaro.d.ts +25 -0
- package/tests/testaro.js +745 -652
- package/tests/testaro.ts +862 -0
- package/tests/wave.d.ts +46 -0
- package/tests/wave.js +166 -177
- package/tests/wave.ts +252 -0
- package/tsconfig.json +17 -0
- package/types.d.ts +243 -0
- package/types.js +10 -0
- package/types.ts +376 -0
- package/validation/act/README.md +46 -0
- package/validation/act/capture.js +424 -0
- package/validation/act/chromium-issue-draft.md +66 -0
- package/validation/act/fp-triage-2026-08-22.md +86 -0
- package/validation/act/isolation-notes.md +159 -0
- package/validation/act/playwright-issue-draft.md +73 -0
- package/validation/act/propose-mappings.js +0 -0
- package/validation/act/repro-cdp-raw.js +105 -0
- package/validation/act/repro-metarefresh.js +65 -0
- package/validation/act/score.js +184 -0
- package/validation/act/stage3a-stress-report.md +69 -0
- package/validation/act/stage3b-mapping-proposals.md +94 -0
- package/validation/act/stage3b-triage-draft.md +138 -0
- package/validation/act/surea11y-track-a-2026-09-01.md +50 -0
- package/validation/executors/netWatch.js +180 -90
- package/validation/executors/test.js +17 -2
- package/validation/executors/tests.js +118 -10
- package/validation/jobs/reports/raw/260901T1000-surea11y-validation.json +964 -0
- package/validation/jobs/todo/240101T1200-simple-example.json +14 -6
- package/validation/jobs/todo/240101T1300-shoot-example.json +2 -1
- package/validation/jobs/todo/260821T1900-pour-validation.json +45 -0
- package/validation/jobs/todo/260901T1000-surea11y-validation.json +45 -0
- package/validation/knownFailures.json +1 -0
- package/validation/tests/jobProperties/adbID.json +27 -2
- package/validation/tests/jobProperties/{focOp.json → allCapStyle.json} +56 -53
- package/validation/tests/jobProperties/allCaps.json +25 -0
- package/validation/tests/jobProperties/allHidden.json +133 -13
- package/validation/tests/jobProperties/allSlanted.json +3 -3
- package/validation/tests/jobProperties/altScheme.json +23 -8
- package/validation/tests/jobProperties/attVal.json +57 -57
- package/validation/tests/jobProperties/autocomplete.json +11 -1
- package/validation/tests/jobProperties/bulk.json +6 -1
- package/validation/tests/jobProperties/buttonMenu.json +63 -42
- package/validation/tests/jobProperties/captionLoc.json +1 -6
- package/validation/tests/jobProperties/checkpoint-browser.json +401 -0
- package/validation/tests/jobProperties/checkpoint-page.json +397 -0
- package/validation/tests/jobProperties/checkpoint.json +395 -0
- package/validation/tests/jobProperties/datalistRef.json +20 -5
- package/validation/tests/jobProperties/distortion.json +28 -3
- package/validation/tests/jobProperties/docType.json +2 -2
- package/validation/tests/jobProperties/dupAtt.json +48 -33
- package/validation/tests/jobProperties/elements.json +28 -28
- package/validation/tests/jobProperties/embAc.json +36 -31
- package/validation/tests/jobProperties/focAndOp.json +284 -0
- package/validation/tests/jobProperties/focInd.json +34 -34
- package/validation/tests/jobProperties/focVis.json +1 -1
- package/validation/tests/jobProperties/hover.json +39 -37
- package/validation/tests/jobProperties/hr.json +13 -3
- package/validation/tests/jobProperties/imageLink.json +0 -5
- package/validation/tests/jobProperties/labClash.json +68 -33
- package/validation/tests/jobProperties/legendLoc.json +1 -6
- package/validation/tests/jobProperties/lineHeight.json +2 -2
- package/validation/tests/jobProperties/linkAmb.json +13 -18
- package/validation/tests/jobProperties/linkExt.json +1 -1
- package/validation/tests/jobProperties/linkOldAtt.json +12 -2
- package/validation/tests/jobProperties/linkTo.json +1 -1
- package/validation/tests/jobProperties/linkUl.json +65 -65
- package/validation/tests/jobProperties/miniText.json +7 -2
- package/validation/tests/jobProperties/motion.json +4 -50
- package/validation/tests/jobProperties/nonTable.json +48 -3
- package/validation/tests/jobProperties/optRoleSel.json +12 -2
- package/validation/tests/jobProperties/phOnly.json +6 -16
- package/validation/tests/jobProperties/pseudoP.json +17 -2
- package/validation/tests/jobProperties/radioSet.json +30 -30
- package/validation/tests/jobProperties/role.json +25 -5
- package/validation/tests/jobProperties/secHeading.json +26 -21
- package/validation/tests/jobProperties/styleDiff.json +35 -5
- package/validation/tests/jobProperties/tabNav.json +3 -1
- package/validation/tests/jobProperties/targetsNear.json +237 -0
- package/validation/tests/jobProperties/textNodes.json +29 -29
- package/validation/tests/jobProperties/textSem.json +26 -1
- package/validation/tests/jobProperties/title.json +12 -2
- package/validation/tests/jobProperties/titledEl.json +39 -9
- package/validation/tests/jobProperties/userPath.json +317 -0
- package/validation/tests/jobProperties/zIndex.json +40 -35
- package/validation/tests/targets/allCapStyle/index.html +26 -0
- package/validation/tests/targets/checkpoint/index.html +38 -0
- package/validation/tests/targets/datalistRef/index.html +1 -1
- package/validation/tests/targets/focAndOp/bad.html +29 -0
- package/validation/tests/targets/{focOp → focAndOp}/good.html +3 -1
- package/validation/tests/targets/focInd/bad.html +2 -1
- package/validation/tests/targets/headEl/index.html +10 -1
- package/validation/tests/targets/{targetSmall → targetsNear}/index.html +15 -1
- package/validation/tests/targets/userPath/index.html +42 -0
- package/validation/validateTest.js +61 -9
- package/.claude/settings.local.json +0 -11
- package/.eslintrc.json +0 -41
- package/htmlcs/.eslintrc.json +0 -67
- package/validation/tests/jobProperties/linkTitle.json +0 -127
- package/validation/tests/jobProperties/opFoc.json +0 -164
- package/validation/tests/jobProperties/targetSmall.json +0 -152
- package/validation/tests/jobProperties/targetTiny.json +0 -142
- package/validation/tests/targets/focOp/bad.html +0 -25
- package/validation/tests/targets/linkTitle/index.html +0 -24
- package/validation/tests/targets/opFoc/bad.html +0 -26
- package/validation/tests/targets/opFoc/good.html +0 -23
package/README.md
CHANGED
|
@@ -53,11 +53,13 @@ Testaro can perform tests of these _rule engines_:
|
|
|
53
53
|
- [Editoria11y](https://github.com/itmaybejj/editoria11y) (Princeton University)
|
|
54
54
|
- [HTML CodeSniffer](https://www.npmjs.com/package/html_codesniffer) (Squiz Labs)
|
|
55
55
|
- [Nu Html Checker](https://github.com/validator/validator) (World Wide Web Consortium)
|
|
56
|
+
- [Pour Engine](https://github.com/pourdev/pour-engine) (David Yarham and Geoffrey Crofte)
|
|
56
57
|
- [QualWeb](https://www.npmjs.com/package/@qualweb/core) (University of Lisbon)
|
|
58
|
+
- [SureA11y](https://github.com/SureA11y/core) (Jorge Rumoroso)
|
|
57
59
|
- [Testaro](https://www.npmjs.com/package/testaro) (CVS Health)
|
|
58
60
|
- [WAVE](https://wave.webaim.org/api/) (WebAIM)
|
|
59
61
|
|
|
60
|
-
For the rule engines that are open-source, the identified organizations are their principal or original sponsors.
|
|
62
|
+
For the rule engines that are open-source, the identified organizations or persons are their principal or original sponsors or authors.
|
|
61
63
|
|
|
62
64
|
As shown, Testaro is not only an integrator but also one of the integrated rule engines. That is because it provides about 50 tests of its own, mostly to complement tests provided by the other rule engines. Some of those Testaro tests are designed to act as approximate alternatives to tests of vulnerable, restricted, or no longer available rule engines. In all such cases the Testaro tests are independently designed and implemented, without reference to the code of the tests that inspired them.
|
|
63
65
|
|
|
@@ -81,7 +83,7 @@ The main concepts of Testaro are:
|
|
|
81
83
|
|
|
82
84
|
### Operating system and Node.js version
|
|
83
85
|
|
|
84
|
-
Testaro can be installed under a MacOS, Windows, Debian, or Ubuntu operating system with the latest long-term-support version of [Node.js](https://nodejs.org/en/).
|
|
86
|
+
Testaro can be installed under a MacOS, Windows, Debian, or Ubuntu operating system with the latest long-term-support version of [Node.js](https://nodejs.org/en/). The minimum version is Node 22.12: Node 20 reached end of life in April 2026, and some dependencies (the Alfa packages and pixelmatch) are ES modules that Testaro loads with `require()`, which the Node 22 line supports from 22.12 onward. When Node 22 reaches end of life in April 2027, the minimum is expected to rise to Node 24.
|
|
85
87
|
|
|
86
88
|
### Browser security
|
|
87
89
|
|
|
@@ -115,7 +117,7 @@ This application implements option B.
|
|
|
115
117
|
|
|
116
118
|
## Installation as an independent application
|
|
117
119
|
|
|
118
|
-
To install Testaro as an independent application, rather than a dependency, clone the [Testaro repository](https://github.com/
|
|
120
|
+
To install Testaro as an independent application, rather than a dependency, clone the [Testaro repository](https://github.com/YRA-Tech/testaro). To ensure that the binary browsers of its Playwright dependency get installed, execute `(p)npx playwright install` after executing `(p)npm install`.
|
|
119
121
|
|
|
120
122
|
To update Testaro when it is an independent application, execute:
|
|
121
123
|
|
|
@@ -129,6 +131,8 @@ git pull
|
|
|
129
131
|
|
|
130
132
|
The `.env` file stores your decisions about the environment in which Testaro runs. The variables that can be defined there are documented in the `env.example` file.
|
|
131
133
|
|
|
134
|
+
Deployment options let an operator set a fleet-wide policy that a job can override: the load state and time limit a navigation waits for and whether a 4xx response ends launch retries at once (`NAV_WAIT_UNTIL`, `NAV_TIMEOUT`, `NAV_FAIL_FAST_4XX`, or a job's `navigation` property); a scanner identity sent as the `X-YRA-Scanner` request header (`SCANNER_ID` or a job's `scannerId`); a full-page scroll after navigation so lazily loaded content is present (`PRESCAN_SCROLL` or a job's `scroll`); a branded Chromium channel (a job's `browserChannel`); launch retries per rule of the `testaro` tool (`TESTARO_RULE_RETRIES` or a `testaro` test act's `retries`); and whether the `qualWeb` tool's browser runs stealth evasions and blocks ads and trackers (`QUALWEB_STEALTH`, `QUALWEB_ADBLOCK`, or a `qualWeb` test act's `stealth` and `adBlock`). The defaults keep the behavior of earlier versions.
|
|
135
|
+
|
|
132
136
|
## Jobs
|
|
133
137
|
|
|
134
138
|
Jobs tell Testaro what to do.
|
|
@@ -164,6 +168,20 @@ Here is a sample job, showing properties that you can set:
|
|
|
164
168
|
// Chromium-specific). Defaults to true. Set false to opt
|
|
165
169
|
// out — useful for sites whose anti-bot heuristics react
|
|
166
170
|
// badly to stealth's patches.
|
|
171
|
+
browserChannel: 'chrome', // Optional. Run an installed branded Chromium (chrome or msedge)
|
|
172
|
+
// instead of the bundled build; bundled or absent keeps the default.
|
|
173
|
+
scannerId: 'MyScanner/1.0; +https://example.com/scanner', // Optional. Sent as the
|
|
174
|
+
// X-YRA-Scanner request header (default SCANNER_ID, else no header).
|
|
175
|
+
scroll: false, // Optional. Scroll the full page after navigation so lazily loaded content
|
|
176
|
+
// is present before tools run (default PRESCAN_SCROLL, else false).
|
|
177
|
+
navigation: { // Optional. Load state to wait for (networkidle, load, or domcontentloaded),
|
|
178
|
+
// time limit in ms, and whether a 4xx response ends launch retries at once
|
|
179
|
+
// (defaults NAV_WAIT_UNTIL, NAV_TIMEOUT, NAV_FAIL_FAST_4XX, else networkidle,
|
|
180
|
+
// 10000, false).
|
|
181
|
+
waitUntil: 'load',
|
|
182
|
+
timeout: 30000,
|
|
183
|
+
failFast4xx: true
|
|
184
|
+
},
|
|
167
185
|
creationTimeStamp: '241229T0537', // When job was created
|
|
168
186
|
executionTimeStamp: '250110T1200', // When job will be ready to be performed
|
|
169
187
|
target: {
|
|
@@ -288,32 +306,34 @@ In both cases, the first argument of `dirWatch` tells Testaro whether to continu
|
|
|
288
306
|
|
|
289
307
|
### Server polling
|
|
290
308
|
|
|
291
|
-
Testaro can poll a server for jobs to be performed. The server can act as the “controller” described in [How to run a thousand accessibility tests](https://medium.com/cvs-health-tech-blog/how-to-run-a-thousand-accessibility-tests-63692ad120c3). The server is responsible for preparing Testaro jobs, assigning them to Testaro
|
|
309
|
+
Testaro can poll a server for jobs to be performed. The server can act as the “controller” described in [How to run a thousand accessibility tests](https://medium.com/cvs-health-tech-blog/how-to-run-a-thousand-accessibility-tests-63692ad120c3). The server is responsible for preparing Testaro jobs, assigning them to Testaro workers, receiving reports back from those workers, and performing any further processing of the reports, including enhancement, storage, and disclosure to audiences. It can be any server reachable with a URL. That includes a server running on the same host as Testaro, with a URL such as `localhost:3000`.
|
|
310
|
+
|
|
311
|
+
To allow Testaro to poll a server for jobs, define the environment variables documented under `netWatch variables` in the [env.example](env.example) file. The URL paths are determined by agreement between Testaro and the server. A single Testaro instance can watch one server.
|
|
292
312
|
|
|
293
|
-
|
|
313
|
+
`NETWATCH_AUTH_TYPE` selects how Testaro authenticates to the server:
|
|
294
314
|
|
|
295
|
-
- `
|
|
296
|
-
- `
|
|
297
|
-
- `
|
|
315
|
+
- `none`: no credentials are sent. `NETWATCH_WORKER_ID` and `NETWATCH_WORKER_SECRET` are not required.
|
|
316
|
+
- `pathBody`: the password (`NETWATCH_WORKER_SECRET`) is transmitted in the request body as the value of an `agentPW` property. If the server requires the ID of the Testaro instance in the URL path, include it in `NETWATCH_URL_JOB` and `NETWATCH_URL_REPORT` yourself; Testaro does not insert it.
|
|
317
|
+
- `header`: the request carries an `authorization` header whose value is `Basic`, followed by a space and the base64 encoding of `NETWATCH_WORKER_ID:NETWATCH_WORKER_SECRET`. The worker ID must not contain a colon.
|
|
298
318
|
|
|
299
|
-
|
|
319
|
+
Testaro sends job requests and completed reports as `POST` requests. When Testaro sends a report to the server, the report is the value of a `report` property in the request body. If `NETWATCH_WORKER_ID` is defined, Testaro also records it as the `sources.agent` property of the report, so the server can attribute the report to this instance under any auth type.
|
|
300
320
|
|
|
301
|
-
|
|
321
|
+
The `AGENT` and `NETWATCH_URL_AUTH` variables of earlier versions are deprecated. Testaro still honors them (as `NETWATCH_WORKER_ID` and as a `pathBody` password, respectively) but warns; rename them.
|
|
302
322
|
|
|
303
323
|
An application can make Testaro poll a server for jobs with:
|
|
304
324
|
|
|
305
325
|
```javaScript
|
|
306
326
|
const {netWatch} = require('testaro/netWatch');
|
|
307
|
-
netWatch(true, 300
|
|
327
|
+
netWatch(true, 300);
|
|
308
328
|
```
|
|
309
329
|
|
|
310
330
|
A user can make Testaro poll a server for jobs with:
|
|
311
331
|
|
|
312
332
|
```bash
|
|
313
|
-
node call netWatch true 300
|
|
333
|
+
node call netWatch true 300
|
|
314
334
|
```
|
|
315
335
|
|
|
316
|
-
The first argument of `netWatch` tells Testaro whether to continue polling after performing the first job. The second argument tells Testaro how many seconds to wait after receiving a no-jobs response before polling again. The third argument tells Testaro whether to be certificate-tolerant, i.e. to accept SSL certificates that fail verification against a list of certificate authorities (the default is `
|
|
336
|
+
The first argument of `netWatch` tells Testaro whether to continue polling after performing the first job. The second argument tells Testaro how many seconds to wait after receiving a no-jobs response before polling again. The optional third argument tells Testaro whether to be certificate-tolerant, i.e. to accept SSL certificates that fail verification against a list of certificate authorities (the default is `false`). Certificate tolerance disables the protection of an `https` connection, exposing credentials and reports to interception, so use it only against servers you control, such as local test servers with self-signed certificates.
|
|
317
337
|
|
|
318
338
|
## Reports
|
|
319
339
|
|
|
@@ -361,6 +381,7 @@ Testaro uses the following techniques to make the rule engines calculate XPaths:
|
|
|
361
381
|
|
|
362
382
|
- `alfa` and `aslint`: They report XPaths, so Testaro needs only to normalize them.
|
|
363
383
|
- `ed11y`: Testaro adds it and a `window.getXPath` method to the page. When the rule engine reports an element, Testaro computes its XPath.
|
|
384
|
+
- `pour` and `surea11y`: Testaro adds the vendored engine bundle and a `window.getXPath` method to the page. Each engine reports a CSS selector for each element; Testaro finds the element in the page via its selector and executes `window.getXPath` on it.
|
|
364
385
|
- `wave`: It reports a selector for each element; Testaro finds each element in the page via its selector and executes `window.getXPath` on the element.
|
|
365
386
|
- `htmlcs`, `ibm`, `nuVal`, `nuVnu`, `qualWeb`: Testaro adds `data-xpath` attributes to all elements. The rule engines include code excerpts, with the `data-xpath` attributes, in the reported violations.
|
|
366
387
|
- `axe`: It reports a selector for each element, and Testaro adds `data-xpath` attributes to all elements. Testaro finds each element in the page via its selector and uses the `data-xpath` attribute. When this fails, Testaro uses the `data-xpath` attribute if its complete value is included in the reported `node.html` value.
|
|
@@ -405,24 +426,49 @@ Details about these expectation properties are documened in the `VALIDATION.md`
|
|
|
405
426
|
|
|
406
427
|
#### Standard results
|
|
407
428
|
|
|
408
|
-
If the job instructs Testaro to include standard results, then the `result.standardResult` property of each act of type `test` will have
|
|
429
|
+
If the job instructs Testaro to include standard results, then the `result.standardResult` property of each act of type `test` will have four properties:
|
|
409
430
|
|
|
410
431
|
- `prevented`: Whether the rule engine was prevented from performing the act
|
|
411
432
|
- `totals`: An array of 4 integers, counting the rule violations at 4 severity levels
|
|
433
|
+
- `outcomeTotals`: An object counting the rule violations by outcome: `{failed, cantTell}`
|
|
412
434
|
- `instances`: An array of data about the violations reported by the rule engine
|
|
413
435
|
|
|
414
436
|
More specifically:
|
|
415
437
|
|
|
416
438
|
- The `totals` value is an array like this: `[3, 0, 87, 4]`. This example would mean that the rule engine reported 3 failures at severity 0 (the least severe level), none at severity 1, 87 at severity 2, and 4 at severity 3. These four severities are conceptually ordinal, not metric.
|
|
439
|
+
- The `outcomeTotals` value is an object like this: `{failed: 87, cantTell: 7}`. It counts the violations (weighted by `count`) that the rule engine asserted versus those it flagged as uncertain.
|
|
417
440
|
- The `instances` value is an array of objects, each having these properties:
|
|
418
|
-
- `
|
|
441
|
+
- `ruleID`: The ID of the rule that was violated
|
|
419
442
|
- `what`: A description of the rule or of the violation
|
|
420
443
|
- `ordinalSeverity`: The severity of the violation
|
|
444
|
+
- `outcome`: `failed` if the rule engine asserted the violation, or `cantTell` if the rule engine reported that it could not determine whether the rule was violated (the vocabulary of the ACT Rules Format). Every instance has an outcome.
|
|
445
|
+
- `uncertainty` (only with `cantTell`, and only if the rule engine gave a reason): One of `not-computable`, `judgement-required`, `runtime-dependent`, `spec-only`, `equivalence-unknown`, `out-of-scope`
|
|
446
|
+
- `needed` (only with `cantTell`, and only if the rule engine said): What a reviewer must determine to resolve the uncertainty
|
|
421
447
|
- `count`: How many violations of the rule this instance reports
|
|
422
448
|
- `catalogIndex`: Key of the HTML element in the catalog
|
|
423
449
|
|
|
424
450
|
If no catalog entry was found for the instance, then instead of a `catalogIndex` property Testaro tries to insert a `pathID` property, whose value is a normalized XPath of the offending HTML element.
|
|
425
451
|
|
|
452
|
+
The `outcome` property is the authoritative certainty signal. In version 78, each tool's `ordinalSeverity` conventions are unchanged from earlier versions: most tools encode uncertainty as a low severity (for example, axe `incomplete` results have severities 0 and 1, and `violations` have severities 2 and 3), so `ordinalSeverity` still mixes certainty with impact, and it mixes them differently per tool. Consumers should read `outcome` for certainty and should not infer it from `ordinalSeverity`. A later major version will redefine `ordinalSeverity` as impact only (0 minor, 1 moderate, 2 serious, 3 critical). Design record: `docs/standard-result-outcome.md`.
|
|
453
|
+
|
|
454
|
+
Testaro's own rules report `failed` unless the rule's entry in `allRules` (in `tests/testaro.ts`) specifies `outcome: 'cantTell'` (for example, `allCaps`, whose violations are AI estimates) or a violation description carries a prefix: `2:` sets severity 2, `2?:` sets severity 2 and outcome `cantTell`, and `?:` sets outcome `cantTell` at the rule's default severity.
|
|
455
|
+
|
|
456
|
+
### Checkpoints
|
|
457
|
+
|
|
458
|
+
A job's acts run in order: a `launch` act opens a page, interaction acts (`button`, `link`, `text`, `press`, `url`, and so on) act on it, and `test` acts run rule engines. A **checkpoint** is a named page state reached by that flow, snapshotted and tested. Checkpoint 0 is the job target as launched; a `checkpoint` act (`{type: 'checkpoint', which: 'name'}`) creates the next one from the live page. A `test` act tests the most recent checkpoint, and each of its standard instances carries the `checkpoint` index. `report.checkpoints[k]` describes each checkpoint: its name, URL, title, the page images (`imageIndexes` into `report.images`), the catalog entries it added (`catalogRange`; every catalog entry also carries `checkpoint`), an ARIA snapshot, and, for a state reached by interaction, the acts (`replay`) that a test act's browser re-enacts after navigating to `launchURL` before the rule engine runs. Each such test act records `data.replay` with the count of replayed acts and a `fidelity` of `exact` or `divergent`, comparing the replayed page's DOM with the snapshot.
|
|
459
|
+
|
|
460
|
+
A job's `isolation` property (or the `ISOLATION` environment default) sets how test acts are isolated: `process` (the default, and the previous behavior) runs each test act in a child process with its own browser; `browser` runs test acts in the job's process, each in a fresh context of one browser shared by the job; `page` runs them in the job's process on the live page of the current checkpoint, with no replay, so tools may contaminate one another's page (contaminating testaro rules still get a fresh page). `jobData.isolation` records the level used. Only `process` isolation kills a tool that overruns its time limit; the others report the act as timed out and continue.
|
|
461
|
+
|
|
462
|
+
When a job has two or more checkpoints, the report gains `flow`, the running list of issues across them. `flow.checkpoints[k]` summarizes each checkpoint (the tools that observed it and its issue count), and `flow.deltas[k - 1]` compares checkpoints `k - 1` and `k`: the issues `added` by the acts between them, those that `persisted`, and those `removed`, each identified by tool, rule ID, element XPath (`pathID`), and start tag, so the same element in two page states is one issue. Only tools that observed both checkpoints are compared (`tools`); the rest are listed as `notObserved`. An earlier issue that a tool did not re-test at the later checkpoint, because its acts there were all scoped to changed subtrees that exclude the issue's element, is listed as `notRetested`, not `removed`. Each delta also carries `structure`, the difference between the two checkpoints' catalogs as XPaths (`added`, `removed`, `changed` start tags, `textChanged`, and the outermost changed elements as `roots`), and `aria`, a line diff of the two ARIA snapshots.
|
|
463
|
+
|
|
464
|
+
Interaction acts can identify their elements by a `selector` property (any Playwright selector, such as `#name`, `text="Continue"`, or `role=button[name="Continue"]`) instead of an element type and text substring; a `text` act with `clear: true` replaces the input's value. With these, a recorded user path (a start URL and actions of the kinds a Playwright recording yields: `click`, `fill`, `select`, `navigate`, `wait`, `checkpoint`) converts directly into a job: `require('testaro/procs/userPath').getUserPathActs({startUrl, actions, testActs})` returns the acts, one per action, with each `checkpoint` action becoming a `checkpoint` act followed by a copy of each test act in `testActs`.
|
|
465
|
+
|
|
466
|
+
When a checkpoint is created, the catalog entries of the previous checkpoint that none of its test acts cited are pruned at once, since no later test act can cite them, so a long flow does not accumulate every page state's catalog in the report that each test act reads.
|
|
467
|
+
|
|
468
|
+
A `test` act may have a `scope` property. The default, `page`, tests the whole page of the act's checkpoint. With `changed`, the act tests only the subtrees that changed since the previous checkpoint (the `roots` of the structure diff, as CSS selectors), for the rules and tools that can be so restricted: the `testaro` rules declared element-local (`local: true` in `allRules`), `axe` (by its `include` context), and `surea11y` (by its context selector, the nearest common ancestor of the roots). Page-level `testaro` rules (heading order, landmarks, duplicate IDs, focus order, hover, motion, and others) and all other tools test the whole page whatever the scope, because any change can alter their verdicts. The act records `data.scope` (`requested`, `applied`, `reason`, `roots`, `pathIDs`, and for `testaro` the `localRules` and `pageRules`), so a reader can see what was and was not re-tested. The act is not scoped, and `jobData.warnings` says why, when there is no previous checkpoint, nothing changed, more than 50 subtrees changed, or the tool cannot restrict itself.
|
|
469
|
+
|
|
470
|
+
Checkpoint acts are optional. A job without one behaves as before: every test act tests checkpoint 0, and interaction acts before a test act only produce a warning in `jobData.warnings`. In a job with checkpoint acts, interaction acts followed by a test act without a checkpoint act produce an implicit checkpoint and a warning. A rule engine that tests a URL rather than a page (WAVE, and the Nu checkers with `withSource`) cannot test a state reached by interaction; such a test act is prevented with the reason. Details: `docs/checkpoint-scanning.md`.
|
|
471
|
+
|
|
426
472
|
## Rule-engine details
|
|
427
473
|
|
|
428
474
|
The rule engines whose tests Testaro performs have particularities described below.
|
|
@@ -494,6 +540,10 @@ The `nuVal` and `nuVnu` rule engines perform the tests of the Nu Html Checker. T
|
|
|
494
540
|
|
|
495
541
|
Its `rules` argument is **not** an array of rule IDs, but instead is an array of rule _specifications_. A rule specification for `nuVal` or `nuVnu` is a string with the format `=ruleID` or `~ruleID`. The `=` prefix indicates that the rule ID is invariable. The `~` prefix indicates that the rule ID is variable, in which case the `ruleID` part of the specification is a matching regular expression, rather than the exact text of a message. This `rules` format arises from the fact that `nuVal` and `nuVnu` generate customized messages and do not accompany them with rule identifiers.
|
|
496
542
|
|
|
543
|
+
### Pour Engine
|
|
544
|
+
|
|
545
|
+
The `pour` rule engine makes use of the `pour/pour.min.js` file, a bundle that Testaro builds from the upstream [pour-engine](https://github.com/pourdev/pour-engine) repository (MIT), because upstream publishes no distributable bundle. The `pour/README.md` file documents the build command and the pinned upstream version. Testaro injects the bundle into the page and runs every rule. Findings in the engine's `violations` bucket become standard instances with outcome `failed`; findings in its `incomplete` bucket become instances with outcome `cantTell`. The engine's `passes`, `inapplicable`, and `manualReview` buckets are tallied in the act's `data` property and never become instances. If the bundle is missing or fails to define its global, the act is reported as prevented.
|
|
546
|
+
|
|
497
547
|
### QualWeb
|
|
498
548
|
|
|
499
549
|
The `qualWeb` rule engine performs the ACT rules, WCAG Techniques, and best-practices tests of QualWeb. Only failures and warnings are included in the report. The EARL report of QualWeb is not generated, because it is equivalent to the report of the ACT rules tests.
|
|
@@ -519,13 +569,17 @@ Thus, when the `rules` argument is omitted, QualWeb will test for all of the rul
|
|
|
519
569
|
|
|
520
570
|
The target can be provided to QualWeb either as HTML or as a URL. Experience indicates that the results can differ between these methods, with each method reporting some rule violations or some instances that the other method does not report. For at least some cases, more rules are reported violated when HTML is provided (`withNewItems: false`).
|
|
521
571
|
|
|
522
|
-
QualWeb creates sandboxed
|
|
572
|
+
QualWeb creates sandboxed Playwright pages to perform its tests on. Therefore, the host must permit sandboxed browsers to be launched. See the discussion above about browser security.
|
|
573
|
+
|
|
574
|
+
### SureA11y
|
|
575
|
+
|
|
576
|
+
The `surea11y` rule engine makes use of the `surea11y/surea11y.browser.js` file, the standalone browser bundle that [`@surea11y/core`](https://github.com/SureA11y/core) publishes, vendored verbatim. That package is licensed under the Mozilla Public License 2.0, unlike the MIT-licensed or Apache-licensed rule engines; the vendored file must not be modified. The `surea11y/README.md` file documents the pinned upstream version and the result shape. Testaro injects the bundle into the page and runs every automatic rule. The engine reports an outcome per rule (`pass`, `fail`, `cantTell`, or `notApplicable`) and may grade individual occurrences of a `fail` rule as `cantTell`. Occurrences graded `fail` become standard instances with outcome `failed`; occurrences graded `cantTell` become instances with outcome `cantTell`, carrying the engine's `uncertainty` code and `needed` guidance when it supplies them. Rules of type `manual` and rules with outcome `pass` or `notApplicable` are tallied in the act's `data` property and never become instances.
|
|
523
577
|
|
|
524
578
|
### Testaro
|
|
525
579
|
|
|
526
580
|
The rules that Testaro can test for are implemented in files within the `testaro` directory.
|
|
527
581
|
|
|
528
|
-
The Testaro rules are classified by an `allRules` array defined in the `tests/testaro.
|
|
582
|
+
The Testaro rules are classified by an `allRules` array defined in the `tests/testaro.ts` file. Each item in that array is an object with these properties:
|
|
529
583
|
|
|
530
584
|
- `id`: the rule ID.
|
|
531
585
|
- `what`: a description of the rule.
|
|
@@ -558,7 +612,7 @@ If you want the stand-alone API to perform the tests, you need to have that API
|
|
|
558
612
|
|
|
559
613
|
You can define additional Testaro rules and functionality. Contributions are welcome.
|
|
560
614
|
|
|
561
|
-
Please report any issues, including feature requests, at the [repository](https://github.com/
|
|
615
|
+
Please report any issues, including feature requests, at the [repository](https://github.com/YRA-Tech/testaro/issues).
|
|
562
616
|
|
|
563
617
|
## Accessibility principles
|
|
564
618
|
|
|
@@ -654,7 +708,7 @@ From 12 February 2024 through 30 September 2025, contributors of code to Testaro
|
|
|
654
708
|
|
|
655
709
|
## Future work
|
|
656
710
|
|
|
657
|
-
Future work contemplated for this project is described in its [issues](https://github.com/
|
|
711
|
+
Future work contemplated for this project is described in its [issues](https://github.com/YRA-Tech/testaro/issues) and also discussed in the [UPGRADES.md](UPGRADES.md) file.
|
|
658
712
|
|
|
659
713
|
## Etymology
|
|
660
714
|
|
package/UPGRADES.md
CHANGED
|
@@ -8720,3 +8720,7 @@ you'll get notified when `#334` merges and when the subsequent changesets "Versi
|
|
|
8720
8720
|
- **Re-test**: run a job with a `qualWeb` act and confirm the `No DOM` error is gone before merging your `qwpw` branch.
|
|
8721
8721
|
|
|
8722
8722
|
I'll be ready to help with the dependency bump and verification when that release lands.
|
|
8723
|
+
|
|
8724
|
+
# Certainty in the standard result (2026-09-01)
|
|
8725
|
+
|
|
8726
|
+
Decision: add a first-class `outcome` (`failed` | `cantTell`) to every standard instance, with optional `uncertainty` (six ACT-style codes borrowed from surea11y) and `needed` (reviewer guidance), plus `standardResult.outcomeTotals`. `ordinalSeverity` and `totals` are unchanged in 78.x; a later major version redefines `ordinalSeverity` as impact only. This follows the `allCaps` ruling above (do not overload `ordinalSeverity` with confidence) by giving certainty its own field rather than by hiding it in `what`. Shared shape helpers live in `procs/standard.js`; the alfa adapter no longer rewrites rule IDs to `cantTell` / `cantTellTextContrast`. Full design, including the recommended Testilo tic consolidation of the 57 `*Risk` issues and certainty-aware scoring: `docs/standard-result-outcome.md`.
|
package/actSpecs-doc.md
CHANGED
|
@@ -55,9 +55,13 @@ The validity criterion named in item 2 may be any of these:
|
|
|
55
55
|
- `'isWaitable'`: is `'url'`, `'title'`, or `'body'`
|
|
56
56
|
- `'areStrings'`: is an array of strings
|
|
57
57
|
|
|
58
|
+
## qualWeb tool
|
|
59
|
+
|
|
60
|
+
A `qualWeb` test act may have `stealth` and `adBlock` boolean properties, which set whether the tool's browser runs stealth evasions and blocks ads and trackers (defaults `QUALWEB_STEALTH` and `QUALWEB_ADBLOCK`, else true).
|
|
61
|
+
|
|
58
62
|
## testaro tool
|
|
59
63
|
|
|
60
|
-
The `tools.testaro` object has an `args` property specifying that a `testaro` test act may include an `args` property with an object value.
|
|
64
|
+
The `tools.testaro` object has a `retries` property (launch retries per rule; default `TESTARO_RULE_RETRIES`, else 2) and an `args` property specifying that a `testaro` test act may include an `args` property with an object value.
|
|
61
65
|
|
|
62
66
|
If it does, the property names of the object value must be `testaro` rule IDs. Any property value must be an array of the positional arguments to be concatenated to the four default arguments (`page`, `report`, `actIndex`, and `withItems`) in the signature of the `reporter` function of each `testaro` rule.
|
|
63
67
|
|
|
@@ -84,3 +88,11 @@ Licensed under the [MIT License](https://opensource.org/license/mit/). See [LICE
|
|
|
84
88
|
at the project root for details.
|
|
85
89
|
|
|
86
90
|
SPDX-License-Identifier: MIT
|
|
91
|
+
|
|
92
|
+
## Checkpoint acts
|
|
93
|
+
|
|
94
|
+
The move acts (`button`, `checkbox`, `link`, `radio`, `search`, `select`, `text`) may have a `selector` property, any Playwright selector, which replaces the act type's element selector and the text matching of `which`; `index` still selects among the matches. A `checkbox` or `radio` act must have `which` or `selector`. A `text` act with `clear: true` replaces the input's value instead of appending to it. A `select` act whose `what` matches no option text falls back to Playwright's matching of `what` as an option value or label. `procs/userPath.js` builds acts of these kinds from a recorded user path.
|
|
95
|
+
|
|
96
|
+
A `test` act may have a `scope` property: `page` (the default) tests the whole page of the act's checkpoint; `changed` tests only the subtrees that changed since the previous checkpoint, for the rules and tools that can be so restricted (the element-local `testaro` rules, `axe`, and `surea11y`), and the whole page for the rest. A job with a changed-scope test act must have a checkpoint act. The act records what it was given as `data.scope`. See `docs/checkpoint-scanning.md`.
|
|
97
|
+
|
|
98
|
+
A `checkpoint` act snapshots the current page state as a checkpoint that subsequent `test` acts observe. Its `which` property names the checkpoint (unique within the job, and not `start`, the name of checkpoint 0). A checkpoint act must follow a `launch` act. See `docs/checkpoint-scanning.md`.
|
package/actSpecs.js
CHANGED
|
@@ -19,15 +19,24 @@ exports.actSpecs = {
|
|
|
19
19
|
button: [
|
|
20
20
|
'Click a button or submit input',
|
|
21
21
|
{
|
|
22
|
+
selector: [false, 'string', 'hasLength', 'Playwright selector of the element, instead of an element type and text substring'],
|
|
22
23
|
which: [false, 'string', 'hasLength', 'substring of button text'],
|
|
23
24
|
index: [false, 'number', '', 'index among matches if not 0'],
|
|
24
25
|
what: [false, 'string', 'hasLength', 'comment']
|
|
25
26
|
}
|
|
26
27
|
],
|
|
28
|
+
checkpoint: [
|
|
29
|
+
'Snapshot the current page state (catalog, page image, ARIA snapshot) as a checkpoint that subsequent test acts observe',
|
|
30
|
+
{
|
|
31
|
+
which: [true, 'string', 'hasLength', 'checkpoint name, unique within the job'],
|
|
32
|
+
what: [false, 'string', 'hasLength', 'comment']
|
|
33
|
+
}
|
|
34
|
+
],
|
|
27
35
|
checkbox: [
|
|
28
36
|
'Check a checkbox',
|
|
29
37
|
{
|
|
30
|
-
|
|
38
|
+
selector: [false, 'string', 'hasLength', 'Playwright selector of the element, instead of an element type and text substring'],
|
|
39
|
+
which: [false, 'string', 'hasLength', 'substring of checkbox text (required unless selector is given)'],
|
|
31
40
|
index: [false, 'number', '', 'index among matches if not 0'],
|
|
32
41
|
what: [false, 'string', 'hasLength', 'comment']
|
|
33
42
|
}
|
|
@@ -52,6 +61,7 @@ exports.actSpecs = {
|
|
|
52
61
|
link: [
|
|
53
62
|
'Click a link and wait for the page to be idle or loaded',
|
|
54
63
|
{
|
|
64
|
+
selector: [false, 'string', 'hasLength', 'Playwright selector of the element, instead of an element type and text substring'],
|
|
55
65
|
which: [false, 'string', 'hasLength', 'substring of link text'],
|
|
56
66
|
index: [false, 'number', '', 'index among matches if not 0'],
|
|
57
67
|
what: [false, 'string', 'hasLength', 'comment']
|
|
@@ -96,7 +106,8 @@ exports.actSpecs = {
|
|
|
96
106
|
radio: [
|
|
97
107
|
'Check a radio button',
|
|
98
108
|
{
|
|
99
|
-
|
|
109
|
+
selector: [false, 'string', 'hasLength', 'Playwright selector of the element, instead of an element type and text substring'],
|
|
110
|
+
which: [false, 'string', 'hasLength', 'substring of radio-button text (required unless selector is given)'],
|
|
100
111
|
index: [false, 'number', '', 'index among matches if not 0'],
|
|
101
112
|
what: [false, 'string', 'hasLength', 'comment']
|
|
102
113
|
}
|
|
@@ -110,6 +121,7 @@ exports.actSpecs = {
|
|
|
110
121
|
search: [
|
|
111
122
|
'Enter text into a search input, optionally with 1 placeholder for an all-caps literal environment variable',
|
|
112
123
|
{
|
|
124
|
+
selector: [false, 'string', 'hasLength', 'Playwright selector of the element, instead of an element type and text substring'],
|
|
113
125
|
which: [false, 'string', 'hasLength', 'substring of input text'],
|
|
114
126
|
index: [false, 'number', '', 'index among matches if not 0'],
|
|
115
127
|
what: [true, 'string', 'hasLength', 'text to enter, with optional __PLACEHOLDER__']
|
|
@@ -118,6 +130,7 @@ exports.actSpecs = {
|
|
|
118
130
|
select: [
|
|
119
131
|
'Select a select option',
|
|
120
132
|
{
|
|
133
|
+
selector: [false, 'string', 'hasLength', 'Playwright selector of the element, instead of an element type and text substring'],
|
|
121
134
|
which: [false, 'string', 'hasLength', 'substring of select-list text'],
|
|
122
135
|
index: [false, 'number', '', 'index among matches if not 0'],
|
|
123
136
|
what: [true, 'string', 'hasLength', 'substring of option text content']
|
|
@@ -144,15 +157,18 @@ exports.actSpecs = {
|
|
|
144
157
|
{
|
|
145
158
|
which: [true, 'string', 'isTest', 'tool name'],
|
|
146
159
|
launch: [false, 'object', '', 'new target, browserID, and/or what, if any'],
|
|
147
|
-
rules: [false, 'array', 'areStrings', 'rule IDs or (for testaro, nuVal, or nuVnu) specifications, if not all']
|
|
160
|
+
rules: [false, 'array', 'areStrings', 'rule IDs or (for testaro, nuVal, or nuVnu) specifications, if not all'],
|
|
161
|
+
scope: [false, 'string', 'isScope', 'page (default) or changed (only the subtrees changed since the previous checkpoint, for rules and tools that can be so restricted)']
|
|
148
162
|
}
|
|
149
163
|
],
|
|
150
164
|
text: [
|
|
151
165
|
'Enter text into a text input, optionally with 1 placeholder for an all-caps literal environment variable',
|
|
152
166
|
{
|
|
167
|
+
selector: [false, 'string', 'hasLength', 'Playwright selector of the element, instead of an element type and text substring'],
|
|
153
168
|
which: [false, 'string', 'hasLength', 'substring of input text'],
|
|
154
169
|
index: [false, 'number', '', 'index among matches if not 0'],
|
|
155
|
-
what: [true, 'string', 'hasLength', 'text to enter, with optional __PLACEHOLDER__']
|
|
170
|
+
what: [true, 'string', 'hasLength', 'text to enter, with optional __PLACEHOLDER__'],
|
|
171
|
+
clear: [false, 'boolean', '', 'whether to replace any existing value instead of appending']
|
|
156
172
|
}
|
|
157
173
|
],
|
|
158
174
|
url: [
|
|
@@ -196,12 +212,20 @@ exports.actSpecs = {
|
|
|
196
212
|
withSource: [false, 'boolean', '', 'whether to use the page source and not the browser page']
|
|
197
213
|
}
|
|
198
214
|
],
|
|
215
|
+
qualWeb: [
|
|
216
|
+
'Perform QualWeb tests',
|
|
217
|
+
{
|
|
218
|
+
stealth: [false, 'boolean', '', 'whether the browser runs stealth evasions (default QUALWEB_STEALTH, else true)'],
|
|
219
|
+
adBlock: [false, 'boolean', '', 'whether the browser blocks ads and trackers (default QUALWEB_ADBLOCK, else true)']
|
|
220
|
+
}
|
|
221
|
+
],
|
|
199
222
|
testaro: [
|
|
200
223
|
'Perform Testaro tests',
|
|
201
224
|
{
|
|
202
225
|
withItems: [true, 'boolean', '', 'itemize'],
|
|
203
226
|
stopOnFail: [true, 'boolean', '', 'whether testing is to stop after first failure'],
|
|
204
|
-
args: [false, 'object', 'areArrays', 'extra arguments of rules taking any']
|
|
227
|
+
args: [false, 'object', 'areArrays', 'extra arguments of rules taking any'],
|
|
228
|
+
retries: [false, 'number', '', 'launch retries per rule (default TESTARO_RULE_RETRIES, else 2)']
|
|
205
229
|
}
|
|
206
230
|
],
|
|
207
231
|
wave: [
|
package/call.js
CHANGED
|
@@ -45,8 +45,8 @@ const callRun = async jobIDStart => {
|
|
|
45
45
|
const jobDirFileNames = await fs.readdir(todoDir);
|
|
46
46
|
const jobFileNames = jobDirFileNames.filter(fileName => fileName.endsWith('.json'));
|
|
47
47
|
const specifiedJobFileNames = jobIDStart
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
? jobFileNames.filter(fileName => fileName.startsWith(jobIDStart))
|
|
49
|
+
: jobFileNames;
|
|
50
50
|
const jobFileName = specifiedJobFileNames[0];
|
|
51
51
|
// If it exists:
|
|
52
52
|
if (jobFileName) {
|
|
@@ -74,7 +74,7 @@ const callDirWatch = async (isForever, intervalInSeconds) => {
|
|
|
74
74
|
};
|
|
75
75
|
// Starts a network watch, converting the interval argument to a number.
|
|
76
76
|
const callNetWatch = async (isForever, intervalInSeconds, isCertTolerant) => {
|
|
77
|
-
await netWatch(
|
|
77
|
+
return await netWatch(
|
|
78
78
|
isForever === 'true',
|
|
79
79
|
Number.parseInt(intervalInSeconds, 10),
|
|
80
80
|
isCertTolerant ? isCertTolerant === 'true' : undefined
|
|
@@ -100,9 +100,10 @@ else if (fn === 'dirWatch' && fnArgs.length === 2) {
|
|
|
100
100
|
}
|
|
101
101
|
else if (fn === 'netWatch' && [2, 3].includes(fnArgs.length)) {
|
|
102
102
|
callNetWatch(... fnArgs)
|
|
103
|
-
.then(
|
|
103
|
+
.then(isOK => {
|
|
104
104
|
console.log('Network watch ended');
|
|
105
|
-
|
|
105
|
+
// Exit with a failure code if the watch was misconfigured or aborted, so supervisors notice.
|
|
106
|
+
process.exit(isOK ? 0 : 1);
|
|
106
107
|
});
|
|
107
108
|
}
|
|
108
109
|
else {
|
package/docker-compose.yml
CHANGED
|
@@ -26,10 +26,16 @@ services:
|
|
|
26
26
|
# Send nuVal requests to the sidecar instead of the W3C service.
|
|
27
27
|
TESTARO_NU_URL: "http://nu:8888/?parser=html&out=json"
|
|
28
28
|
# JODBIR and REPORTDIR from Dockerfile override those from .env.
|
|
29
|
-
# Import other specific environment variables from .env file.
|
|
30
|
-
|
|
29
|
+
# Import other specific environment variables from .env file. The
|
|
30
|
+
# NETWATCH_* variables default to empty so that directory-watch use
|
|
31
|
+
# needs no .env entries for them; set them in .env for server polling.
|
|
31
32
|
WAVE_KEY: ${WAVE_KEY}
|
|
32
33
|
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
|
|
34
|
+
NETWATCH_URL_JOB: ${NETWATCH_URL_JOB:-}
|
|
35
|
+
NETWATCH_URL_REPORT: ${NETWATCH_URL_REPORT:-}
|
|
36
|
+
NETWATCH_AUTH_TYPE: ${NETWATCH_AUTH_TYPE:-}
|
|
37
|
+
NETWATCH_WORKER_ID: ${NETWATCH_WORKER_ID:-}
|
|
38
|
+
NETWATCH_WORKER_SECRET: ${NETWATCH_WORKER_SECRET:-}
|
|
33
39
|
volumes:
|
|
34
40
|
# Host directories for jobs and reports. The container runs as the
|
|
35
41
|
# unprivileged pwuser; the host directories must be writable by it
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# Checkpoints: scanning across a serial action flow
|
|
2
|
+
|
|
3
|
+
**Status:** Phases 0, 1, and 1b shipped in Testaro 78.2 (2026-09-02); Phases 2 (`report.flow`),
|
|
4
|
+
3 (`scope: 'changed'`), and 4 (incremental pruning, selector acts, the user-path converter)
|
|
5
|
+
shipped in 78.3 (2026-09-02). The interaction modalities and the yra-monitor ingestion changes
|
|
6
|
+
remain follow-ups.
|
|
7
|
+
|
|
8
|
+
## Why
|
|
9
|
+
|
|
10
|
+
A job is a serial list of acts: launch a browser, interact with the page, test it. Until 78.2,
|
|
11
|
+
the interaction acts had no effect on any test: every `test` act ran in a child process that
|
|
12
|
+
launched its own browser and navigated to the job target, and the element catalog was built
|
|
13
|
+
once, before any act, for that same page. A job of the form launch → click → test therefore
|
|
14
|
+
tested the page as first loaded, and any test after a `url` act resolved its elements against
|
|
15
|
+
the wrong page's catalog.
|
|
16
|
+
|
|
17
|
+
The maintainer's goals: keep the serial action flow; keep or extend a running list of found
|
|
18
|
+
issues as the flow progresses; use explicit triggers for re-scanning rather than re-running
|
|
19
|
+
every tool after every action; and re-scan either the whole page or only the parts that
|
|
20
|
+
changed, as the case requires.
|
|
21
|
+
|
|
22
|
+
## The model
|
|
23
|
+
|
|
24
|
+
A **checkpoint** is a named page state reached by the flow, snapshotted and tested:
|
|
25
|
+
|
|
26
|
+
- **Checkpoint 0** is the job target as launched. `getCatalog` creates it before any act, as
|
|
27
|
+
it always built the catalog, and records it as `report.checkpoints[0]` (named `start`).
|
|
28
|
+
- A **`checkpoint` act** (`{type: 'checkpoint', which: '<name>'}`) creates the next one from
|
|
29
|
+
the live page in the parent process: catalog entries for the current state, page image(s)
|
|
30
|
+
if the job asks for them, the URL and title, an ARIA snapshot, and a DOM digest.
|
|
31
|
+
- A **`test` act belongs to the most recent checkpoint** (`act.checkpoint`), and every
|
|
32
|
+
standard instance it reports carries `checkpoint`.
|
|
33
|
+
|
|
34
|
+
Checkpoint mode is opt-in: it is on only when the job contains a `checkpoint` act. Legacy
|
|
35
|
+
jobs (no such act) run as before and produce today's report plus the `checkpoint: 0` fields;
|
|
36
|
+
if interaction acts precede a test act in a legacy job, `jobData.warnings` says that the act
|
|
37
|
+
tests checkpoint 0. In checkpoint mode, interaction acts followed by a test act without an
|
|
38
|
+
intervening checkpoint produce an implicit checkpoint (named `act<N>`) and a warning; the
|
|
39
|
+
warning never fails the job.
|
|
40
|
+
|
|
41
|
+
### Navigation and interaction checkpoints
|
|
42
|
+
|
|
43
|
+
A checkpoint is a **navigation checkpoint** when the page was reached by navigation alone
|
|
44
|
+
(a `launch` or `url` act) and no interaction act ran since; it is an **interaction
|
|
45
|
+
checkpoint** when acts on a page (button, link, text, press, reveal, …) reached it. The
|
|
46
|
+
distinction decides how a test act's browser reaches the state:
|
|
47
|
+
|
|
48
|
+
- Navigation checkpoint: the child navigates to the checkpoint's URL. Every tool runs.
|
|
49
|
+
- Interaction checkpoint: the child navigates to the URL the interaction started from
|
|
50
|
+
(`launchURL`) and **replays** the recorded interaction acts (`replay`, act indexes) before
|
|
51
|
+
running the tool. The replay happens inside `launchOnce` after navigation and before any
|
|
52
|
+
`data-xpath` stamping, so elements the acts reveal or create are stamped like the rest,
|
|
53
|
+
and every per-rule relaunch of a contaminating testaro rule replays automatically.
|
|
54
|
+
|
|
55
|
+
Replay is a re-enactment, not a restore. Server state, sessions, timers and randomness can
|
|
56
|
+
make the replayed DOM differ from the snapshot. Each test act records
|
|
57
|
+
`data.replay = {checkpoint, acts, elapsedMs, fidelity}` where `fidelity` is `exact` when
|
|
58
|
+
the replayed DOM's digest equals the checkpoint's, else `divergent`. A replay failure
|
|
59
|
+
prevents the test act with `checkpoint replay failed at act N (…)` and is not retried.
|
|
60
|
+
|
|
61
|
+
### What each tool can observe
|
|
62
|
+
|
|
63
|
+
`procs/job.js` `toolInputs` declares what a tool tests:
|
|
64
|
+
|
|
65
|
+
| input | tools | interaction checkpoints |
|
|
66
|
+
| --- | --- | --- |
|
|
67
|
+
| `page` | alfa, aslint, axe, ed11y, htmlcs, ibm, pour, surea11y, testaro | yes (replayed page) |
|
|
68
|
+
| `html` | qualWeb, nuVal, nuVnu (they read the live page's HTML) | yes (replayed page) |
|
|
69
|
+
| `url` | wave; nuVal and nuVnu with `withSource: true` | no: prevented with a stated reason |
|
|
70
|
+
|
|
71
|
+
### Report shape
|
|
72
|
+
|
|
73
|
+
- `report.checkpoints[k]`: `{index, name, implicit, actIndex, launchActIndex, launchURL,
|
|
74
|
+
replay, interaction: {modality}, kind: 'navigation' | 'interaction', url, title,
|
|
75
|
+
imageIndexes, catalogRange, elementCount, ariaSnapshot, domDigest, elapsedMs, testActs}`.
|
|
76
|
+
- `report.catalog` stays one flat map. Entries carry `checkpoint`; indexes come from a
|
|
77
|
+
monotonic job-time counter (`report.catalogNextIndex`), so entries of different checkpoints
|
|
78
|
+
never collide, and the job-time `report.pathIDs` is scoped per checkpoint so the same XPath
|
|
79
|
+
in two states maps to two entries. Pruning keeps only cited entries, as before.
|
|
80
|
+
- `report.images`: `images[0]` (and `[1]` at `imageScale > 1`) keep meaning checkpoint 0;
|
|
81
|
+
later checkpoints' images are indexed by `checkpoints[k].imageIndexes`. The testaro `motion`
|
|
82
|
+
rule compares against its checkpoint's image.
|
|
83
|
+
- `jobData.catalogData.checkpoints[k]`: element and entry counts per checkpoint.
|
|
84
|
+
- `report.flow` (two or more checkpoints): `{checkpoints: [{index, name, kind, url, actIndex,
|
|
85
|
+
testActs, tools, issueCount}], deltas: [{from, to, tools, notObserved, added, persisted,
|
|
86
|
+
removed, notRetested, structure, aria}]}`; each issue is `{tool, ruleID, pathID, startTag,
|
|
87
|
+
what, ordinalSeverity, outcome, count, actIndexes}`.
|
|
88
|
+
- Test acts: `scope` (`page` default or `changed`) and `data.scope = {requested, applied,
|
|
89
|
+
reason, roots, pathIDs, commonRoot, localRules?, pageRules?}`. Job-time only, deleted by
|
|
90
|
+
`pruneCatalog`: `report.scope`, `report.ruleScopeRoots`.
|
|
91
|
+
- Progress events: `checkpointStart` and `checkpointEnd` (with `kind` and `elapsedMs`);
|
|
92
|
+
`actEnd` carries `checkpoint`.
|
|
93
|
+
|
|
94
|
+
### Interaction modality (planned)
|
|
95
|
+
|
|
96
|
+
The act executors live in `procs/actDo.js` and take an `interaction` option
|
|
97
|
+
(`{modality: 'efficient'}` today), recorded on each checkpoint so replay uses the same
|
|
98
|
+
modality. Low-level events (`mousedown`/`mouseup`), emulated human mouse travel and key
|
|
99
|
+
pauses, and pass-to-pass comparisons between modalities are designed to slot in there.
|
|
100
|
+
|
|
101
|
+
## Phases
|
|
102
|
+
|
|
103
|
+
- **Phase 0 (shipped):** act-loop repairs (`next` acts, failed launches, the `url` and
|
|
104
|
+
`state` acts), `procs/actDo.js`, `procs/xPathScript.js`, `catalogPage`, checkpoint 0.
|
|
105
|
+
- **Phase 1 (shipped):** the `checkpoint` act, `procs/checkpoint.js`, replay in the
|
|
106
|
+
launcher, implicit checkpoints, tool gating, the `validation/tests/jobProperties/checkpoint`
|
|
107
|
+
validator with report-level expectations.
|
|
108
|
+
- **Phase 1b (shipped):** the `isolation` job property (or the `ISOLATION` environment
|
|
109
|
+
default): `process` (the default: a child process and browser per test act), `browser`
|
|
110
|
+
(one browser shared by the job's launches, a fresh context per test act, replay), `page`
|
|
111
|
+
(tools run in sequence in the job's process on the live checkpoint page, no replay;
|
|
112
|
+
contaminating testaro rules still get a fresh context with replay). `procs/testAct.js`
|
|
113
|
+
performs a test act for both the child process and the in-process levels; the launcher
|
|
114
|
+
keeps the shared browser and prepares a live page (XPath script or attributes, accessible
|
|
115
|
+
names) without changing its DOM. Recorded in `jobData.isolation`. Only `process` can kill a
|
|
116
|
+
tool that overruns its time limit; the others report the act as timed out and continue.
|
|
117
|
+
- **Phase 2 (shipped):** `report.flow` (`procs/flow.js`, `getFlow(report)`), added at job end
|
|
118
|
+
before pruning when the job has two or more checkpoints, and usable standalone on a stored
|
|
119
|
+
report (the structure diff then covers cited elements only). `flow.checkpoints[k]`
|
|
120
|
+
summarizes each checkpoint; `flow.deltas[k - 1]` compares checkpoints `k - 1` and `k`:
|
|
121
|
+
`added`, `persisted`, and `removed` issues with identity `tool | ruleID | pathID | startTag`
|
|
122
|
+
(box and text excluded, since layout and copy shift without the defect changing; a summary
|
|
123
|
+
instance has an empty element key), compared only for the `tools` that observed both
|
|
124
|
+
checkpoints with a non-prevented act (`notObserved` lists the rest); `structure`, the
|
|
125
|
+
catalog diff (`procs/scope.js`, `getStructureDiff`): `added`, `removed`, and `changed`
|
|
126
|
+
(start tag) XPaths, `textChanged` XPaths, and `roots`, the outermost changed elements (the
|
|
127
|
+
nearest surviving ancestor stands for a removed element; a text change counts only where no
|
|
128
|
+
descendant changed, because the catalog text of an element includes its descendants'); and
|
|
129
|
+
`aria`, a line diff of the ARIA snapshots (`diff`, the jsdiff library yra-monitor also uses;
|
|
130
|
+
at most 500 changed lines recorded, `truncated` otherwise).
|
|
131
|
+
- **Phase 3 (shipped):** `scope: 'page' | 'changed'` on test acts (`actSpecs.js`; a job with a
|
|
132
|
+
changed-scope act must have a checkpoint act). Before such an act the acts loop calls
|
|
133
|
+
`getChangedRoots(report, k)`, which converts the structure roots of the diff between
|
|
134
|
+
checkpoints `k - 1` and `k` to CSS selectors (`/html/body/main[1]/div[2]` becomes
|
|
135
|
+
`html > body > main:nth-of-type(1) > div:nth-of-type(2)`, exact because `getXPath`
|
|
136
|
+
subscripts among same-tag siblings, which is what `nth-of-type` counts) and gives them to
|
|
137
|
+
the tool as the job-time `report.scope` when the tool is in `toolScopes` (`procs/job.js`:
|
|
138
|
+
axe, surea11y, testaro). The act records `data.scope`; when the act cannot be scoped (no
|
|
139
|
+
previous checkpoint, no change, more than `maxRoots` = 50 roots, an XPath with no selector,
|
|
140
|
+
a tool without a root option) it tests the whole page with `applied: false` and a reason,
|
|
141
|
+
and `jobData.warnings` says so. axe takes the roots as its `include` context; surea11y takes
|
|
142
|
+
the nearest common ancestor of the roots (`commonRoot`), since its context is one selector;
|
|
143
|
+
the testaro tool sets `report.ruleScopeRoots` per rule to the roots for a rule with
|
|
144
|
+
`local: true` in `allRules` and to null otherwise, and `doTest` keeps only candidates inside
|
|
145
|
+
a root (`getBasicResult` rules, hover and role, are not local). The conservative first-pass
|
|
146
|
+
classification marks as not local: allHidden, bulk, docType, dupAtt, headEl, headingAmb,
|
|
147
|
+
secHeading, linkAmb, labClash, radioSet, styleDiff, targetsNear, title, motion, role, hover,
|
|
148
|
+
hovInd, focAll, focAndOp, focInd, focVis, tabNav, buttonMenu, elements, textNodes. Whether a
|
|
149
|
+
partial scan is valid is not automated; the author chooses per act, and the rule metadata
|
|
150
|
+
protects the choice. Limits: the diff is by XPath, so inserting one sibling shifts later
|
|
151
|
+
same-tag indexes and the changed set can grow to the container (correct but coarse); a
|
|
152
|
+
changed-scope act finds only defects inside the roots, so `flow` unions the findings of every
|
|
153
|
+
act at a checkpoint rather than trusting one act.
|
|
154
|
+
- **Phase 4 (shipped):** three parts.
|
|
155
|
+
- *Incremental pruning.* When checkpoint `k + 1` is created, `makeCheckpoint` first records
|
|
156
|
+
the structure diff between `k` and `k + 1` on the new checkpoint (job-time
|
|
157
|
+
`checkpoints[k + 1].structure`, which `getChangedRoots` and `getFlow` read instead of
|
|
158
|
+
recomputing, and which the acts loop deletes once `flow` holds it), then calls
|
|
159
|
+
`pruneCheckpoint(report, k)` (`procs/catalog.ts`), which deletes checkpoint `k`'s entries
|
|
160
|
+
that no test act of checkpoint `k` cites and drops its job-time XPath map. No later test
|
|
161
|
+
act can cite checkpoint `k`, since a test act belongs to the latest checkpoint, so the
|
|
162
|
+
temporary report that every test act reads stays bounded by one checkpoint's page plus
|
|
163
|
+
the cited entries of earlier ones. `catalogData.elementCount` is therefore the count of
|
|
164
|
+
entries ever made (`catalogNextIndex`), not the count at pruning time. A single-checkpoint
|
|
165
|
+
job is unaffected.
|
|
166
|
+
- *Selector acts.* The move acts (`button`, `checkbox`, `link`, `radio`, `search`, `select`,
|
|
167
|
+
`text`) accept a `selector` property, any Playwright selector (CSS, `text=`, `role=`,
|
|
168
|
+
`label=`), which replaces the act type's element selector and text matching; `index`
|
|
169
|
+
still picks among matches. A `text` act with `clear: true` replaces the input's value
|
|
170
|
+
instead of appending to it, and a `select` act whose `what` matches no option text falls
|
|
171
|
+
back to Playwright's value-or-label matching. Replay uses the same executors, so
|
|
172
|
+
selector acts replay like the rest.
|
|
173
|
+
- *User-path converter.* `procs/userPath.js` `getUserPathActs({startUrl, actions,
|
|
174
|
+
testActs, scanAtCheckpoints, what})` maps a recorded user path of the shape yra-monitor
|
|
175
|
+
stores (actions `click`, `fill`, `select`, `navigate`, `wait`, `checkpoint`, with
|
|
176
|
+
Playwright selectors) to a job's acts: launch, then one act per action (`button`, `text`
|
|
177
|
+
with `clear`, `select`, `url`, `state: idle` for a pause), and for each `checkpoint`
|
|
178
|
+
action a `checkpoint` act (named from its label, made unique) followed by a copy of each
|
|
179
|
+
requested test act, with `scope: 'changed'` downgraded to `page` at the first checkpoint.
|
|
180
|
+
The `userPath` validator runs the converter's output for a fill, select, checkpoint,
|
|
181
|
+
click, wait, checkpoint, navigate, checkpoint path. yra-monitor's user-path executor still
|
|
182
|
+
replays actions itself and runs a stub axe scan at checkpoints; replacing that with a
|
|
183
|
+
Testaro job built by this converter waits on the ingestion changes below.
|
|
184
|
+
- `flow` and scoped acts: a tool whose acts at a checkpoint were all scoped to changed
|
|
185
|
+
subtrees observed nothing outside them, so an earlier issue of that tool whose element
|
|
186
|
+
lies outside the roots is listed in the delta as `notRetested`, not `removed`.
|
|
187
|
+
|
|
188
|
+
## Relationship to yra-monitor
|
|
189
|
+
|
|
190
|
+
yra-monitor's DOM-difference feature captures outerHTML, a screenshot, element positions
|
|
191
|
+
and the ARIA snapshot per URL per scan and diffs them across scans. Checkpoints capture the
|
|
192
|
+
same artifacts per page state inside one job. The cross-scan history and comparison UI stay
|
|
193
|
+
downstream; a later consolidation can store Testaro's checkpoint-0 artifacts instead of
|
|
194
|
+
launching a separate capture browser.
|
|
195
|
+
|
|
196
|
+
Until yra-monitor carries `checkpoint` and the checkpoint URL on stored rows, adds a
|
|
197
|
+
checkpoint dimension to its unique-issue key and auto-resolve scoping, and stores one
|
|
198
|
+
screenshot per checkpoint, multi-checkpoint reports must not be fed through its scan
|
|
199
|
+
ingestion path.
|