testaro 58.0.0 → 58.0.2
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/README.md +1 -360
- package/UPGRADES.md +1515 -0
- package/package.json +1 -1
package/UPGRADES.md
ADDED
|
@@ -0,0 +1,1515 @@
|
|
|
1
|
+
# Major decisions for JavaScript to TypeScript conversion
|
|
2
|
+
_Exported on 9/23/2025 at 15:13:23 PDT from Cursor (1.6.45)_
|
|
3
|
+
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
**User**
|
|
7
|
+
|
|
8
|
+
What are the major decisions that will be required if this entire repository is converted from JavaScript to TypeScript?
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
**Cursor**
|
|
13
|
+
|
|
14
|
+
I'll scan key files to understand the current setup (module system, scripts, dependencies) so I can tailor the TypeScript migration decisions to this repo’s specifics.
|
|
15
|
+
|
|
16
|
+
I'll quickly scan for module patterns and JSON imports across the repo to tailor the TypeScript migration decisions (CJS vs ESM, JSON handling, dynamic requires).
|
|
17
|
+
|
|
18
|
+
### Major decisions for a full TypeScript migration
|
|
19
|
+
|
|
20
|
+
- **Module system and runtime**
|
|
21
|
+
- CommonJS vs ESM output (`module` = commonjs vs nodenext) and `package.json` `"type"` choice.
|
|
22
|
+
- Whether to keep `require/exports` at runtime or rewrite to `import/export` in source.
|
|
23
|
+
- `esModuleInterop`/`allowSyntheticDefaultImports` settings for interop.
|
|
24
|
+
|
|
25
|
+
- **Build vs runtime execution**
|
|
26
|
+
- Transpile-then-run (`tsc` to `dist/`) vs on-the-fly (`ts-node`/register) for all CLI executors in `validation/executors/` and top-level scripts.
|
|
27
|
+
- If building, how to resolve runtime paths to forked workers (e.g., `procs/doTestAct`): compute `dist` paths, or use a loader.
|
|
28
|
+
|
|
29
|
+
- **Pathing for child processes**
|
|
30
|
+
- How `child_process.fork` targets compiled files (adjust `__dirname` usage, emit to predictable `outDir`, or use ts-node in children).
|
|
31
|
+
- Consistent strategy for file URL handling (current `file://` normalization logic) post-build.
|
|
32
|
+
|
|
33
|
+
- **Type strictness and tsconfig**
|
|
34
|
+
- Level of strictness (`strict`, `noImplicitAny`, `strictNullChecks`, `exactOptionalPropertyTypes`, `noUncheckedIndexedAccess`).
|
|
35
|
+
- Target and libs (`target` ES2020/ES2022; `lib` includes `ES2020`, `DOM` if needed for `page.evaluate` contexts).
|
|
36
|
+
- `moduleResolution` (`node`, `nodenext`, or `bundler`) and `resolveJsonModule` (only if you convert JSON imports from fs-read to imports).
|
|
37
|
+
|
|
38
|
+
- **Data model design**
|
|
39
|
+
- Formal interfaces for `Job`, `Report`, `Act` (discriminated unions for `type` = `launch|test|url|wait|state|page|...`), and nested structures like `standardResult`, `jobData`, `toolTimes`.
|
|
40
|
+
- How much to type dynamic/mutable shapes (e.g., `report.jobData.*`, adding properties lazily) vs using `any`/`Partial`.
|
|
41
|
+
- Strategy for optional properties and progressive enrichment during execution.
|
|
42
|
+
|
|
43
|
+
- **3rd‑party types and augmentations**
|
|
44
|
+
- Verify/choose type packages for `playwright`, `@siteimprove/alfa-*`, `axe-playwright`, `@qualweb/*`, `accessibility-checker`, `playwright-dompath`, `pixelmatch`. Plan fallbacks if defs are missing.
|
|
45
|
+
- Decide on module augmentation vs casting for custom fields (e.g., `page.browserID` assignment requires augmenting `playwright.Page` or casting).
|
|
46
|
+
|
|
47
|
+
- **Dynamic loading patterns**
|
|
48
|
+
- `tests/testaro.js` dynamically requires rule modules by filename; decide to:
|
|
49
|
+
- keep dynamic `require` (typed as `unknown`/`any`), or
|
|
50
|
+
- replace with a typed registry/factory, or
|
|
51
|
+
- use dynamic `import()` with explicit result typing.
|
|
52
|
+
- Same decision for runtime JSON rule loading vs typed imports.
|
|
53
|
+
|
|
54
|
+
- **JSON rule and data typing**
|
|
55
|
+
- Define interfaces for JSON rule files in `testaro/*.json` and job property JSON under `validation/tests/jobProperties/`.
|
|
56
|
+
- Whether to keep fs-based JSON reads (runtime-validated) or switch to typed imports using `resolveJsonModule`.
|
|
57
|
+
|
|
58
|
+
- **Node/DOM boundary typing**
|
|
59
|
+
- How to type `page.evaluate` payloads and element handles; utility helpers like `textOf`, `getLocatorData`, `boxOf` should have precise generics vs `any`.
|
|
60
|
+
- Decide whether to include `DOM` lib globally or rely on Playwright types and narrow evaluate functions.
|
|
61
|
+
|
|
62
|
+
- **Error and result typing**
|
|
63
|
+
- Standardize error codes/messages (e.g., `'status429'`, `'badRedirection'`, numeric codes from children) into a typed union.
|
|
64
|
+
- Time-limit handling and messaging types for per-rule timeouts.
|
|
65
|
+
|
|
66
|
+
- **Project layout and outputs**
|
|
67
|
+
- Where compiled files live (`dist/` mirroring current tree) and which directories are included/excluded (`node_modules`, `temp/`, `validation/jobs/**`, `validation/tests/targets/**`).
|
|
68
|
+
- Whether to keep `.js` under `testaro/` alongside `.json` or convert all rule JS to `.ts`.
|
|
69
|
+
|
|
70
|
+
- **Tooling**
|
|
71
|
+
- ESLint to TS config (`@typescript-eslint/*`, parser, rules), what to enforce/relax during migration.
|
|
72
|
+
- Incremental checking plan (`allowJs`, `checkJs`, JSDoc types) vs big‑bang conversion.
|
|
73
|
+
- `skipLibCheck` policy for faster builds vs stricter dependency checks.
|
|
74
|
+
|
|
75
|
+
- **Runtime compatibility and CI**
|
|
76
|
+
- Minimum Node version (current code uses `fs/promises`; align `target`/features accordingly).
|
|
77
|
+
- Update `npm` scripts to run compiled executors or ts-node variants; adjust `main`/exports fields.
|
|
78
|
+
- Update CI to compile, run validation suites, and publish artifacts if applicable.
|
|
79
|
+
|
|
80
|
+
- **Performance and DX choices**
|
|
81
|
+
- Use of `tslib`/`importHelpers` to reduce output size.
|
|
82
|
+
- Source maps for debugging vs build speed.
|
|
83
|
+
- Build caching and watch mode for local dev across many small files.
|
|
84
|
+
|
|
85
|
+
- **Public API typing**
|
|
86
|
+
- Surface types for externally used entry points like `run.js` (`doJob`, `launch`) if this is used as a library; decide on `.d.ts` emission and what is considered public.
|
|
87
|
+
|
|
88
|
+
- **Gradual safety boundaries**
|
|
89
|
+
- Where to place `unknown`/`any` escapes (e.g., dynamic module results, process messages) and how to fence them with runtime guards to preserve correctness.
|
|
90
|
+
|
|
91
|
+
- **Behavioral parity vs refactor**
|
|
92
|
+
- Whether to refactor opportunistically (e.g., replace dynamic exports, normalize act handling with discriminated unions) or preserve exact runtime semantics first and harden types later.
|
|
93
|
+
|
|
94
|
+
- **Monorepo/external types scenario (if needed)**
|
|
95
|
+
- If `ibmOutput/` or other data folders need typings or should be excluded entirely from compilation.
|
|
96
|
+
|
|
97
|
+
- **Licensing and headers**
|
|
98
|
+
- How to preserve license headers/comments during transpilation if that’s a requirement.
|
|
99
|
+
|
|
100
|
+
- **Migration sequencing**
|
|
101
|
+
- Directory order (e.g., core `procs/` first, then `tests/`, then executors) and gate criteria to keep `validation` flows working throughout.
|
|
102
|
+
|
|
103
|
+
- **Testing strategy**
|
|
104
|
+
- Decide on type-level tests and runtime regression checks for the many rules in `testaro/` to ensure no behavior drift.
|
|
105
|
+
|
|
106
|
+
- **Non-standard patterns**
|
|
107
|
+
- Confirm approach for in-place mutation of Playwright elements (focus/check/click workflows) and timing helpers to remain compatible under TS’s stricter async typing.
|
|
108
|
+
|
|
109
|
+
- **Distribution and consumers**
|
|
110
|
+
- If published, decide on dual CJS/ESM output and `exports` map for consumers; if internal CLI only, keep CJS for simplicity.
|
|
111
|
+
|
|
112
|
+
- **Env/config handling**
|
|
113
|
+
- Typing for env vars (e.g., `DEBUG`, `WAITS`) and a strategy to centralize env parsing, optionally with a schema.
|
|
114
|
+
|
|
115
|
+
- **File I/O and paths**
|
|
116
|
+
- Formalize types for file contents read/written (reports, JSON job files) and ensure atomicity/encoding assumptions are explicit.
|
|
117
|
+
|
|
118
|
+
- **Automated code mods**
|
|
119
|
+
- Choose codemods for `require`→`import`, `exports.`→`export`, and add TSDoc/JSDoc scaffolding where helpful.
|
|
120
|
+
|
|
121
|
+
- **Fallback for missing types**
|
|
122
|
+
- Policy for creating minimal `*.d.ts` shims vs pinning dependency versions that ship their own types.
|
|
123
|
+
|
|
124
|
+
- **Security and sandboxing**
|
|
125
|
+
- Revisit `page.evaluate` usage to ensure types don’t mask unsafe patterns; possibly introduce typed helpers for CSP/nonce handling.
|
|
126
|
+
|
|
127
|
+
- **Ownership and conventions**
|
|
128
|
+
- Naming, folder structure for types, and conventions (e.g., suffix `*Rule.ts` for testaro rules, `*Executor.ts` for executors).
|
|
129
|
+
|
|
130
|
+
- **Performance budgets**
|
|
131
|
+
- Ensure TS doesn’t slow hot paths; decide on `transpileOnly` for dev and full type-check in CI.
|
|
132
|
+
|
|
133
|
+
- **Docs**
|
|
134
|
+
- Whether to publish type-first docs for rules, job schema, and report schema.
|
|
135
|
+
|
|
136
|
+
- **Binary compatibility and scripts**
|
|
137
|
+
- Shebang/CLI wrappers if any are added; adjust NPM scripts (`run`, `tests`, `dirWatch`, `netWatch`) to compiled targets.
|
|
138
|
+
|
|
139
|
+
- **Source of truth for rule registry**
|
|
140
|
+
- Move from filesystem discovery/dynamic require to a typed registry or keep FS-based discovery and accept weaker typing there.
|
|
141
|
+
|
|
142
|
+
- **Augmentation of global state**
|
|
143
|
+
- Approach for module-global mutable state (`browser`, `page`, `actIndex`, `actCount`) under TS (keep, or encapsulate for easier typing).
|
|
144
|
+
|
|
145
|
+
- **Error codes and enums**
|
|
146
|
+
- Decide on enums/constants for error strings currently used ad hoc across modules.
|
|
147
|
+
|
|
148
|
+
- **Back-compatibility**
|
|
149
|
+
- If external users rely on current JS entry points, decide on keeping JS shim files or major-version bump.
|
|
150
|
+
|
|
151
|
+
- **CI artifacts**
|
|
152
|
+
- Whether to commit `dist/` for executors used by external systems (if any) or build on demand.
|
|
153
|
+
|
|
154
|
+
- **Validation data**
|
|
155
|
+
- Type-checking and exclude patterns for large static trees under `validation/tests/targets/**`.
|
|
156
|
+
|
|
157
|
+
- **Standardization pipeline**
|
|
158
|
+
- Strongly typing `standardize`, `identify`, `getLocatorData` interfaces to ensure the report format remains stable.
|
|
159
|
+
|
|
160
|
+
- **Global configuration**
|
|
161
|
+
- Where to centralize tsconfig(s): single root vs per-folder `tsconfig.json` if executors or tests need different settings.
|
|
162
|
+
|
|
163
|
+
- **Dev ergonomics**
|
|
164
|
+
- Editor/watch settings for auto-build and source maps to keep the current debugging/logging experience.
|
|
165
|
+
|
|
166
|
+
- **Release management**
|
|
167
|
+
- Versioning strategy aligning the migration with a major release and a deprecation window for JS users.
|
|
168
|
+
|
|
169
|
+
- **Repository hygiene**
|
|
170
|
+
- Git ignore updates for `dist/`, source maps, and generated typings; precommit checks for type errors.
|
|
171
|
+
|
|
172
|
+
- **Incremental guardrails**
|
|
173
|
+
- Introduce `// TODO(ts):` backlog tags and thresholds (e.g., don’t merge if new `any`s added) to keep type quality from regressing.
|
|
174
|
+
|
|
175
|
+
- **Performance of rule timeouts**
|
|
176
|
+
- Keep or parameterize the 15s per-rule timeout with typed config; ensure typings don’t accidentally widen timing types.
|
|
177
|
+
|
|
178
|
+
- **Playwright context**
|
|
179
|
+
- Decide if `Page`/`BrowserContext` are passed through typed helpers rather than shared module state to improve type soundness.
|
|
180
|
+
|
|
181
|
+
- **Logging**
|
|
182
|
+
- Strongly type logging interfaces and message formats (currently strings) if you want structured logs.
|
|
183
|
+
|
|
184
|
+
- **Observability hooks**
|
|
185
|
+
- Type `tellServer` interface so message parameters are validated at compile time.
|
|
186
|
+
|
|
187
|
+
- **Temporary directories and file lifecycle**
|
|
188
|
+
- Ensure typed guarantees for report temp file creation/deletion around `doActs`.
|
|
189
|
+
|
|
190
|
+
- **Edge-case Node APIs**
|
|
191
|
+
- Keep `process.on('message')` and `fork` message contract typed (e.g., discriminated unions for IPC).
|
|
192
|
+
|
|
193
|
+
- **Risk posture**
|
|
194
|
+
- Choose between maximal type safety (more refactor) vs minimal-change transpilation (faster migration, looser types).
|
|
195
|
+
|
|
196
|
+
- **Team workflow**
|
|
197
|
+
- Coding standards for type annotations, error handling, and rule authoring templates (`data/template.js` → `.ts`).
|
|
198
|
+
|
|
199
|
+
- **Documentation updates**
|
|
200
|
+
- Update `README.md` and contributor docs for TS build, scripts, and rule authoring in TS.
|
|
201
|
+
|
|
202
|
+
- **License headers**
|
|
203
|
+
- Confirm TypeScript compiler preserves headers in output where needed.
|
|
204
|
+
|
|
205
|
+
- **Binary assets**
|
|
206
|
+
- Decide on handling and typing for `ed11y/editoria11y.min.js`, `htmlcs/HTMLCS.js`, and `temp/engine/*.js` (likely exclude from TS).
|
|
207
|
+
|
|
208
|
+
- **Validation executors**
|
|
209
|
+
- Whether to type and migrate `validation/**` (watchers, runners) now or later; they are part of the runtime entrypoints.
|
|
210
|
+
|
|
211
|
+
- **Scripted searches**
|
|
212
|
+
- If any script relies on `.js` globbing, update to include `.ts` or compiled `.js` as appropriate.
|
|
213
|
+
|
|
214
|
+
- **Monorepo split (optional)**
|
|
215
|
+
- Consider separating library (`procs/`, `testaro/`) from CLI/executors to simplify build and type boundaries.
|
|
216
|
+
|
|
217
|
+
- **Release notes and migration guide**
|
|
218
|
+
- Communicate breaking changes (paths, module format, APIs) to downstream users.
|
|
219
|
+
|
|
220
|
+
- **Contingency**
|
|
221
|
+
- Rollback plan if TS introduces runtime regressions; maintain a JS branch during transition.
|
|
222
|
+
|
|
223
|
+
- **Ownership of generated types**
|
|
224
|
+
- Whether to emit `.d.ts` for public consumption and how to keep them in sync.
|
|
225
|
+
|
|
226
|
+
- **Security posture**
|
|
227
|
+
- Type-narrow inputs to `page.evaluate` to reduce injection risks; consider runtime schema validation aligned with compile-time types.
|
|
228
|
+
|
|
229
|
+
- **Consistency and naming**
|
|
230
|
+
- Normalize names (e.g., rule IDs, act types) in enums to prevent typo bugs now caught by types.
|
|
231
|
+
|
|
232
|
+
- **Testing gates**
|
|
233
|
+
- Enforce typecheck in CI (noEmit + typecheck) and keep separate from build to catch type errors early.
|
|
234
|
+
|
|
235
|
+
- **Performance tuning**
|
|
236
|
+
- `skipLibCheck` usage for speed in CI, and segment builds if needed.
|
|
237
|
+
|
|
238
|
+
- **Dev dependency choices**
|
|
239
|
+
- Add and pin: `typescript`, `ts-node` (if used), `@types/node`, `@typescript-eslint/*`, `tslib`.
|
|
240
|
+
|
|
241
|
+
- **Scaffolding**
|
|
242
|
+
- Provide a TS rule template replacing `data/template.js`.
|
|
243
|
+
|
|
244
|
+
- **Migration approach**
|
|
245
|
+
- Big bang vs module-by-module with `allowJs`; define the cutover point for flipping scripts to compiled artifacts.
|
|
246
|
+
|
|
247
|
+
- **Source map policy**
|
|
248
|
+
- Whether to emit for executors (useful for debugging) and how to ship them.
|
|
249
|
+
|
|
250
|
+
- **Error handling consistency**
|
|
251
|
+
- Tighten thrown vs returned error patterns and type them across modules.
|
|
252
|
+
|
|
253
|
+
- **API surfaces to freeze**
|
|
254
|
+
- Identify external-callable functions (e.g., `doJob`) and lock their types as public contracts.
|
|
255
|
+
|
|
256
|
+
- **Coding ergonomics**
|
|
257
|
+
- Decide on utility types and helpers to avoid repeated broad `any`.
|
|
258
|
+
|
|
259
|
+
- **CI matrix**
|
|
260
|
+
- If Node versions vary in your environments, decide on supported versions and align TS `target` and features.
|
|
261
|
+
|
|
262
|
+
- **Sourcemap stack traces**
|
|
263
|
+
- Configure `source-map-support` if you need clean stack traces in production.
|
|
264
|
+
|
|
265
|
+
- **Rule discovery**
|
|
266
|
+
- If you keep filesystem discovery of rules, define a typed manifest generator to bridge dynamic loading and static typing.
|
|
267
|
+
|
|
268
|
+
- **Binary and non-TS code**
|
|
269
|
+
- Exclude third-party/minified JS from the TS pipeline; document it in `tsconfig.exclude`.
|
|
270
|
+
|
|
271
|
+
- **Globbing and watch**
|
|
272
|
+
- Decide on watch-mode for dev across large tree and avoid compiling validation target fixtures.
|
|
273
|
+
|
|
274
|
+
- **Optional refactors**
|
|
275
|
+
- Replace stringly-typed error/status codes with enums for compile-time checks.
|
|
276
|
+
|
|
277
|
+
- **Docs for contributors**
|
|
278
|
+
- Update `CONTRIBUTING.md` to explain adding new rules/tests in TS.
|
|
279
|
+
|
|
280
|
+
- **License and headers policy**
|
|
281
|
+
- Ensure headers are preserved via tsconfig `removeComments: false` (or custom tooling).
|
|
282
|
+
|
|
283
|
+
- **Long-term maintenance**
|
|
284
|
+
- Plan for gradually increasing strictness and paying down `any`/casts.
|
|
285
|
+
|
|
286
|
+
- **Ownership of types**
|
|
287
|
+
- Assign owners for core type packages (job/report schema) to prevent drift.
|
|
288
|
+
|
|
289
|
+
- **Release cadence**
|
|
290
|
+
- Decide on a major version for TS cutover and soft-deprecate JS.
|
|
291
|
+
|
|
292
|
+
- **Verification runs**
|
|
293
|
+
- Run the existing `validation` flows pre/post migration to assert parity.
|
|
294
|
+
|
|
295
|
+
- **Scripting updates**
|
|
296
|
+
- Update NPM scripts to call `node dist/...` or `ts-node ...` consistently.
|
|
297
|
+
|
|
298
|
+
- **Formatting**
|
|
299
|
+
- Decide on Prettier integration for TS files.
|
|
300
|
+
|
|
301
|
+
- **Path aliases**
|
|
302
|
+
- Whether to introduce TS path mapping (e.g., `@procs/*`) and align runtime with `tsconfig-paths` if used.
|
|
303
|
+
|
|
304
|
+
- **Type exposure for consumers**
|
|
305
|
+
- If this is used as a library, add `types` in `package.json` and consider dual-emit CJS/ESM with an `exports` map.
|
|
306
|
+
|
|
307
|
+
- **Internal logging contracts**
|
|
308
|
+
- Give `tellServer` a typed param object instead of loosely concatenated query strings.
|
|
309
|
+
|
|
310
|
+
- **IPC contracts**
|
|
311
|
+
- Type the message payloads between parent and forked child (act results, error codes) as discriminated unions.
|
|
312
|
+
|
|
313
|
+
- **Rule authoring ergonomics**
|
|
314
|
+
- Provide typed helpers (`init`, `report`, `simplify`) signatures and ensure rule modules stay small and consistent.
|
|
315
|
+
|
|
316
|
+
- **Binary deps (Playwright)**
|
|
317
|
+
- Decide if Playwright version pins need to change for type stability.
|
|
318
|
+
|
|
319
|
+
- **Local dev**
|
|
320
|
+
- Editor/tsserver performance considerations; exclude large static trees to keep TS fast.
|
|
321
|
+
|
|
322
|
+
- **Guarding dynamic text operations**
|
|
323
|
+
- Tight typing for text processing helpers (`debloat`, `textOf`) to reduce nullability issues.
|
|
324
|
+
|
|
325
|
+
- **Backward-compatible shims**
|
|
326
|
+
- If external systems call JS entrypoints, add thin JS shims that `require` built outputs.
|
|
327
|
+
|
|
328
|
+
- **Risk acceptance**
|
|
329
|
+
- Explicitly document areas that remain `any` for practicality (dynamic rule loading, external tool outputs).
|
|
330
|
+
|
|
331
|
+
- **Ownership and review**
|
|
332
|
+
- Establish code owners for type changes spanning modules (`procs/`, `tests/`, `validation/`).
|
|
333
|
+
|
|
334
|
+
- **Documentation of schemas**
|
|
335
|
+
- Publish the job/report JSON schema alongside TS types to keep runtime validation aligned.
|
|
336
|
+
|
|
337
|
+
- **SLA for migration**
|
|
338
|
+
- Timeline and checkpoints (compile, typecheck clean, parity runs, strictness uplift).
|
|
339
|
+
|
|
340
|
+
- **Final cutover**
|
|
341
|
+
- Switch scripts to compiled artifacts, remove `allowJs`, and enforce TS-only in CI.
|
|
342
|
+
|
|
343
|
+
- **Post-cutover cleanups**
|
|
344
|
+
- Remove unused JS files, codemod leftovers, and deprecated helpers.
|
|
345
|
+
|
|
346
|
+
- **Observability**
|
|
347
|
+
- Optional: typed structured logs to replace ad hoc `console.log` parsing in CI.
|
|
348
|
+
|
|
349
|
+
- **Security review**
|
|
350
|
+
- Review `page.evaluate` and dynamic inputs under strict types; add guards where types reveal risks.
|
|
351
|
+
|
|
352
|
+
- **Team training**
|
|
353
|
+
- Align on TS patterns (narrowing, discriminated unions, module augmentation).
|
|
354
|
+
|
|
355
|
+
- **Performance validation**
|
|
356
|
+
- Ensure no regressions in tool time limits and process orchestration after build step insertion.
|
|
357
|
+
|
|
358
|
+
- **Long-term benefits**
|
|
359
|
+
- Decide which parts gain the most from rich typing first (job/act schema, rule registry, Playwright helpers).
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
- Converted the repo’s needs into concrete decision points covering module format, build/run, tsconfig, domain typing, dynamic loading, child-process pathing, 3rd‑party types, and CI/publishing impacts.
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
**User**
|
|
367
|
+
|
|
368
|
+
Another conversion that I want to consider for this project is a conversion from commonJS to ES modules. I have two questions about this:
|
|
369
|
+
(1) What are the major decisions that will be required if the project is to undergo that conversion?
|
|
370
|
+
(2) If both conversions are to be performed, are there efficiencies in performing them together rather than sequentially?
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
**Cursor**
|
|
375
|
+
|
|
376
|
+
I'll analyze the current codebase to understand the CommonJS patterns and then address both your questions about ES module conversion and the efficiency of combining it with TypeScript conversion.
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
Now let me examine some more files to understand the module patterns better:
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
Now let me check some dynamic require patterns and child process usage:
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
Based on my analysis of the codebase, I can now provide comprehensive answers to both questions about CommonJS to ES modules conversion and the efficiency of combining it with TypeScript conversion.
|
|
386
|
+
|
|
387
|
+
## (1) Major decisions for CommonJS to ES modules conversion
|
|
388
|
+
|
|
389
|
+
### **Module system and package.json changes**
|
|
390
|
+
- **`package.json` `"type"` field**: Set to `"module"` to enable ES modules by default, or use `.mjs` extensions
|
|
391
|
+
- **Entry point updates**: Update `"main"` field and potentially add `"exports"` map for dual CJS/ESM support
|
|
392
|
+
- **Script execution**: All `package.json` scripts will need to handle ES modules (may need `--loader` flags or different execution)
|
|
393
|
+
|
|
394
|
+
### **Import/export syntax conversion**
|
|
395
|
+
- **134 `require()` calls** need conversion to `import` statements
|
|
396
|
+
- **91 `exports.` assignments** need conversion to `export` statements
|
|
397
|
+
- **2 `module.exports`** need conversion to `export default`
|
|
398
|
+
- **Dynamic requires**: The codebase has dynamic `require()` calls like `require(\`../tests/${which}\`)` that need special handling
|
|
399
|
+
|
|
400
|
+
### **Child process and dynamic loading**
|
|
401
|
+
- **`child_process.fork` paths**: Currently forks `${__dirname}/procs/doTestAct` - need to handle ES module paths
|
|
402
|
+
- **Dynamic module loading**: `tests/testaro.js` dynamically loads rule modules by filename - requires `import()` or registry pattern
|
|
403
|
+
- **Circular dependencies**: Current `require()` patterns may have circular deps that need restructuring
|
|
404
|
+
|
|
405
|
+
### **Node.js built-in modules**
|
|
406
|
+
- **`fs/promises`**: Already using modern Node.js APIs, should work with ES modules
|
|
407
|
+
- **`child_process`**: Fork paths need adjustment for ES module execution
|
|
408
|
+
- **`os`, `path`**: Standard Node.js modules, should work fine
|
|
409
|
+
|
|
410
|
+
### **Third-party dependencies**
|
|
411
|
+
- **Playwright ecosystem**: Need to verify all dependencies support ES modules
|
|
412
|
+
- **QualWeb, Alfa, etc.**: Check if these packages have ES module exports
|
|
413
|
+
- **`dotenv`**: May need different import syntax or configuration
|
|
414
|
+
|
|
415
|
+
### **File extensions and resolution**
|
|
416
|
+
- **`.js` to `.mjs`**: Decide whether to rename files or use `"type": "module"`
|
|
417
|
+
- **JSON imports**: Currently using `fs.readFile()` for JSON - could use `import` with `resolveJsonModule`
|
|
418
|
+
- **Relative imports**: All relative paths need explicit `.js` extensions in ES modules
|
|
419
|
+
|
|
420
|
+
### **Runtime behavior changes**
|
|
421
|
+
- **`__dirname` and `__filename`**: Not available in ES modules, need `import.meta.url` equivalents
|
|
422
|
+
- **Top-level await**: ES modules support top-level await, could simplify some async patterns
|
|
423
|
+
- **Strict mode**: ES modules are always in strict mode
|
|
424
|
+
|
|
425
|
+
### **Backward compatibility**
|
|
426
|
+
- **Dual package support**: Consider supporting both CJS and ESM for external consumers
|
|
427
|
+
- **Migration strategy**: Gradual vs. all-at-once conversion
|
|
428
|
+
- **External API**: How this affects consumers of the library
|
|
429
|
+
|
|
430
|
+
## (2) Efficiencies of combining TypeScript and ES modules conversion
|
|
431
|
+
|
|
432
|
+
### **Significant synergies exist:**
|
|
433
|
+
|
|
434
|
+
#### **Single migration effort**
|
|
435
|
+
- **One codebase transformation** instead of two separate major changes
|
|
436
|
+
- **Unified tooling setup**: TypeScript compiler can handle both syntax conversion and type checking
|
|
437
|
+
- **Single testing cycle**: Validate both module system and type safety together
|
|
438
|
+
|
|
439
|
+
#### **TypeScript ES module advantages**
|
|
440
|
+
- **Better ES module support**: TypeScript has excellent ES module tooling
|
|
441
|
+
- **`moduleResolution: "nodenext"`**: TypeScript's modern module resolution works well with ES modules
|
|
442
|
+
- **Import/export typing**: TypeScript can type ES module imports more precisely than CommonJS
|
|
443
|
+
|
|
444
|
+
#### **Reduced complexity**
|
|
445
|
+
- **No intermediate state**: Avoid having to maintain both CommonJS and TypeScript simultaneously
|
|
446
|
+
- **Single build pipeline**: One compilation step handles both transformations
|
|
447
|
+
- **Unified tooling**: ESLint, Prettier, etc. can be configured once for both
|
|
448
|
+
|
|
449
|
+
#### **Modern development experience**
|
|
450
|
+
- **Native ES module support**: TypeScript + ES modules is the modern standard
|
|
451
|
+
- **Better tree shaking**: ES modules enable better dead code elimination
|
|
452
|
+
- **Future-proof**: Aligns with JavaScript ecosystem direction
|
|
453
|
+
|
|
454
|
+
### **Potential challenges of combined approach:**
|
|
455
|
+
|
|
456
|
+
#### **Complexity management**
|
|
457
|
+
- **Two major changes at once**: Higher risk of introducing bugs
|
|
458
|
+
- **Debugging difficulty**: Harder to isolate whether issues are from module conversion or type conversion
|
|
459
|
+
- **Learning curve**: Team needs to understand both changes simultaneously
|
|
460
|
+
|
|
461
|
+
#### **Migration strategy**
|
|
462
|
+
- **All-or-nothing**: Harder to do incremental migration
|
|
463
|
+
- **Testing complexity**: Need to validate both module loading and type correctness
|
|
464
|
+
- **Rollback difficulty**: Harder to rollback one change without the other
|
|
465
|
+
|
|
466
|
+
### **Recommended approach:**
|
|
467
|
+
|
|
468
|
+
#### **Sequential with overlap** (Most efficient)
|
|
469
|
+
1. **Phase 1**: Convert to TypeScript while keeping CommonJS
|
|
470
|
+
- Add TypeScript tooling and types
|
|
471
|
+
- Convert syntax to TypeScript
|
|
472
|
+
- Establish type safety
|
|
473
|
+
|
|
474
|
+
2. **Phase 2**: Convert to ES modules within TypeScript
|
|
475
|
+
- Use TypeScript's ES module support
|
|
476
|
+
- Convert `require`/`exports` to `import`/`export`
|
|
477
|
+
- Handle dynamic loading with typed `import()`
|
|
478
|
+
|
|
479
|
+
#### **Benefits of this approach:**
|
|
480
|
+
- **Incremental validation**: Can test TypeScript conversion before module conversion
|
|
481
|
+
- **Type safety during module conversion**: TypeScript will catch module-related errors
|
|
482
|
+
- **Familiar tooling**: TypeScript tooling handles ES module conversion well
|
|
483
|
+
- **Reduced risk**: Smaller, manageable changes
|
|
484
|
+
|
|
485
|
+
#### **Tooling advantages:**
|
|
486
|
+
- **TypeScript compiler**: Can transpile ES modules to CommonJS if needed during transition
|
|
487
|
+
- **Better error messages**: TypeScript provides clearer errors for module issues
|
|
488
|
+
- **IDE support**: Better autocomplete and refactoring for ES modules in TypeScript
|
|
489
|
+
|
|
490
|
+
### **Specific efficiencies for this codebase:**
|
|
491
|
+
|
|
492
|
+
#### **Dynamic loading patterns**
|
|
493
|
+
- **Current**: `require(\`../tests/${which}\`)`
|
|
494
|
+
- **TypeScript + ESM**: `const module = await import(\`../tests/${which}.js\`)` with proper typing
|
|
495
|
+
|
|
496
|
+
#### **Child process handling**
|
|
497
|
+
- **Current**: `fork(\`${__dirname}/procs/doTestAct\`)`
|
|
498
|
+
- **TypeScript + ESM**: Use `import.meta.url` and proper ES module paths
|
|
499
|
+
|
|
500
|
+
#### **JSON handling**
|
|
501
|
+
- **Current**: `fs.readFile()` + `JSON.parse()`
|
|
502
|
+
- **TypeScript + ESM**: `import data from './config.json' assert { type: 'json' }` with typed interfaces
|
|
503
|
+
|
|
504
|
+
### **Conclusion:**
|
|
505
|
+
**Yes, there are significant efficiencies in performing both conversions together**, especially using the sequential approach. The TypeScript tooling provides excellent support for ES module conversion, and doing both changes in a coordinated manner reduces overall migration effort while providing better type safety throughout the process.
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
**User**
|
|
510
|
+
|
|
511
|
+
I would like advice on an upgrade strategy. I want to consider both of the upgrades on which you have commented above.
|
|
512
|
+
|
|
513
|
+
I also want to consider other modernizations, which may include:
|
|
514
|
+
1. changing package manager from npm to pnpm
|
|
515
|
+
2. joining Testaro, its closely related package Testilo, and possibly also a new closely related package creating a UI for these two pagkages into a single monorepo
|
|
516
|
+
3. adding type checking
|
|
517
|
+
4. using Biome for linting
|
|
518
|
+
5. using Playwright Test instead of plain Playwright
|
|
519
|
+
6. making the package container-safe so it no longer crashes when containerized
|
|
520
|
+
7. adding robust and user-friendly support for the easy construction of tests for customer-specific custom accessibility rules
|
|
521
|
+
|
|
522
|
+
There could be more.
|
|
523
|
+
|
|
524
|
+
My hunch is that the efficiencies in simultaneous multiple upgrades would be lost if I attempted to perform them on the entire existing codebase, and a long time would pass before the bugs were extinguished. Therefore, I want to consider an upgrade strategy that begins with a minimal package that is bug-free and is kept bug-free throughout the process, as more items are added.
|
|
525
|
+
|
|
526
|
+
For example, the initial minimal package (or monorepo) could implement only one testing tool, and it could be the most antiquated one, so that the initial design is foreseeably compatible with all of the 10 non-Testaro testing tools with respect to module type, typing, and other potential sources of incompatibility. Once it is established that the architecture succeeds with that testing tool for all of the upgrade objectives (e.g., containerizability, Playwright Test conversion), then a second tool could be added, with advantage taken of the lessons learned so far.
|
|
527
|
+
|
|
528
|
+
Does this strategy seem appropriate in this situation, or does a different strategy seem better?
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
**Cursor**
|
|
533
|
+
|
|
534
|
+
Your strategy is **excellent** and highly appropriate for this situation. You've correctly identified that attempting all upgrades simultaneously on the entire codebase would be risky and inefficient. Let me analyze why your approach is sound and suggest some refinements.
|
|
535
|
+
|
|
536
|
+
## Why your strategy is optimal
|
|
537
|
+
|
|
538
|
+
### **Risk management**
|
|
539
|
+
- **Incremental validation**: Each step can be thoroughly tested before proceeding
|
|
540
|
+
- **Early failure detection**: Problems surface quickly rather than after massive changes
|
|
541
|
+
- **Rollback safety**: Easy to revert individual changes if issues arise
|
|
542
|
+
- **Learning curve**: Team can master new patterns incrementally
|
|
543
|
+
|
|
544
|
+
### **Architecture validation**
|
|
545
|
+
- **Design verification**: The minimal package proves the architecture works
|
|
546
|
+
- **Pattern establishment**: Creates templates for subsequent additions
|
|
547
|
+
- **Compatibility testing**: Ensures the chosen tool (oldest) works with all planned upgrades
|
|
548
|
+
|
|
549
|
+
### **Development efficiency**
|
|
550
|
+
- **Parallel work**: Once patterns are established, multiple tools can be added simultaneously
|
|
551
|
+
- **Reduced debugging**: Smaller scope makes issues easier to isolate and fix
|
|
552
|
+
- **Continuous delivery**: Each increment can be deployed and validated
|
|
553
|
+
|
|
554
|
+
## Recommended implementation strategy
|
|
555
|
+
|
|
556
|
+
### **Phase 1: Minimal Foundation (2-4 weeks)**
|
|
557
|
+
Create a new monorepo with:
|
|
558
|
+
|
|
559
|
+
```
|
|
560
|
+
testaro-monorepo/
|
|
561
|
+
├── packages/
|
|
562
|
+
│ ├── core/ # Shared utilities, types
|
|
563
|
+
│ ├── testaro/ # Minimal implementation
|
|
564
|
+
│ └── testilo/ # Placeholder for future
|
|
565
|
+
├── tools/
|
|
566
|
+
│ └── ui/ # Future UI package
|
|
567
|
+
└── apps/
|
|
568
|
+
└── example/ # Demo/test app
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
**Minimal testaro package should include:**
|
|
572
|
+
- **One testing tool**: Choose the most "antiquated" one (likely `nuVal` or `htmlcs` based on your codebase)
|
|
573
|
+
- **Core architecture**: Module system, typing, containerization, Playwright Test
|
|
574
|
+
- **Essential features**: Job processing, report generation, basic CLI
|
|
575
|
+
|
|
576
|
+
### **Phase 2: Architecture Validation (1-2 weeks)**
|
|
577
|
+
- **All upgrades applied**: TypeScript, ES modules, pnpm, Biome, Playwright Test, containerization
|
|
578
|
+
- **Full testing**: Unit tests, integration tests, container tests
|
|
579
|
+
- **Performance validation**: Ensure the architecture scales
|
|
580
|
+
- **Documentation**: Establish patterns and guidelines
|
|
581
|
+
|
|
582
|
+
### **Phase 3: Incremental Tool Addition (2-3 weeks per tool)**
|
|
583
|
+
Add tools in order of complexity:
|
|
584
|
+
1. **Simple tools first**: `nuVal`, `htmlcs`, `wave`
|
|
585
|
+
2. **Medium complexity**: `axe`, `ed11y`, `ibm`
|
|
586
|
+
3. **Complex tools**: `alfa`, `qualWeb`, `aslint`
|
|
587
|
+
4. **Testaro rules**: Add the custom accessibility rules
|
|
588
|
+
|
|
589
|
+
### **Phase 4: Integration & Polish (2-4 weeks)**
|
|
590
|
+
- **Testilo integration**: Add Testilo package
|
|
591
|
+
- **UI development**: Create the UI package
|
|
592
|
+
- **Custom rules framework**: Implement the extensible rules system
|
|
593
|
+
- **Documentation**: Complete user guides and API docs
|
|
594
|
+
|
|
595
|
+
## Specific recommendations for your upgrades
|
|
596
|
+
|
|
597
|
+
### **1. Package manager: npm → pnpm**
|
|
598
|
+
- **Start with pnpm**: Set up the monorepo with pnpm from the beginning
|
|
599
|
+
- **Benefits**: Better monorepo support, faster installs, disk efficiency
|
|
600
|
+
- **Migration**: Use `pnpm import` to convert existing `package-lock.json`
|
|
601
|
+
|
|
602
|
+
### **2. Monorepo structure**
|
|
603
|
+
```
|
|
604
|
+
testaro-monorepo/
|
|
605
|
+
├── pnpm-workspace.yaml
|
|
606
|
+
├── packages/
|
|
607
|
+
│ ├── core/ # Shared types, utilities
|
|
608
|
+
│ ├── testaro/ # Main testing engine
|
|
609
|
+
│ ├── testilo/ # Report processing
|
|
610
|
+
│ └── ui/ # Web interface
|
|
611
|
+
├── apps/
|
|
612
|
+
│ ├── cli/ # Command-line interface
|
|
613
|
+
│ └── demo/ # Example usage
|
|
614
|
+
└── tools/
|
|
615
|
+
└── rule-builder/ # Custom rule creation tool
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
### **3. TypeScript + ES modules**
|
|
619
|
+
- **Start with strict TypeScript**: `strict: true`, `noImplicitAny: true`
|
|
620
|
+
- **ES modules from day one**: Use `"type": "module"` in package.json
|
|
621
|
+
- **Modern tooling**: Vite or esbuild for fast builds
|
|
622
|
+
|
|
623
|
+
### **4. Biome for linting**
|
|
624
|
+
- **Replace ESLint**: Biome is faster and more modern
|
|
625
|
+
- **Configuration**: Start with default rules, customize incrementally
|
|
626
|
+
- **Pre-commit hooks**: Ensure code quality
|
|
627
|
+
|
|
628
|
+
### **5. Playwright Test**
|
|
629
|
+
- **Replace custom test orchestration**: Use Playwright Test's built-in features
|
|
630
|
+
- **Parallel execution**: Better performance than current sequential approach
|
|
631
|
+
- **Better reporting**: Built-in HTML reports and screenshots
|
|
632
|
+
|
|
633
|
+
### **6. Containerization**
|
|
634
|
+
- **Multi-stage Dockerfile**: Separate build and runtime stages
|
|
635
|
+
- **Health checks**: Ensure container starts properly
|
|
636
|
+
- **Resource limits**: Prevent crashes from memory issues
|
|
637
|
+
- **Volume mounts**: For persistent data
|
|
638
|
+
|
|
639
|
+
### **7. Custom rules framework**
|
|
640
|
+
- **Plugin architecture**: Allow external rule definitions
|
|
641
|
+
- **TypeScript interfaces**: Strongly typed rule contracts
|
|
642
|
+
- **Validation**: Ensure custom rules follow patterns
|
|
643
|
+
- **Documentation**: Auto-generate docs from rule definitions
|
|
644
|
+
|
|
645
|
+
## Alternative strategies to consider
|
|
646
|
+
|
|
647
|
+
### **Option A: Your proposed strategy (Recommended)**
|
|
648
|
+
- **Pros**: Low risk, learnable, scalable
|
|
649
|
+
- **Cons**: Longer timeline, more phases
|
|
650
|
+
- **Best for**: Complex codebase, team learning, production stability
|
|
651
|
+
|
|
652
|
+
### **Option B: Big bang approach**
|
|
653
|
+
- **Pros**: Faster completion, single migration effort
|
|
654
|
+
- **Cons**: High risk, difficult debugging, potential for major issues
|
|
655
|
+
- **Best for**: Simple codebase, experienced team, non-production use
|
|
656
|
+
|
|
657
|
+
### **Option C: Hybrid approach**
|
|
658
|
+
- **Phase 1**: Create new architecture with minimal features
|
|
659
|
+
- **Phase 2**: Migrate existing codebase to new architecture
|
|
660
|
+
- **Phase 3**: Add remaining features
|
|
661
|
+
- **Pros**: Balance of risk and speed
|
|
662
|
+
- **Cons**: More complex migration path
|
|
663
|
+
|
|
664
|
+
## Specific tool selection for minimal package
|
|
665
|
+
|
|
666
|
+
Based on your codebase analysis, I recommend starting with **`nuVal`** as your minimal tool because:
|
|
667
|
+
|
|
668
|
+
- **Simple implementation**: Basic HTML validation
|
|
669
|
+
- **Minimal dependencies**: Fewer external packages to manage
|
|
670
|
+
- **Clear patterns**: Easy to establish the architecture
|
|
671
|
+
- **Compatibility**: Works with all planned upgrades
|
|
672
|
+
- **Debugging**: Simple enough to troubleshoot issues quickly
|
|
673
|
+
|
|
674
|
+
## Success metrics for each phase
|
|
675
|
+
|
|
676
|
+
### **Phase 1 success criteria:**
|
|
677
|
+
- [ ] Minimal package runs without errors
|
|
678
|
+
- [ ] All upgrades (TypeScript, ES modules, etc.) work
|
|
679
|
+
- [ ] Container runs successfully
|
|
680
|
+
- [ ] Basic CLI works
|
|
681
|
+
- [ ] Report generation works
|
|
682
|
+
|
|
683
|
+
### **Phase 2 success criteria:**
|
|
684
|
+
- [ ] Performance meets requirements
|
|
685
|
+
- [ ] Memory usage is stable
|
|
686
|
+
- [ ] Error handling is robust
|
|
687
|
+
- [ ] Documentation is complete
|
|
688
|
+
|
|
689
|
+
### **Phase 3 success criteria:**
|
|
690
|
+
- [ ] Each tool addition takes < 1 week
|
|
691
|
+
- [ ] No regression in existing functionality
|
|
692
|
+
- [ ] New patterns are established
|
|
693
|
+
- [ ] Team is comfortable with process
|
|
694
|
+
|
|
695
|
+
## Conclusion
|
|
696
|
+
|
|
697
|
+
Your strategy is **highly appropriate** and shows excellent engineering judgment. The incremental approach will:
|
|
698
|
+
|
|
699
|
+
1. **Minimize risk** while maximizing learning
|
|
700
|
+
2. **Establish patterns** that can be replicated
|
|
701
|
+
3. **Enable parallel development** once the foundation is solid
|
|
702
|
+
4. **Provide continuous value** throughout the process
|
|
703
|
+
5. **Allow for course correction** based on early learnings
|
|
704
|
+
|
|
705
|
+
The key is to start with the most constrained, simplest possible implementation and gradually add complexity. This approach has proven successful for many major software modernizations and is particularly well-suited for your complex, multi-faceted upgrade requirements.
|
|
706
|
+
|
|
707
|
+
```plaintext
|
|
708
|
+
testaro-monorepo/
|
|
709
|
+
├── packages/
|
|
710
|
+
│ ├── core/ # Shared utilities, types
|
|
711
|
+
│ ├── testaro/ # Minimal implementation
|
|
712
|
+
│ └── testilo/ # Placeholder for future
|
|
713
|
+
├── tools/
|
|
714
|
+
│ └── ui/ # Future UI package
|
|
715
|
+
└── apps/
|
|
716
|
+
└── example/ # Demo/test app
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
```plaintext
|
|
720
|
+
testaro-monorepo/
|
|
721
|
+
├── pnpm-workspace.yaml
|
|
722
|
+
├── packages/
|
|
723
|
+
│ ├── core/ # Shared types, utilities
|
|
724
|
+
│ ├── testaro/ # Main testing engine
|
|
725
|
+
│ ├── testilo/ # Report processing
|
|
726
|
+
│ └── ui/ # Web interface
|
|
727
|
+
├── apps/
|
|
728
|
+
│ ├── cli/ # Command-line interface
|
|
729
|
+
│ └── demo/ # Example usage
|
|
730
|
+
└── tools/
|
|
731
|
+
└── rule-builder/ # Custom rule creation tool
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
---
|
|
735
|
+
|
|
736
|
+
**User**
|
|
737
|
+
|
|
738
|
+
Comments on the above suggestions:
|
|
739
|
+
|
|
740
|
+
The `nuVal` tool is one of three (also `wave` and `wax`) that operate as APIs, with the substantial disadvantage that they can test only publicly reachable pages. The `nuVal` tool could be brought into the package (see How to to run your own copy of the Nu Html Checker at @https://validator.w3.org/nu/about.html). Until then, it seems to me that it avoids presenting incompatibility problems, so I believe another tool would be better to start with. But that decision could await the start of the upgrade project.
|
|
741
|
+
|
|
742
|
+
I forgot to mention the modernization of validation. I am using that term in place of unit, integration, and end-to-end testing, because the entire project is a testing project and it gets confusing when the word “test” can refer both to the primary functionality of the project and the verification that the project works correctly. Currently validation is limited to the Testaro tool’s 55 or so tests. The idea behind that is that this project treats the 10 external tools like oracles that make claims, but these claims are inherently suspect, so for any tool there are 10 others that may perform their own version of any test. When tools disagree, Testaro does not try to decide which is correct. Instead, it uses Testilo to find similar tests of other tools and collect the results together so users can experience the disagreements and decide for themselves which tools are correct. Such user judgments can be collected by the UI and lead to deprecations by Testilo so that dubious tests are disregarded. Validation of the Testaro tests is currently exposed in a nonstandard way, and I want to consider converting it to a widely accepted interface.
|
|
743
|
+
|
|
744
|
+
I also wonder whether Turborepo should be used if the project becomes a monorepo.
|
|
745
|
+
|
|
746
|
+
---
|
|
747
|
+
|
|
748
|
+
**Cursor**
|
|
749
|
+
|
|
750
|
+
Excellent clarifications! Your insights about `nuVal` and the validation approach significantly refine the strategy. Let me address your points and provide updated recommendations.
|
|
751
|
+
|
|
752
|
+
## Tool selection reconsideration
|
|
753
|
+
|
|
754
|
+
You're absolutely right about `nuVal`'s limitations. Since it requires publicly reachable pages and operates as an API, it's not ideal for the minimal package. Better alternatives for the initial tool:
|
|
755
|
+
|
|
756
|
+
### **Recommended alternatives:**
|
|
757
|
+
1. **`htmlcs`** - Pure JavaScript, no external dependencies, works on any HTML
|
|
758
|
+
2. **`wave`** - Also API-based, so same limitations as `nuVal`
|
|
759
|
+
3. **`wax`** - API-based as well
|
|
760
|
+
4. **`axe`** - Self-contained, works on any page, excellent for establishing patterns
|
|
761
|
+
|
|
762
|
+
**I recommend starting with `axe`** because:
|
|
763
|
+
- **Self-contained**: No external API dependencies
|
|
764
|
+
- **Mature ecosystem**: Well-established patterns for TypeScript, ES modules, etc.
|
|
765
|
+
- **Comprehensive**: Covers many accessibility rules, good for pattern establishment
|
|
766
|
+
- **Playwright integration**: Has excellent Playwright Test support
|
|
767
|
+
- **Container-friendly**: No external network dependencies
|
|
768
|
+
|
|
769
|
+
## Validation modernization strategy
|
|
770
|
+
|
|
771
|
+
Your distinction between "testing" (primary functionality) and "validation" (verification) is crucial. Here's how to modernize the validation approach:
|
|
772
|
+
|
|
773
|
+
### **Current validation approach:**
|
|
774
|
+
- **55 Testaro tests** as oracles
|
|
775
|
+
- **Cross-tool comparison** via Testilo
|
|
776
|
+
- **User judgment collection** for deprecation decisions
|
|
777
|
+
|
|
778
|
+
### **Modernized validation strategy:**
|
|
779
|
+
|
|
780
|
+
#### **1. Standardized test interfaces**
|
|
781
|
+
```typescript
|
|
782
|
+
// Core validation interface
|
|
783
|
+
interface ValidationSuite {
|
|
784
|
+
name: string;
|
|
785
|
+
version: string;
|
|
786
|
+
run(page: Page, options: ValidationOptions): Promise<ValidationResult>;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
// Tool-specific validation
|
|
790
|
+
interface ToolValidation extends ValidationSuite {
|
|
791
|
+
tool: 'axe' | 'wave' | 'htmlcs' | 'nuVal' | 'wax' | 'alfa' | 'qualWeb' | 'ibm' | 'ed11y' | 'aslint';
|
|
792
|
+
rules: RuleDefinition[];
|
|
793
|
+
}
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
#### **2. Playwright Test integration**
|
|
797
|
+
```typescript
|
|
798
|
+
// validation/tests/axe.spec.ts
|
|
799
|
+
import { test, expect } from '@playwright/test';
|
|
800
|
+
import { AxeValidation } from '../packages/core/src/validations/axe';
|
|
801
|
+
|
|
802
|
+
test.describe('Axe Tool Validation', () => {
|
|
803
|
+
test('should detect basic accessibility violations', async ({ page }) => {
|
|
804
|
+
await page.goto('http://localhost:3000/test-pages/basic-violations.html');
|
|
805
|
+
|
|
806
|
+
const validation = new AxeValidation();
|
|
807
|
+
const result = await validation.run(page);
|
|
808
|
+
|
|
809
|
+
expect(result.violations).toHaveLength(2);
|
|
810
|
+
expect(result.violations[0].id).toBe('color-contrast');
|
|
811
|
+
});
|
|
812
|
+
});
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
#### **3. Cross-tool validation framework**
|
|
816
|
+
```typescript
|
|
817
|
+
// validation/tests/cross-tool.spec.ts
|
|
818
|
+
test.describe('Cross-Tool Validation', () => {
|
|
819
|
+
test('should identify tool disagreements', async ({ page }) => {
|
|
820
|
+
const results = await Promise.all([
|
|
821
|
+
axeValidation.run(page),
|
|
822
|
+
waveValidation.run(page),
|
|
823
|
+
htmlcsValidation.run(page)
|
|
824
|
+
]);
|
|
825
|
+
|
|
826
|
+
const disagreements = findDisagreements(results);
|
|
827
|
+
expect(disagreements).toBeDefined();
|
|
828
|
+
expect(disagreements.length).toBeGreaterThan(0);
|
|
829
|
+
});
|
|
830
|
+
});
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
#### **4. User judgment collection**
|
|
834
|
+
```typescript
|
|
835
|
+
// packages/ui/src/components/ValidationReview.tsx
|
|
836
|
+
interface ValidationReview {
|
|
837
|
+
testId: string;
|
|
838
|
+
toolResults: ToolResult[];
|
|
839
|
+
userJudgment: 'correct' | 'incorrect' | 'unclear';
|
|
840
|
+
reasoning: string;
|
|
841
|
+
}
|
|
842
|
+
```
|
|
843
|
+
|
|
844
|
+
## Turborepo for monorepo management
|
|
845
|
+
|
|
846
|
+
**Yes, absolutely use Turborepo!** It's specifically designed for this use case and provides significant advantages:
|
|
847
|
+
|
|
848
|
+
### **Turborepo benefits:**
|
|
849
|
+
- **Incremental builds**: Only rebuilds what changed
|
|
850
|
+
- **Parallel execution**: Runs tasks across packages simultaneously
|
|
851
|
+
- **Caching**: Intelligent caching of build artifacts
|
|
852
|
+
- **Dependency management**: Tracks inter-package dependencies
|
|
853
|
+
- **CI optimization**: Dramatically faster CI/CD pipelines
|
|
854
|
+
|
|
855
|
+
### **Recommended monorepo structure:**
|
|
856
|
+
```
|
|
857
|
+
testaro-monorepo/
|
|
858
|
+
├── turbo.json
|
|
859
|
+
├── pnpm-workspace.yaml
|
|
860
|
+
├── packages/
|
|
861
|
+
│ ├── core/ # Shared types, utilities
|
|
862
|
+
│ ├── testaro/ # Main testing engine
|
|
863
|
+
│ ├── testilo/ # Report processing
|
|
864
|
+
│ ├── ui/ # Web interface
|
|
865
|
+
│ └── validation/ # Validation framework
|
|
866
|
+
├── apps/
|
|
867
|
+
│ ├── cli/ # Command-line interface
|
|
868
|
+
│ ├── demo/ # Example usage
|
|
869
|
+
│ └── validation-runner/ # Validation test runner
|
|
870
|
+
└── tools/
|
|
871
|
+
└── rule-builder/ # Custom rule creation tool
|
|
872
|
+
```
|
|
873
|
+
|
|
874
|
+
### **turbo.json configuration:**
|
|
875
|
+
```json
|
|
876
|
+
{
|
|
877
|
+
"pipeline": {
|
|
878
|
+
"build": {
|
|
879
|
+
"dependsOn": ["^build"],
|
|
880
|
+
"outputs": ["dist/**"]
|
|
881
|
+
},
|
|
882
|
+
"test": {
|
|
883
|
+
"dependsOn": ["build"],
|
|
884
|
+
"outputs": ["coverage/**"]
|
|
885
|
+
},
|
|
886
|
+
"validation": {
|
|
887
|
+
"dependsOn": ["build"],
|
|
888
|
+
"outputs": ["validation-results/**"]
|
|
889
|
+
},
|
|
890
|
+
"lint": {
|
|
891
|
+
"outputs": []
|
|
892
|
+
},
|
|
893
|
+
"type-check": {
|
|
894
|
+
"outputs": []
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
## Updated minimal package strategy
|
|
901
|
+
|
|
902
|
+
### **Phase 1: Minimal Foundation with `axe`**
|
|
903
|
+
```typescript
|
|
904
|
+
// packages/testaro/src/tools/axe.ts
|
|
905
|
+
export class AxeTool implements TestingTool {
|
|
906
|
+
async run(page: Page, options: ToolOptions): Promise<ToolResult> {
|
|
907
|
+
const results = await new AxeBuilder({ page })
|
|
908
|
+
.withTags(options.tags)
|
|
909
|
+
.analyze();
|
|
910
|
+
|
|
911
|
+
return this.standardizeResults(results);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
```
|
|
915
|
+
|
|
916
|
+
### **Phase 2: Validation framework**
|
|
917
|
+
```typescript
|
|
918
|
+
// packages/validation/src/suites/axe-validation.ts
|
|
919
|
+
export class AxeValidationSuite implements ValidationSuite {
|
|
920
|
+
async run(page: Page, options: ValidationOptions): Promise<ValidationResult> {
|
|
921
|
+
// Run axe on known test pages
|
|
922
|
+
// Compare results against expected outcomes
|
|
923
|
+
// Return validation report
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
```
|
|
927
|
+
|
|
928
|
+
### **Phase 3: Cross-tool validation**
|
|
929
|
+
```typescript
|
|
930
|
+
// packages/validation/src/cross-tool-validator.ts
|
|
931
|
+
export class CrossToolValidator {
|
|
932
|
+
async validateDisagreements(results: ToolResult[]): Promise<DisagreementReport> {
|
|
933
|
+
// Identify where tools disagree
|
|
934
|
+
// Collect user judgments
|
|
935
|
+
// Update deprecation rules
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
```
|
|
939
|
+
|
|
940
|
+
## Implementation timeline
|
|
941
|
+
|
|
942
|
+
### **Week 1-2: Minimal package with `axe`**
|
|
943
|
+
- [ ] Set up Turborepo monorepo
|
|
944
|
+
- [ ] Implement `axe` tool with all upgrades
|
|
945
|
+
- [ ] Basic validation framework
|
|
946
|
+
- [ ] Containerization
|
|
947
|
+
|
|
948
|
+
### **Week 3-4: Validation modernization**
|
|
949
|
+
- [ ] Playwright Test integration
|
|
950
|
+
- [ ] Standardized validation interfaces
|
|
951
|
+
- [ ] Cross-tool validation framework
|
|
952
|
+
- [ ] User judgment collection system
|
|
953
|
+
|
|
954
|
+
### **Week 5-6: Tool addition**
|
|
955
|
+
- [ ] Add second tool (e.g., `htmlcs`)
|
|
956
|
+
- [ ] Validate cross-tool patterns
|
|
957
|
+
- [ ] Performance testing
|
|
958
|
+
|
|
959
|
+
### **Week 7-8: UI and Testilo integration**
|
|
960
|
+
- [ ] Basic UI for judgment collection
|
|
961
|
+
- [ ] Testilo integration
|
|
962
|
+
- [ ] Custom rules framework
|
|
963
|
+
|
|
964
|
+
## Key advantages of this approach
|
|
965
|
+
|
|
966
|
+
1. **`axe` as starting point**: Self-contained, mature, well-documented
|
|
967
|
+
2. **Turborepo**: Handles monorepo complexity efficiently
|
|
968
|
+
3. **Modern validation**: Playwright Test provides excellent testing infrastructure
|
|
969
|
+
4. **Scalable architecture**: Patterns established with `axe` apply to all tools
|
|
970
|
+
5. **User-centric**: Maintains the oracle-based approach while modernizing the interface
|
|
971
|
+
|
|
972
|
+
This strategy addresses your concerns about `nuVal`'s limitations while providing a solid foundation for the more complex tools that follow. The validation modernization ensures the project maintains its unique value proposition while adopting modern testing practices.
|
|
973
|
+
|
|
974
|
+
```typescript
|
|
975
|
+
// Core validation interface
|
|
976
|
+
interface ValidationSuite {
|
|
977
|
+
name: string;
|
|
978
|
+
version: string;
|
|
979
|
+
run(page: Page, options: ValidationOptions): Promise<ValidationResult>;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// Tool-specific validation
|
|
983
|
+
interface ToolValidation extends ValidationSuite {
|
|
984
|
+
tool: 'axe' | 'wave' | 'htmlcs' | 'nuVal' | 'wax' | 'alfa' | 'qualWeb' | 'ibm' | 'ed11y' | 'aslint';
|
|
985
|
+
rules: RuleDefinition[];
|
|
986
|
+
}
|
|
987
|
+
```
|
|
988
|
+
|
|
989
|
+
```typescript
|
|
990
|
+
// validation/tests/axe.spec.ts
|
|
991
|
+
import { test, expect } from '@playwright/test';
|
|
992
|
+
import { AxeValidation } from '../packages/core/src/validations/axe';
|
|
993
|
+
|
|
994
|
+
test.describe('Axe Tool Validation', () => {
|
|
995
|
+
test('should detect basic accessibility violations', async ({ page }) => {
|
|
996
|
+
await page.goto('http://localhost:3000/test-pages/basic-violations.html');
|
|
997
|
+
|
|
998
|
+
const validation = new AxeValidation();
|
|
999
|
+
const result = await validation.run(page);
|
|
1000
|
+
|
|
1001
|
+
expect(result.violations).toHaveLength(2);
|
|
1002
|
+
expect(result.violations[0].id).toBe('color-contrast');
|
|
1003
|
+
});
|
|
1004
|
+
});
|
|
1005
|
+
```
|
|
1006
|
+
|
|
1007
|
+
```typescript
|
|
1008
|
+
// validation/tests/cross-tool.spec.ts
|
|
1009
|
+
test.describe('Cross-Tool Validation', () => {
|
|
1010
|
+
test('should identify tool disagreements', async ({ page }) => {
|
|
1011
|
+
const results = await Promise.all([
|
|
1012
|
+
axeValidation.run(page),
|
|
1013
|
+
waveValidation.run(page),
|
|
1014
|
+
htmlcsValidation.run(page)
|
|
1015
|
+
]);
|
|
1016
|
+
|
|
1017
|
+
const disagreements = findDisagreements(results);
|
|
1018
|
+
expect(disagreements).toBeDefined();
|
|
1019
|
+
expect(disagreements.length).toBeGreaterThan(0);
|
|
1020
|
+
});
|
|
1021
|
+
});
|
|
1022
|
+
```
|
|
1023
|
+
|
|
1024
|
+
```typescript
|
|
1025
|
+
// packages/ui/src/components/ValidationReview.tsx
|
|
1026
|
+
interface ValidationReview {
|
|
1027
|
+
testId: string;
|
|
1028
|
+
toolResults: ToolResult[];
|
|
1029
|
+
userJudgment: 'correct' | 'incorrect' | 'unclear';
|
|
1030
|
+
reasoning: string;
|
|
1031
|
+
}
|
|
1032
|
+
```
|
|
1033
|
+
|
|
1034
|
+
```plaintext
|
|
1035
|
+
testaro-monorepo/
|
|
1036
|
+
├── turbo.json
|
|
1037
|
+
├── pnpm-workspace.yaml
|
|
1038
|
+
├── packages/
|
|
1039
|
+
│ ├── core/ # Shared types, utilities
|
|
1040
|
+
│ ├── testaro/ # Main testing engine
|
|
1041
|
+
│ ├── testilo/ # Report processing
|
|
1042
|
+
│ ├── ui/ # Web interface
|
|
1043
|
+
│ └── validation/ # Validation framework
|
|
1044
|
+
├── apps/
|
|
1045
|
+
│ ├── cli/ # Command-line interface
|
|
1046
|
+
│ ├── demo/ # Example usage
|
|
1047
|
+
│ └── validation-runner/ # Validation test runner
|
|
1048
|
+
└── tools/
|
|
1049
|
+
└── rule-builder/ # Custom rule creation tool
|
|
1050
|
+
```
|
|
1051
|
+
|
|
1052
|
+
```json
|
|
1053
|
+
{
|
|
1054
|
+
"pipeline": {
|
|
1055
|
+
"build": {
|
|
1056
|
+
"dependsOn": ["^build"],
|
|
1057
|
+
"outputs": ["dist/**"]
|
|
1058
|
+
},
|
|
1059
|
+
"test": {
|
|
1060
|
+
"dependsOn": ["build"],
|
|
1061
|
+
"outputs": ["coverage/**"]
|
|
1062
|
+
},
|
|
1063
|
+
"validation": {
|
|
1064
|
+
"dependsOn": ["build"],
|
|
1065
|
+
"outputs": ["validation-results/**"]
|
|
1066
|
+
},
|
|
1067
|
+
"lint": {
|
|
1068
|
+
"outputs": []
|
|
1069
|
+
},
|
|
1070
|
+
"type-check": {
|
|
1071
|
+
"outputs": []
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
```
|
|
1076
|
+
|
|
1077
|
+
```typescript
|
|
1078
|
+
// packages/testaro/src/tools/axe.ts
|
|
1079
|
+
export class AxeTool implements TestingTool {
|
|
1080
|
+
async run(page: Page, options: ToolOptions): Promise<ToolResult> {
|
|
1081
|
+
const results = await new AxeBuilder({ page })
|
|
1082
|
+
.withTags(options.tags)
|
|
1083
|
+
.analyze();
|
|
1084
|
+
|
|
1085
|
+
return this.standardizeResults(results);
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
```
|
|
1089
|
+
|
|
1090
|
+
```typescript
|
|
1091
|
+
// packages/validation/src/suites/axe-validation.ts
|
|
1092
|
+
export class AxeValidationSuite implements ValidationSuite {
|
|
1093
|
+
async run(page: Page, options: ValidationOptions): Promise<ValidationResult> {
|
|
1094
|
+
// Run axe on known test pages
|
|
1095
|
+
// Compare results against expected outcomes
|
|
1096
|
+
// Return validation report
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
```
|
|
1100
|
+
|
|
1101
|
+
```typescript
|
|
1102
|
+
// packages/validation/src/cross-tool-validator.ts
|
|
1103
|
+
export class CrossToolValidator {
|
|
1104
|
+
async validateDisagreements(results: ToolResult[]): Promise<DisagreementReport> {
|
|
1105
|
+
// Identify where tools disagree
|
|
1106
|
+
// Collect user judgments
|
|
1107
|
+
// Update deprecation rules
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
```
|
|
1111
|
+
|
|
1112
|
+
---
|
|
1113
|
+
|
|
1114
|
+
**User**
|
|
1115
|
+
|
|
1116
|
+
But Axe is probably not the most antiquated tool. I would expect ASLint and HTML CodeSniffer to be the most antiquated. Alfa, Axe, Editoria11y, IBM Equal Access, and QualWeb are all currently being actively maintained. I have no intuition as to which of those might pose upgrade problems, but inspection could reveal that.
|
|
1117
|
+
|
|
1118
|
+
---
|
|
1119
|
+
|
|
1120
|
+
**Cursor**
|
|
1121
|
+
|
|
1122
|
+
You're absolutely right! Let me analyze the tools by their maintenance status and potential upgrade challenges.
|
|
1123
|
+
|
|
1124
|
+
|
|
1125
|
+
Perfect! Now I can see the implementation details. You're absolutely correct about the maintenance status and potential upgrade challenges. Let me analyze the tools by their implementation patterns and maintenance status:
|
|
1126
|
+
|
|
1127
|
+
## Tool Analysis by Maintenance Status & Upgrade Challenges
|
|
1128
|
+
|
|
1129
|
+
### **Most Antiquated (Best for initial minimal package):**
|
|
1130
|
+
|
|
1131
|
+
#### **1. HTML CodeSniffer (`htmlcs`) - RECOMMENDED**
|
|
1132
|
+
- **Maintenance**: Squiz Labs, appears less actively maintained
|
|
1133
|
+
- **Implementation**: Pure JavaScript, self-contained, reads from local file
|
|
1134
|
+
- **Upgrade challenges**:
|
|
1135
|
+
- Uses `fs.readFile()` to load script from local file
|
|
1136
|
+
- Injects script into page DOM
|
|
1137
|
+
- Uses global `window.HTMLCS_RUNNER` API
|
|
1138
|
+
- String-based result parsing
|
|
1139
|
+
- **Why it's ideal**: Simple, self-contained, no external dependencies, clear patterns
|
|
1140
|
+
|
|
1141
|
+
#### **2. ASLint (`aslint`) - SECOND CHOICE**
|
|
1142
|
+
- **Maintenance**: eSSENTIAL Accessibility, moderate maintenance
|
|
1143
|
+
- **Implementation**: More complex, uses bundled script from `node_modules`
|
|
1144
|
+
- **Upgrade challenges**:
|
|
1145
|
+
- Reads from `node_modules/aslint-testaro/aslint.bundle.js`
|
|
1146
|
+
- Complex script injection with nonce handling
|
|
1147
|
+
- Waits for DOM element attachment
|
|
1148
|
+
- JSON result parsing
|
|
1149
|
+
- **Why it's good**: More modern patterns, but still self-contained
|
|
1150
|
+
|
|
1151
|
+
### **Actively Maintained (Higher upgrade risk):**
|
|
1152
|
+
|
|
1153
|
+
#### **3. Axe (`axe`)**
|
|
1154
|
+
- **Maintenance**: Deque, very active
|
|
1155
|
+
- **Implementation**: Uses `axe-playwright` package
|
|
1156
|
+
- **Upgrade challenges**: Modern package, frequent updates, complex API
|
|
1157
|
+
|
|
1158
|
+
#### **4. Alfa (`alfa`)**
|
|
1159
|
+
- **Maintenance**: Siteimprove, very active
|
|
1160
|
+
- **Implementation**: Uses `@siteimprove/alfa-*` packages
|
|
1161
|
+
- **Upgrade challenges**: Modern TypeScript packages, complex API
|
|
1162
|
+
|
|
1163
|
+
#### **5. QualWeb (`qualWeb`)**
|
|
1164
|
+
- **Maintenance**: University of Lisbon, active
|
|
1165
|
+
- **Implementation**: Uses `@qualweb/*` packages
|
|
1166
|
+
- **Upgrade challenges**: Modern packages, complex configuration
|
|
1167
|
+
|
|
1168
|
+
## **Recommended Strategy: Start with HTML CodeSniffer**
|
|
1169
|
+
|
|
1170
|
+
### **Why HTML CodeSniffer is perfect for the minimal package:**
|
|
1171
|
+
|
|
1172
|
+
1. **Simple implementation pattern**:
|
|
1173
|
+
```typescript
|
|
1174
|
+
// Current pattern (easy to modernize)
|
|
1175
|
+
const scriptText = await fs.readFile(`${__dirname}/../htmlcs/HTMLCS.js`, 'utf8');
|
|
1176
|
+
const issues = await page.evaluate((scriptText, scriptNonce) => {
|
|
1177
|
+
// Inject and run HTMLCS
|
|
1178
|
+
}, scriptText, scriptNonce);
|
|
1179
|
+
```
|
|
1180
|
+
|
|
1181
|
+
2. **Self-contained**: No external package dependencies
|
|
1182
|
+
3. **Clear upgrade path**: Easy to convert to ES modules and TypeScript
|
|
1183
|
+
4. **Established patterns**: The script injection pattern will work for other tools
|
|
1184
|
+
5. **Minimal complexity**: String parsing is straightforward to type
|
|
1185
|
+
|
|
1186
|
+
### **Implementation plan for HTML CodeSniffer:**
|
|
1187
|
+
|
|
1188
|
+
#### **Phase 1: Minimal HTML CodeSniffer package**
|
|
1189
|
+
```typescript
|
|
1190
|
+
// packages/testaro/src/tools/htmlcs.ts
|
|
1191
|
+
export class HTMLCodeSnifferTool implements TestingTool {
|
|
1192
|
+
async run(page: Page, options: ToolOptions): Promise<ToolResult> {
|
|
1193
|
+
const scriptText = await fs.readFile(
|
|
1194
|
+
new URL('../htmlcs/HTMLCS.js', import.meta.url),
|
|
1195
|
+
'utf8'
|
|
1196
|
+
);
|
|
1197
|
+
|
|
1198
|
+
const issues = await page.evaluate(
|
|
1199
|
+
(scriptText, scriptNonce, rules) => {
|
|
1200
|
+
// Modern ES module version of current logic
|
|
1201
|
+
},
|
|
1202
|
+
scriptText,
|
|
1203
|
+
options.scriptNonce,
|
|
1204
|
+
options.rules
|
|
1205
|
+
);
|
|
1206
|
+
|
|
1207
|
+
return this.standardizeResults(issues);
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
```
|
|
1211
|
+
|
|
1212
|
+
#### **Phase 2: Validation framework**
|
|
1213
|
+
```typescript
|
|
1214
|
+
// packages/validation/src/suites/htmlcs-validation.ts
|
|
1215
|
+
export class HTMLCodeSnifferValidationSuite implements ValidationSuite {
|
|
1216
|
+
async run(page: Page, options: ValidationOptions): Promise<ValidationResult> {
|
|
1217
|
+
// Test HTML CodeSniffer on known test pages
|
|
1218
|
+
// Validate rule detection accuracy
|
|
1219
|
+
// Check result standardization
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
```
|
|
1223
|
+
|
|
1224
|
+
### **Why this approach works:**
|
|
1225
|
+
|
|
1226
|
+
1. **Proves architecture**: HTML CodeSniffer will validate all upgrade patterns
|
|
1227
|
+
2. **Simple debugging**: String-based results are easy to troubleshoot
|
|
1228
|
+
3. **Clear patterns**: Script injection pattern applies to other tools
|
|
1229
|
+
4. **Minimal risk**: Self-contained tool reduces external dependencies
|
|
1230
|
+
5. **Learning curve**: Team can master patterns with simple tool first
|
|
1231
|
+
|
|
1232
|
+
### **Tool addition order after HTML CodeSniffer:**
|
|
1233
|
+
|
|
1234
|
+
1. **ASLint** (similar complexity, bundled script pattern)
|
|
1235
|
+
2. **Axe** (modern package, different patterns)
|
|
1236
|
+
3. **Alfa** (complex TypeScript packages)
|
|
1237
|
+
4. **QualWeb** (most complex, modern packages)
|
|
1238
|
+
5. **Testaro rules** (custom rules framework)
|
|
1239
|
+
|
|
1240
|
+
### **Key advantages of starting with HTML CodeSniffer:**
|
|
1241
|
+
|
|
1242
|
+
- **No external package dependencies** to manage during upgrades
|
|
1243
|
+
- **Simple string parsing** that's easy to type with TypeScript
|
|
1244
|
+
- **Clear script injection pattern** that applies to other tools
|
|
1245
|
+
- **Self-contained tool** that won't break during monorepo setup
|
|
1246
|
+
- **Established patterns** that can be replicated for other tools
|
|
1247
|
+
|
|
1248
|
+
This approach gives you the most antiquated tool (as requested) while providing a solid foundation for all the planned upgrades. The patterns established with HTML CodeSniffer will directly apply to the more complex tools that follow.
|
|
1249
|
+
|
|
1250
|
+
```typescript
|
|
1251
|
+
// Current pattern (easy to modernize)
|
|
1252
|
+
const scriptText = await fs.readFile(`${__dirname}/../htmlcs/HTMLCS.js`, 'utf8');
|
|
1253
|
+
const issues = await page.evaluate((scriptText, scriptNonce) => {
|
|
1254
|
+
// Inject and run HTMLCS
|
|
1255
|
+
}, scriptText, scriptNonce);
|
|
1256
|
+
```
|
|
1257
|
+
|
|
1258
|
+
```typescript
|
|
1259
|
+
// packages/testaro/src/tools/htmlcs.ts
|
|
1260
|
+
export class HTMLCodeSnifferTool implements TestingTool {
|
|
1261
|
+
async run(page: Page, options: ToolOptions): Promise<ToolResult> {
|
|
1262
|
+
const scriptText = await fs.readFile(
|
|
1263
|
+
new URL('../htmlcs/HTMLCS.js', import.meta.url),
|
|
1264
|
+
'utf8'
|
|
1265
|
+
);
|
|
1266
|
+
|
|
1267
|
+
const issues = await page.evaluate(
|
|
1268
|
+
(scriptText, scriptNonce, rules) => {
|
|
1269
|
+
// Modern ES module version of current logic
|
|
1270
|
+
},
|
|
1271
|
+
scriptText,
|
|
1272
|
+
options.scriptNonce,
|
|
1273
|
+
options.rules
|
|
1274
|
+
);
|
|
1275
|
+
|
|
1276
|
+
return this.standardizeResults(issues);
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
```
|
|
1280
|
+
|
|
1281
|
+
```typescript
|
|
1282
|
+
// packages/validation/src/suites/htmlcs-validation.ts
|
|
1283
|
+
export class HTMLCodeSnifferValidationSuite implements ValidationSuite {
|
|
1284
|
+
async run(page: Page, options: ValidationOptions): Promise<ValidationResult> {
|
|
1285
|
+
// Test HTML CodeSniffer on known test pages
|
|
1286
|
+
// Validate rule detection accuracy
|
|
1287
|
+
// Check result standardization
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
```
|
|
1291
|
+
|
|
1292
|
+
---
|
|
1293
|
+
|
|
1294
|
+
**User**
|
|
1295
|
+
|
|
1296
|
+
The purpose of starting with an antiquated tool was to maximize the risk of unmodernizability, but your advice is now advocating this tactic because of its ease, rather than because of its difficulty. We should be clear about the considerations that motivate our decisions.
|
|
1297
|
+
|
|
1298
|
+
---
|
|
1299
|
+
|
|
1300
|
+
**Cursor**
|
|
1301
|
+
|
|
1302
|
+
You're absolutely right, and I apologize for the confusion. Let me clarify the actual considerations that should motivate our decisions.
|
|
1303
|
+
|
|
1304
|
+
## The Real Considerations
|
|
1305
|
+
|
|
1306
|
+
### **Primary Goal: Maximize Upgrade Risk Detection**
|
|
1307
|
+
The purpose of starting with an antiquated tool is to **stress-test the architecture** by encountering the most challenging upgrade scenarios early. We want to discover what breaks, what's incompatible, and what requires significant rework.
|
|
1308
|
+
|
|
1309
|
+
### **Secondary Goal: Establish Robust Patterns**
|
|
1310
|
+
Once we've proven the architecture can handle the most difficult cases, we can confidently apply those patterns to easier tools.
|
|
1311
|
+
|
|
1312
|
+
## Re-evaluating Tool Selection by Upgrade Difficulty
|
|
1313
|
+
|
|
1314
|
+
### **Most Challenging (Highest Risk) - RECOMMENDED:**
|
|
1315
|
+
|
|
1316
|
+
#### **1. ASLint (`aslint`) - HIGHEST RISK**
|
|
1317
|
+
- **Why it's the most challenging**:
|
|
1318
|
+
- **Complex dependency chain**: Uses `aslint-testaro` package with bundled script
|
|
1319
|
+
- **Script injection complexity**: Multiple script elements, nonce handling, DOM waiting
|
|
1320
|
+
- **Modern package management**: Depends on `node_modules` structure
|
|
1321
|
+
- **Error handling**: Complex timeout and attachment logic
|
|
1322
|
+
- **JSON parsing**: Structured result processing
|
|
1323
|
+
- **Upgrade challenges**:
|
|
1324
|
+
- **ES modules**: `node_modules` path resolution changes
|
|
1325
|
+
- **TypeScript**: Complex script injection typing
|
|
1326
|
+
- **Containerization**: File system access patterns
|
|
1327
|
+
- **Monorepo**: Package dependency management
|
|
1328
|
+
- **Playwright Test**: Async waiting patterns
|
|
1329
|
+
|
|
1330
|
+
#### **2. HTML CodeSniffer (`htmlcs`) - MEDIUM RISK**
|
|
1331
|
+
- **Why it's moderately challenging**:
|
|
1332
|
+
- **File system access**: `fs.readFile()` for script loading
|
|
1333
|
+
- **Global variable usage**: `window.HTMLCS_RUNNER` API
|
|
1334
|
+
- **String parsing**: Complex result processing
|
|
1335
|
+
- **Upgrade challenges**:
|
|
1336
|
+
- **ES modules**: `__dirname` replacement
|
|
1337
|
+
- **TypeScript**: String parsing typing
|
|
1338
|
+
- **Containerization**: File path resolution
|
|
1339
|
+
|
|
1340
|
+
### **Least Challenging (Lowest Risk):**
|
|
1341
|
+
|
|
1342
|
+
#### **3. Axe (`axe`) - LOWEST RISK**
|
|
1343
|
+
- **Why it's easiest**:
|
|
1344
|
+
- **Modern package**: `axe-playwright` with TypeScript support
|
|
1345
|
+
- **Clean API**: Well-documented, modern patterns
|
|
1346
|
+
- **Active maintenance**: Regular updates, good documentation
|
|
1347
|
+
- **Upgrade challenges**: Minimal, mostly configuration
|
|
1348
|
+
|
|
1349
|
+
## **Recommended Strategy: Start with ASLint**
|
|
1350
|
+
|
|
1351
|
+
### **Why ASLint is the right choice for stress-testing:**
|
|
1352
|
+
|
|
1353
|
+
1. **Maximum complexity**: Most challenging upgrade scenarios
|
|
1354
|
+
2. **Multiple failure points**: Script injection, file system, async waiting, JSON parsing
|
|
1355
|
+
3. **Modern package dependencies**: Tests monorepo package management
|
|
1356
|
+
4. **Containerization challenges**: File system access patterns
|
|
1357
|
+
5. **TypeScript complexity**: Complex typing for script injection and results
|
|
1358
|
+
|
|
1359
|
+
### **What we'll learn from ASLint:**
|
|
1360
|
+
|
|
1361
|
+
#### **Module System Challenges:**
|
|
1362
|
+
- How to handle `node_modules` paths in ES modules
|
|
1363
|
+
- Script injection with nonce handling
|
|
1364
|
+
- File system access patterns
|
|
1365
|
+
|
|
1366
|
+
#### **TypeScript Challenges:**
|
|
1367
|
+
- Typing complex script injection
|
|
1368
|
+
- Result parsing and validation
|
|
1369
|
+
- Error handling patterns
|
|
1370
|
+
|
|
1371
|
+
#### **Containerization Challenges:**
|
|
1372
|
+
- File system access in containers
|
|
1373
|
+
- Script loading and execution
|
|
1374
|
+
- Timeout and waiting patterns
|
|
1375
|
+
|
|
1376
|
+
#### **Monorepo Challenges:**
|
|
1377
|
+
- Package dependency management
|
|
1378
|
+
- Cross-package file access
|
|
1379
|
+
- Build and deployment patterns
|
|
1380
|
+
|
|
1381
|
+
### **Implementation approach:**
|
|
1382
|
+
|
|
1383
|
+
#### **Phase 1: Stress-test with ASLint**
|
|
1384
|
+
```typescript
|
|
1385
|
+
// This will be HARD - that's the point
|
|
1386
|
+
export class ASLintTool implements TestingTool {
|
|
1387
|
+
async run(page: Page, options: ToolOptions): Promise<ToolResult> {
|
|
1388
|
+
// Challenge 1: ES module file system access
|
|
1389
|
+
const aslintRunner = await fs.readFile(
|
|
1390
|
+
new URL('../procs/aslint.js', import.meta.url),
|
|
1391
|
+
'utf8'
|
|
1392
|
+
);
|
|
1393
|
+
|
|
1394
|
+
// Challenge 2: Monorepo package resolution
|
|
1395
|
+
const aslintBundle = await fs.readFile(
|
|
1396
|
+
new URL('../node_modules/aslint-testaro/aslint.bundle.js', import.meta.url),
|
|
1397
|
+
'utf8'
|
|
1398
|
+
);
|
|
1399
|
+
|
|
1400
|
+
// Challenge 3: Complex script injection with typing
|
|
1401
|
+
await page.evaluate(
|
|
1402
|
+
(args: ScriptInjectionArgs) => {
|
|
1403
|
+
// Complex script injection logic
|
|
1404
|
+
},
|
|
1405
|
+
{ scriptNonce: options.scriptNonce, aslintBundle, aslintRunner }
|
|
1406
|
+
);
|
|
1407
|
+
|
|
1408
|
+
// Challenge 4: Async waiting with timeout
|
|
1409
|
+
const reportLoc = page.locator('#aslintResult');
|
|
1410
|
+
await reportLoc.waitFor({
|
|
1411
|
+
state: 'attached',
|
|
1412
|
+
timeout: 1000 * options.timeLimit
|
|
1413
|
+
});
|
|
1414
|
+
|
|
1415
|
+
// Challenge 5: Complex result parsing
|
|
1416
|
+
const actReport = await reportLoc.textContent();
|
|
1417
|
+
const result = JSON.parse(actReport);
|
|
1418
|
+
|
|
1419
|
+
return this.standardizeResults(result);
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
```
|
|
1423
|
+
|
|
1424
|
+
#### **Phase 2: Apply lessons to easier tools**
|
|
1425
|
+
Once we've solved ASLint's challenges, HTML CodeSniffer and Axe will be straightforward.
|
|
1426
|
+
|
|
1427
|
+
### **Success criteria for ASLint stress-test:**
|
|
1428
|
+
|
|
1429
|
+
- [ ] **ES modules**: File system access works with `import.meta.url`
|
|
1430
|
+
- [ ] **TypeScript**: Complex script injection is properly typed
|
|
1431
|
+
- [ ] **Containerization**: Script loading works in containers
|
|
1432
|
+
- [ ] **Monorepo**: Package dependencies resolve correctly
|
|
1433
|
+
- [ ] **Playwright Test**: Async waiting patterns work
|
|
1434
|
+
- [ ] **Error handling**: Robust error handling for all failure points
|
|
1435
|
+
|
|
1436
|
+
### **Why this approach is correct:**
|
|
1437
|
+
|
|
1438
|
+
1. **Risk mitigation**: Discover problems early when scope is small
|
|
1439
|
+
2. **Pattern establishment**: Solve the hardest problems first
|
|
1440
|
+
3. **Confidence building**: Prove the architecture can handle anything
|
|
1441
|
+
4. **Learning**: Team masters complex patterns early
|
|
1442
|
+
5. **Efficiency**: Easier tools become trivial after solving hard ones
|
|
1443
|
+
|
|
1444
|
+
### **Timeline expectations:**
|
|
1445
|
+
|
|
1446
|
+
- **ASLint**: 3-4 weeks (stress-testing phase)
|
|
1447
|
+
- **HTML CodeSniffer**: 1 week (apply established patterns)
|
|
1448
|
+
- **Axe**: 1 week (modern package, easy patterns)
|
|
1449
|
+
- **Remaining tools**: 1-2 weeks each (established patterns)
|
|
1450
|
+
|
|
1451
|
+
This approach ensures we encounter and solve the most challenging upgrade scenarios early, making the entire project more robust and efficient.
|
|
1452
|
+
|
|
1453
|
+
```typescript
|
|
1454
|
+
// This will be HARD - that's the point
|
|
1455
|
+
export class ASLintTool implements TestingTool {
|
|
1456
|
+
async run(page: Page, options: ToolOptions): Promise<ToolResult> {
|
|
1457
|
+
// Challenge 1: ES module file system access
|
|
1458
|
+
const aslintRunner = await fs.readFile(
|
|
1459
|
+
new URL('../procs/aslint.js', import.meta.url),
|
|
1460
|
+
'utf8'
|
|
1461
|
+
);
|
|
1462
|
+
|
|
1463
|
+
// Challenge 2: Monorepo package resolution
|
|
1464
|
+
const aslintBundle = await fs.readFile(
|
|
1465
|
+
new URL('../node_modules/aslint-testaro/aslint.bundle.js', import.meta.url),
|
|
1466
|
+
'utf8'
|
|
1467
|
+
);
|
|
1468
|
+
|
|
1469
|
+
// Challenge 3: Complex script injection with typing
|
|
1470
|
+
await page.evaluate(
|
|
1471
|
+
(args: ScriptInjectionArgs) => {
|
|
1472
|
+
// Complex script injection logic
|
|
1473
|
+
},
|
|
1474
|
+
{ scriptNonce: options.scriptNonce, aslintBundle, aslintRunner }
|
|
1475
|
+
);
|
|
1476
|
+
|
|
1477
|
+
// Challenge 4: Async waiting with timeout
|
|
1478
|
+
const reportLoc = page.locator('#aslintResult');
|
|
1479
|
+
await reportLoc.waitFor({
|
|
1480
|
+
state: 'attached',
|
|
1481
|
+
timeout: 1000 * options.timeLimit
|
|
1482
|
+
});
|
|
1483
|
+
|
|
1484
|
+
// Challenge 5: Complex result parsing
|
|
1485
|
+
const actReport = await reportLoc.textContent();
|
|
1486
|
+
const result = JSON.parse(actReport);
|
|
1487
|
+
|
|
1488
|
+
return this.standardizeResults(result);
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
```
|
|
1492
|
+
|
|
1493
|
+
/*
|
|
1494
|
+
© 2021–2025 CVS Health and/or one of its affiliates. All rights reserved.
|
|
1495
|
+
|
|
1496
|
+
MIT License
|
|
1497
|
+
|
|
1498
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
1499
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
1500
|
+
in the Software without restriction, including without limitation the rights
|
|
1501
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
1502
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
1503
|
+
furnished to do so, subject to the following conditions:
|
|
1504
|
+
|
|
1505
|
+
The above copyright notice and this permission notice shall be included in all
|
|
1506
|
+
copies or substantial portions of the Software.
|
|
1507
|
+
|
|
1508
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
1509
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
1510
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
1511
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
1512
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
1513
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1514
|
+
SOFTWARE.
|
|
1515
|
+
*/
|