testaro 78.4.0 → 78.6.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.
@@ -6,8 +6,11 @@
6
6
  # SPDX-License-Identifier: MIT
7
7
 
8
8
  # Publishes the package to npm when a GitHub release is published (the release tag must equal
9
- # v<package.json version>), or on manual dispatch. Authenticates with the NPM_TOKEN repository
10
- # secret, a granular access token with publish permission for the testaro package.
9
+ # v<package.json version>), or on manual dispatch. Authenticates by npm trusted publishing:
10
+ # the job's GitHub OIDC token (permissions.id-token: write) identifies this repository and
11
+ # workflow file to npm, which is configured on npmjs.com (package testaro, trusted publisher
12
+ # GitHub Actions, YRA-Tech/testaro, publish.yml) to accept publishes from it. No npm token is
13
+ # involved; a NODE_AUTH_TOKEN would take precedence over OIDC, so none is set.
11
14
  # prepublishOnly regenerates the rule registry and the emitted TypeScript, and the version
12
15
  # check refuses a release tag that does not match.
13
16
 
@@ -45,5 +48,3 @@ jobs:
45
48
  - run: npm run lint
46
49
  - run: npm run typecheck
47
50
  - run: npm publish --provenance --access public
48
- env:
49
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
package/CLAUDE.md CHANGED
@@ -83,7 +83,7 @@ Key variables:
83
83
  - `JOBDIR` / `REPORTDIR` — root directories for job files and report output
84
84
  - `NETWATCH_URL_JOB`/`NETWATCH_URL_REPORT`/`NETWATCH_AUTH_TYPE`/`NETWATCH_WORKER_ID`/`NETWATCH_WORKER_SECRET` — server polling configuration
85
85
  - `TIMEOUT_MULTIPLIER` — scales all per-tool time limits (default 1)
86
- - `NAV_WAIT_UNTIL`/`NAV_TIMEOUT`/`NAV_FAIL_FAST_4XX`, `SCANNER_ID`, `PRESCAN_SCROLL`, `TESTARO_RULE_RETRIES`, `QUALWEB_STEALTH`/`QUALWEB_ADBLOCK` — deployment defaults that job properties (`navigation`, `scannerId`, `scroll`, `browserChannel`; `retries`, `stealth`, `adBlock` on test acts) override (`procs/config.js`)
86
+ - `NAV_WAIT_UNTIL`/`NAV_TIMEOUT`/`NAV_FAIL_FAST_4XX`, `SCANNER_ID`, `PRESCAN_SCROLL`, `TESTARO_RULE_RETRIES` — deployment defaults that job properties (`navigation`, `scannerId`, `scroll`, `browserChannel`; `retries` on test acts) override (`procs/config.js`). (`QUALWEB_STEALTH`/`QUALWEB_ADBLOCK` and a `qualWeb` act's `stealth`/`adBlock` no longer have any effect: qualWeb runs in the page under test.)
87
87
 
88
88
  ## Code style
89
89
 
package/README.md CHANGED
@@ -8,6 +8,8 @@ Version 75.0.0 introduced a breaking change in the methods for making screenshot
8
8
 
9
9
  Version 68.0.0 introduced a breaking change in the format of reports.
10
10
 
11
+ Changes in each version since 73.0.0 are listed in [Version change notes](#version-change-notes).
12
+
11
13
  ## Purposes
12
14
 
13
15
  Testaro is an application that performs ensemble testing of web pages for accessibility, usability, and conformity to HTML and CSS specifications.
@@ -131,7 +133,7 @@ git pull
131
133
 
132
134
  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.
133
135
 
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.
136
+ 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 which rule engine the `ibm` tool runs (`IBM_ENGINE`: `archive`, the default, for the rule archive IBM deploys, which can lag the npm package; or `package`, for the engine released with the installed `accessibility-checker`, which IBM's published ACT report describes). The defaults keep the behavior of earlier versions.
135
137
 
136
138
  ## Jobs
137
139
 
@@ -702,6 +704,74 @@ On 12 February 2024 ownership of the Testaro repository was transfered from the
702
704
 
703
705
  Maintenance of the repository owned by CVS Health came to an end on 30 September 2025. The current repository was forked from the `cvs-health` repository in October 2025 and then unlinked from the fork network, by agreement with CVS Health.
704
706
 
707
+ ## Version change notes
708
+
709
+ These notes cover versions from 73.0.0 (May 2026) onward. The date of each version is its npm publication date, except that versions marked “unpublished” were committed but not published to npm, and their changes first reached npm in the next published version. Changes in earlier versions are recorded in the commit history.
710
+
711
+ ### 78
712
+
713
+ - **78.6.0** (20 October 2026). An outbound proxy for every browser Testaro launches: `TESTARO_PROXY` (an http, https, or socks5 URL, with any credentials) routes the browsers' traffic through that proxy, so tested sites see its address rather than the host's. WebRTC is confined to the proxy in Chromium and Firefox. A malformed value stops launches instead of connecting directly. Nothing changes when the variable is unset (#173).
714
+ - **78.5.0** (24 September 2026). The `qualWeb` tool runs in the page under test. It used to give QualWeb the serialized page, which QualWeb loaded into a blank page of its own browser, where relative stylesheet links resolved nowhere, so it tested an unstyled page. CSS-dependent rules (contrast `QW-ACT-R37` and `QW-ACT-R76`, zoomed-text clipping `QW-ACT-R40`, the colour techniques) now see the page's real styles, and their counts change accordingly. A QualWeb rule that throws is excluded and recorded in the act's `data.rulePreventions` instead of failing its whole section (for example `QW-ACT-R76` on `lab()`, `oklab()`, `color()` and `color-mix()` colours, qualweb/qualweb#352). A `qualWeb` act's `stealth` and `adBlock` properties, and `QUALWEB_STEALTH` and `QUALWEB_ADBLOCK`, no longer have any effect. The `ibm` tool's rule engine is selectable with `IBM_ENGINE` (`archive`, the default, or `package`). The ACT validation harness (`validation/act/`) records rule-level outcomes and per-page element snapshots.
715
+ - **78.4.0** (2 September 2026). The first npm publication since 78.0.8; it includes the changes of the unpublished versions 78.1.0 through 78.3.0. Deployment options, each a job property when set, else an environment variable, else the earlier behavior: the load state, time limit, and fail-fast-on-4xx policy of navigation (`navigation`; `NAV_WAIT_UNTIL`, `NAV_TIMEOUT`, `NAV_FAIL_FAST_4XX`), a scanner identity request header (`scannerId`; `SCANNER_ID`), a full-page scroll before testing (`scroll`; `PRESCAN_SCROLL`), a branded Chromium channel (`browserChannel`), launch retries per rule of the `testaro` tool (act `retries`; `TESTARO_RULE_RETRIES`), and stealth and ad blocking for the `qualWeb` tool (act `stealth` and `adBlock`; `QUALWEB_STEALTH`, `QUALWEB_ADBLOCK`), which the QualWeb driver had ignored and which are now provided by `playwright-extra` and `@ghostery/adblocker-playwright`. A GitHub Actions workflow publishes the package to npm when a GitHub release is created whose tag matches the package version.
716
+ - **78.3.0** (2 September 2026, unpublished). Checkpoints (see [Checkpoints](#checkpoints) and `docs/checkpoint-scanning.md`): a `checkpoint` act snapshots a page state reached by the acts of a job, and test acts test the latest checkpoint, reaching it by replaying the recorded interaction acts; an `isolation` job property (`process`, `browser`, or `page`) governs how test acts are isolated; when a job has two or more checkpoints, the report gains a `flow` property listing the issues added, persisted, removed, and not retested between consecutive checkpoints, with catalog-structure and ARIA-snapshot diffs; a test act may have `scope: 'changed'` to test only the subtrees changed since the previous checkpoint; interaction acts may identify elements by a Playwright `selector`; catalog entries not cited by any test act are pruned incrementally; `procs/userPath.js` converts recorded user paths into acts. Repairs to the act loop (`next`, failed launches, `url`, `state`).
717
+ - **78.2.0** (1 September 2026, unpublished). Two new rule engines, `pour` (Pour Engine 1.37.0) and `surea11y` (SureA11y core 1.7.0), each vendored as a browser bundle, bringing the count of rule engines from 10 to 12. All rule validators pass again (47 had been quarantined in 78.0.8), legacy expectation paths are resolved from the catalog, and a harness in `validation/act/` scores engines against the W3C ACT test cases. Dependency updates.
718
+ - **78.1.0** (1 September 2026, unpublished). Certainty on standard instances: every instance carries `outcome` (`failed` or `cantTell`), optionally `uncertainty` and `needed`, and the standard result gains `outcomeTotals`; `ordinalSeverity` and `totals` are unchanged, and a later major version will redefine `ordinalSeverity` as impact only (see `docs/standard-result-outcome.md`). TypeScript: the rule modules, tool adapters, core procs, and `types.ts` are TypeScript sources whose emitted `.js` and `.d.ts` files are committed, the package declares `types`, a generated registry (`testaro/registry.ts`) maps rule IDs to rule modules, and the `typecheck`, `build:ts`, `build:registry`, and `lint` scripts are added. The required Node.js version becomes `>=22.12`, and dependencies are pinned to caret ranges instead of `*`. Polling a server (`netWatch`): authentication by a `Basic` authorization header (`NETWATCH_AUTH_TYPE`, `NETWATCH_WORKER_ID`, `NETWATCH_WORKER_SECRET`), job and report URLs no longer assume fixed paths, TLS certificates are verified by default, HTTP statuses are checked, and reports whose delivery fails are saved under `REPORTDIR/netWatchFailed`; the `AGENT` and `NETWATCH_URL_AUTH` variables are deprecated but still honored. Fixes: `ordinalSeverity` is numeric in summary instances of `doTest` rules, `getBasicResult` awaits the catalog index, `styleDiff` chooses the first list link deterministically, `htmlcs` leaves standard totals empty when standard results are off, `ed11y` reports a prevented run instead of crashing, `browserClose` abandons a close that has not settled after 10 seconds, the `elements` rule loads again (a duplicate parameter name had made it a syntax error), and `executionTimeStamp` is validated. Repository URLs point to `YRA-Tech/testaro`, and CI runs the linter, the type check, and the rule validators.
719
+ - **78.0.8** (20 August 2026). Copyright and license notices updated; a nonstandard directory removed.
720
+ - **78.0.7** (unpublished). `getAttributeXPath` tolerates Nu Html Checker messages without an extract, which had thrown and lost the standardization of the whole act.
721
+ - **78.0.6** (20 August 2026). `nuVal` and `nuVnu`: the extract of a message that identifies no element is preserved in the `what` property of the instance.
722
+ - **78.0.5** (20 August 2026). `htmlcs`: the `define`, `exports`, and `module` globals are hidden while `HTMLCS.js` is injected, so pages that expose an AMD loader no longer prevent the tool.
723
+ - **78.0.4** (19 August 2026). `focAll` reports the specific elements not reached by tabbing and those reached unexpectedly, itemized when `withItems` is true.
724
+ - **78.0.3** (unpublished). The `accessibility-checker` dependency is required to be at least 4.0.29.
725
+ - **78.0.2** (19 August 2026). `browserClose` actually closes the browser context and browser; previously every browser outlived its act.
726
+ - **78.0.1** (19 August 2026). The time budget of the `motion` rule rises from 5 to 30 seconds.
727
+ - **78.0.0** (19 August 2026). New optional `imageScale` job property: when it is greater than 1, the catalog page is rendered at that device scale factor and a second page image, at device-pixel scale, becomes the second item of `images`; the first item stays at CSS-pixel scale. The major version was incremented because of the added job property.
728
+
729
+ ### 77
730
+
731
+ - **77.2.1** (19 August 2026). The catalog records no `boxID` for elements that are laid out but not painted (`visibility: hidden` and `content-visibility: hidden` subtrees).
732
+ - **77.2.0** (19 August 2026). During a job the map from path IDs to catalog indexes lives at `report.pathIDs` instead of `catalog.pathID`, so the catalog contains only element entries; the shipped report is unchanged.
733
+ - **77.1.0** (19 August 2026). Closed `details` elements are expanded before the page image and the box measurements are made, so the two agree.
734
+ - **77.0.4** (18 August 2026). Validation: expectations of test acts are resolved against `act.result`, so `standardResult` expectation paths work.
735
+ - **77.0.3** (18 August 2026). `normalizeURL` resolves relative path segments, so strict jobs with `file:` targets no longer report spurious bad redirections.
736
+ - **77.0.2** (18 August 2026). `deSlash` is defined, so strict jobs no longer abort on their first navigation.
737
+ - **77.0.1** (18 August 2026). `autocomplete`: its label arrays are spliced correctly, so the name, given-name, family-name, and email heuristics fire. The order in which navigation load-wait conditions are relaxed is improved. Dependency updates.
738
+ - **77.0.0** (28 July 2026). Observability: `doJob` accepts a second argument with an `onProgress` callback and emits `jobStart`, `catalogStart`, `catalogEnd`, `actStart`, `actEnd`, and `jobEnd` events (see [Execution with observability](#execution-with-observability)).
739
+
740
+ ### 76
741
+
742
+ - **76.2.2** (28 July 2026). Container versioning requirements documented; dependency updates.
743
+ - **76.2.1** (28 July 2026). The catalog no longer fails on pages whose scripts extend `Array.prototype`.
744
+ - **76.2.0** (27 July 2026). When a target repeatedly rejects a job, the job's `browserID` is changed.
745
+ - **76.1.2** (27 July 2026). The launch context honors a user agent supplied by the job for device emulation instead of overriding it.
746
+ - **76.1.1** (26 July 2026). Corrections related to containerization.
747
+ - **76.1.0** (25 July 2026). The `qualWeb` tool uses the QualWeb Playwright driver instead of Puppeteer. Documentation and dependency updates.
748
+ - **76.0.0** (18 July 2026). Containerized deployment: the `TESTARO_CHROMIUM_NO_SANDBOX` environment variable and a reference container image (`Dockerfile`, `docker-compose.yml`, `CONTAINERS.md`). Archived jobs and reports are named by ID in `run` and `dirWatch`, and a `dirWatch` file-deletion bug is corrected. The `validation/watch` directory is removed.
749
+
750
+ ### 75
751
+
752
+ - **75.2.2** (18 July 2026). The `call` commands tolerate absent `netWatch` environment variables instead of failing.
753
+ - **75.2.1** (20 June 2026). A failure to launch a browser for the catalog is fatal to the job.
754
+ - **75.2.0** (20 June 2026). When a browser crashes on launch, the launch is retried with a different browser type, and browser-type changes are logged.
755
+ - **75.1.0** (6 June 2026). New optional `imageColor` job property: when a catalog is created, a page image with that color type is made the first item of an `images` array in the report. The `motion` rule makes its own screenshot and compares it with that image, using `pixelmatch` instead of BlazeDiff.
756
+ - **75.0.0** (5 June 2026). Breaking: the `shoot` act creates a full-page screenshot as a base64-encoded PNG and, with its `exclusionSelector`, `colorType`, and `action` properties, decides what to mask, which color type to use, and whether to return the image in the act result, add it to the `images` array of the report, or save it as a file; the screenshot option of the `launch` act is removed.
757
+
758
+ ### 74
759
+
760
+ - **74.2.3** (3 June 2026). `axe`: the full `data-xpath` of each flagged element is resolved from the live DOM, because axe truncates the HTML it reports. Dependency updates.
761
+ - **74.2.2** (29 May 2026). Additions to `UPGRADES.md`.
762
+ - **74.2.1** (26 May 2026). WebKit and Firefox are imported from `playwright-extra` again; 74.2.0 had imported only Chromium.
763
+ - **74.2.0** (25 May 2026). The stealth plugin is applied only to Chromium; WebKit and Firefox had rejected a Chromium-only launch option and failed every job.
764
+ - **74.1.3** (25 May 2026). The `TESTARO_NU_URL` environment variable overrides the URL of the Nu Html Checker, for a self-hosted checker without the body-size limit of the public one.
765
+ - **74.1.2** (25 May 2026). `nuVal` survives empty responses from the W3C validator instead of losing the underlying error.
766
+ - **74.1.1** (25 May 2026). The exclude-list form of the `testaro` rule specification (`['n', …]`) actually excludes the listed rules.
767
+ - **74.1.0** (25 May 2026). Job-level `stealth` toggle.
768
+ - **74.0.1** (25 May 2026). Copyright notices updated.
769
+ - **74.0.0** (25 May 2026). New `shoot` act type, making full-page screenshots.
770
+
771
+ ### 73
772
+
773
+ - **73.0.0** (25 May 2026). Temporary files are kept in a per-job directory under `tmp` at the project root, falling back to the operating system's temporary directory; the `TMPDIRNAME` environment variable and `procs/config.js` are removed.
774
+
705
775
  ## Contributing
706
776
 
707
777
  From 12 February 2024 through 30 September 2025, contributors of code to Testaro executed a [CVS Health OSS Project Contributor License Agreement](https://forms.office.com/pages/responsepage.aspx?id=uGG7-v46dU65NKR_eCuM1xbiih2MIwxBuRvO0D_wqVFUQ1k0OE5SVVJWWkY4MTVJMkY3Sk9GM1FHRC4u) for Testaro before any pull request was approved and merged.
package/actSpecs-doc.md CHANGED
@@ -57,7 +57,7 @@ The validity criterion named in item 2 may be any of these:
57
57
 
58
58
  ## qualWeb tool
59
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).
60
+ QualWeb runs in the page under test (as the page is after launch and any earlier acts), with that page's styles and scripts, not in a browser of its own. A rule that throws is excluded and its section rerun; the act's `data.rulePreventions` records such rules (and any section that failed as a whole). The `stealth` and `adBlock` properties a `qualWeb` test act may still have are accepted and ignored: they configured the separate browser QualWeb used to launch.
61
61
 
62
62
  ## testaro tool
63
63
 
package/actSpecs.js CHANGED
@@ -215,8 +215,8 @@ exports.actSpecs = {
215
215
  qualWeb: [
216
216
  'Perform QualWeb tests',
217
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)']
218
+ stealth: [false, 'boolean', '', 'ignored: qualWeb runs in the page under test, not in a browser of its own'],
219
+ adBlock: [false, 'boolean', '', 'ignored: qualWeb runs in the page under test, not in a browser of its own']
220
220
  }
221
221
  ],
222
222
  testaro: [
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  var computeAccessibleName = (() => {
2
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
3
4
  var __commonJS = (cb, mod) => function __require() {
package/env.example CHANGED
@@ -44,10 +44,10 @@ PRESCAN_SCROLL=false
44
44
  # Launch retries per rule of the testaro tool, which relaunches per contaminating rule
45
45
  # (default 2; raise for non-Chromium browsers, which navigate flakily on relaunch).
46
46
  TESTARO_RULE_RETRIES=2
47
- # Whether the qualWeb tool's browser runs stealth evasions and blocks ads and trackers
48
- # (default true; a qualWeb test act may set stealth and adBlock).
49
- QUALWEB_STEALTH=true
50
- QUALWEB_ADBLOCK=true
47
+ # No longer used: the qualWeb tool now runs in the page under test instead of its own
48
+ # browser, so it has no stealth or ad-blocking settings of its own.
49
+ # QUALWEB_STEALTH=true
50
+ # QUALWEB_ADBLOCK=true
51
51
  # URL of any non-default (e.g., self-hosted) Nu Html Checker API (see ghcr.io/validator/validator).
52
52
  TESTARO_NU_URL=__placeholder__
53
53
  # Whether to launch the Playwright chromium browser without its sandbox (normally false).
@@ -55,6 +55,11 @@ TESTARO_NU_URL=__placeholder__
55
55
  # seccomp policies and some hardened hosts prohibit. Set this to true in containers,
56
56
  # or run containers with a seccomp profile that permits user-namespace cloning.
57
57
  TESTARO_CHROMIUM_NO_SANDBOX=false
58
+ # URL (http, https, or socks5, with any credentials) of an outbound proxy for every browser
59
+ # Testaro launches, including the qualWeb tool's, so tested sites see the proxy's address
60
+ # rather than the host's (default none: browsers connect directly). A malformed value stops
61
+ # launches instead of connecting directly.
62
+ TESTARO_PROXY=
58
63
 
59
64
  # netWatch variables
60
65
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testaro",
3
- "version": "78.4.0",
3
+ "version": "78.6.0",
4
4
  "description": "Run 1300 web accessibility tests from 12 tools and get a standardized report",
5
5
  "main": "run.js",
6
6
  "scripts": {
package/procs/config.d.ts CHANGED
@@ -33,3 +33,9 @@ export function getScroll(report: unknown): boolean;
33
33
  export const ruleLaunchRetries: number;
34
34
  // Defaults for the qualWeb tool's browser.
35
35
  export const qualWebDefaults: {stealth: boolean; adBlock: boolean};
36
+ // Launch options routing a browser through the outbound proxy (TESTARO_PROXY), or {} if none.
37
+ export function getProxyLaunchOptions(browserID: string): {
38
+ proxy?: {server: string; username?: string; password?: string};
39
+ args?: string[];
40
+ firefoxUserPrefs?: Record<string, boolean>;
41
+ };
package/procs/config.js CHANGED
@@ -79,3 +79,39 @@ exports.qualWebDefaults = {
79
79
  stealth: envFlag('QUALWEB_STEALTH', true),
80
80
  adBlock: envFlag('QUALWEB_ADBLOCK', true)
81
81
  };
82
+ // Returns the launch options that route a browser of the specified type through the outbound
83
+ // proxy (TESTARO_PROXY: an http, https, or socks5 URL, with any credentials), so that tested
84
+ // sites see the proxy's address rather than the host's; or {} if none is configured. Applies
85
+ // to every browser Testaro launches, including the qualWeb tool's. A malformed value throws
86
+ // instead of falling back to a direct connection that would expose the host's address. The
87
+ // browser's WebRTC traffic is confined to the proxy where the browser permits (Chromium and
88
+ // Firefox; WebKit has no such launch option), since WebRTC UDP bypasses an HTTP proxy.
89
+ exports.getProxyLaunchOptions = browserID => {
90
+ const value = (process.env.TESTARO_PROXY || '').trim();
91
+ if (! value) {
92
+ return {};
93
+ }
94
+ let url;
95
+ try {
96
+ url = new URL(value);
97
+ }
98
+ // The value is not quoted in errors, because it may contain credentials.
99
+ catch {
100
+ throw new Error('TESTARO_PROXY is not a URL');
101
+ }
102
+ if (! ['http:', 'https:', 'socks5:'].includes(url.protocol) || ! url.hostname) {
103
+ throw new Error('TESTARO_PROXY is not an http, https, or socks5 URL with a host');
104
+ }
105
+ const proxy = {server: `${url.protocol}//${url.host}`};
106
+ if (url.username) {
107
+ proxy.username = decodeURIComponent(url.username);
108
+ proxy.password = decodeURIComponent(url.password);
109
+ }
110
+ if (browserID === 'chromium') {
111
+ return {proxy, args: ['--force-webrtc-ip-handling-policy=disable_non_proxied_udp']};
112
+ }
113
+ if (browserID === 'firefox') {
114
+ return {proxy, firefoxUserPrefs: {'media.peerconnection.ice.proxy_only': true}};
115
+ }
116
+ return {proxy};
117
+ };
package/procs/launch.js CHANGED
@@ -34,8 +34,8 @@ const playwrightExtra = require('playwright-extra');
34
34
  const {isBrowserID, isDeviceID, isURL, isValidJob} = require('./job');
35
35
  // The in-page script defining window.getXPath.
36
36
  const {getXPathSource} = require('./xPathScript');
37
- // Deployment options (navigation, scanner identity, pre-scan scroll).
38
- const {getNavigation, getScannerId, getScroll, waitStates} = require('./config');
37
+ // Deployment options (navigation, scanner identity, pre-scan scroll, outbound proxy).
38
+ const {getNavigation, getProxyLaunchOptions, getScannerId, getScroll, waitStates} = require('./config');
39
39
 
40
40
  // CONSTANTS
41
41
 
@@ -465,6 +465,10 @@ const launchOnce = async opts => {
465
465
  // Disable the sandbox.
466
466
  browserOptions.chromiumSandbox = false;
467
467
  }
468
+ // Route the browser through the outbound proxy, if one is configured.
469
+ const {args: proxyArgs = [], ...proxyOptions} = getProxyLaunchOptions(browserID);
470
+ browserOptionArgs.push(...proxyArgs);
471
+ Object.assign(browserOptions, proxyOptions);
468
472
  // If the job specifies a branded Chromium channel (chrome or msedge), run that installed
469
473
  // browser instead of the bundled Chromium build; bundled or absent keeps the default.
470
474
  const {browserChannel} = report;
package/tests/ibm.d.ts CHANGED
@@ -34,6 +34,11 @@ type IbmTrimmedReport = {
34
34
  items: IbmItem[];
35
35
  error: string;
36
36
  };
37
+ export type IbmEngineMode = 'archive' | 'package';
38
+ export declare const ibmEngine: () => Promise<{
39
+ mode: IbmEngineMode;
40
+ version: string | null;
41
+ }>;
37
42
  export declare const reporter: (page: Page, report: Report, actIndex: number) => Promise<{
38
43
  data: {};
39
44
  result: {
package/tests/ibm.js CHANGED
@@ -10,26 +10,35 @@
10
10
  SPDX-License-Identifier: MIT
11
11
  */
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.reporter = void 0;
13
+ exports.reporter = exports.ibmEngine = void 0;
14
14
  const xPath_1 = require("../procs/xPath");
15
15
  const standard_1 = require("../procs/standard");
16
16
  const accessibilityChecker = require('accessibility-checker');
17
- const { getCompliance } = accessibilityChecker;
18
- /*
19
- ibm
20
- Implements the IBM Equal Access ruleset for accessibility.
21
-
22
- This rule engine depends on aceconfig.js.
23
-
24
- This rule engine is compatible with Windows only if the accessibility-checker package
25
- is revised. See README.md for details.
26
- Compiled to ibm.js by tsc (issue #73); edit this file, not the emitted one.
27
- */
28
- // FUNCTIONS
17
+ const { getCompliance, getConfig } = accessibilityChecker;
18
+ let engineSelection = null;
19
+ const ibmEngine = () => {
20
+ engineSelection ??= (async () => {
21
+ const requested = (process.env.IBM_ENGINE || 'archive').trim().toLowerCase();
22
+ if (!['archive', 'package'].includes(requested)) {
23
+ console.log(`WARNING: IBM_ENGINE=${process.env.IBM_ENGINE} is not archive or package; using archive`);
24
+ }
25
+ const mode = requested === 'package' ? 'package' : 'archive';
26
+ const config = await getConfig();
27
+ if (mode === 'package' && config.toolVersion) {
28
+ config.rulePack = `https://cdn.jsdelivr.net/npm/accessibility-checker-engine@${config.toolVersion}`;
29
+ config.ruleArchiveVersion = config.toolVersion;
30
+ config.ruleArchiveLabel = `accessibility-checker-engine ${config.toolVersion} (package)`;
31
+ }
32
+ return { mode, version: config.ruleArchiveVersion ?? null };
33
+ })();
34
+ return engineSelection;
35
+ };
36
+ exports.ibmEngine = ibmEngine;
29
37
  // Runs the IBM test and returns the result.
30
38
  const run = async (content) => {
31
39
  const nowLabel = (new Date()).toISOString().slice(0, 19);
32
40
  try {
41
+ await (0, exports.ibmEngine)();
33
42
  const ibmReport = await getCompliance(content, nowLabel);
34
43
  if (typeof ibmReport === 'object' && ibmReport.report) {
35
44
  return ibmReport;
package/tests/ibm.ts CHANGED
@@ -16,7 +16,7 @@ import {getAttributeXPath, getXPathCatalogIndex} from '../procs/xPath';
16
16
  import {getStandardResult, pushInstance} from '../procs/standard';
17
17
  import type {Act, Report, StandardInstance, StandardResult} from '../types';
18
18
  const accessibilityChecker = require('accessibility-checker') as typeof import('accessibility-checker');
19
- const {getCompliance} = accessibilityChecker;
19
+ const {getCompliance, getConfig} = accessibilityChecker;
20
20
 
21
21
  // TYPES
22
22
 
@@ -69,10 +69,46 @@ type IbmTrimmedReport =
69
69
 
70
70
  // FUNCTIONS
71
71
 
72
+ /*
73
+ Which IBM rule engine runs, per the IBM_ENGINE environment variable:
74
+ archive (default): the rule archive IBM deploys ("latest"), which is what
75
+ users of IBM's own tools get. It can lag the npm package (engine 4.0.27
76
+ under accessibility-checker 4.0.33 in September 2026).
77
+ package: the engine released with the installed accessibility-checker,
78
+ the one IBM's published ACT report describes. It is fetched from the
79
+ same CDN as the archive's.
80
+ accessibility-checker reads aceconfig.js from the working directory and then
81
+ ignores a configuration passed to it, so the package engine is selected by
82
+ adjusting its processed configuration before the first test. Setting
83
+ ruleArchiveVersion also keeps the two engines' cached files apart and makes
84
+ getConfig report the engine actually used.
85
+ */
86
+ export type IbmEngineMode = 'archive' | 'package';
87
+ let engineSelection: Promise<{mode: IbmEngineMode; version: string | null}> | null = null;
88
+ export const ibmEngine = () => {
89
+ engineSelection ??= (async () => {
90
+ const requested = (process.env.IBM_ENGINE || 'archive').trim().toLowerCase();
91
+ if (! ['archive', 'package'].includes(requested)) {
92
+ console.log(`WARNING: IBM_ENGINE=${process.env.IBM_ENGINE} is not archive or package; using archive`);
93
+ }
94
+ const mode: IbmEngineMode = requested === 'package' ? 'package' : 'archive';
95
+ const config = await getConfig() as unknown as {
96
+ toolVersion?: string; rulePack?: string; ruleArchiveVersion?: string; ruleArchiveLabel?: string;
97
+ };
98
+ if (mode === 'package' && config.toolVersion) {
99
+ config.rulePack = `https://cdn.jsdelivr.net/npm/accessibility-checker-engine@${config.toolVersion}`;
100
+ config.ruleArchiveVersion = config.toolVersion;
101
+ config.ruleArchiveLabel = `accessibility-checker-engine ${config.toolVersion} (package)`;
102
+ }
103
+ return {mode, version: config.ruleArchiveVersion ?? null};
104
+ })();
105
+ return engineSelection;
106
+ };
72
107
  // Runs the IBM test and returns the result.
73
108
  const run = async (content: Page) => {
74
109
  const nowLabel = (new Date()).toISOString().slice(0, 19);
75
110
  try {
111
+ await ibmEngine();
76
112
  const ibmReport = await getCompliance(content, nowLabel);
77
113
  if (typeof ibmReport === 'object' && ibmReport.report) {
78
114
  return ibmReport as unknown as {report: IbmActReport};
@@ -20,9 +20,8 @@ interface QwModuleReport {
20
20
  }
21
21
  interface QwNativeResult {
22
22
  system?: {
23
- page?: {
24
- dom?: unknown;
25
- };
23
+ url?: string;
24
+ evaluation?: string;
26
25
  };
27
26
  modules?: Record<string, QwModuleReport>;
28
27
  }
@@ -30,6 +29,7 @@ export declare const reporter: (page: Page, report: Report, actIndex: number, ti
30
29
  data: {
31
30
  prevented?: boolean;
32
31
  error?: string;
32
+ rulePreventions?: Record<string, string>;
33
33
  };
34
34
  result: {
35
35
  nativeResult: QwNativeResult;