@warlock.js/core 5.35.0 → 5.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/esm/cli/commands/migrate.command.mjs +10 -0
- package/esm/cli/commands/migrate.command.mjs.map +1 -1
- package/esm/cli/commands/release/release-command.action.mjs +245 -0
- package/esm/cli/commands/release/release-command.action.mjs.map +1 -0
- package/esm/cli/commands/release.command.mjs +66 -0
- package/esm/cli/commands/release.command.mjs.map +1 -0
- package/esm/cli/framework-cli-commands.mjs +2 -0
- package/esm/cli/framework-cli-commands.mjs.map +1 -1
- package/esm/database/migrate-action.mjs +24 -2
- package/esm/database/migrate-action.mjs.map +1 -1
- package/esm/dev-server/loader/load-hook.d.mts.map +1 -1
- package/esm/dev-server/loader/load-hook.mjs +6 -0
- package/esm/dev-server/loader/load-hook.mjs.map +1 -1
- package/esm/dev-server/module-loader.mjs +1 -1
- package/esm/dev-server/parse-imports.mjs +1 -1
- package/esm/dev-server/type-generator.mjs +1 -1
- package/esm/e2e/cdp.d.mts.map +1 -1
- package/esm/e2e/cdp.mjs +9 -2
- package/esm/e2e/cdp.mjs.map +1 -1
- package/esm/e2e/page.d.mts +9 -1
- package/esm/e2e/page.d.mts.map +1 -1
- package/esm/e2e/page.mjs +45 -7
- package/esm/e2e/page.mjs.map +1 -1
- package/esm/e2e/types.d.mts +18 -0
- package/esm/e2e/types.d.mts.map +1 -1
- package/esm/e2e/types.mjs.map +1 -1
- package/esm/errors/error-codes.d.mts +24 -0
- package/esm/errors/error-codes.d.mts.map +1 -1
- package/esm/errors/error-codes.mjs +24 -0
- package/esm/errors/error-codes.mjs.map +1 -1
- package/esm/generations/features/test.feature.mjs +7 -7
- package/esm/generations/features/test.feature.mjs.map +1 -1
- package/esm/generations/features/web.feature.mjs +3 -3
- package/esm/generations/features/web.feature.mjs.map +1 -1
- package/esm/index.d.mts +6 -3
- package/esm/index.mjs +4 -2
- package/esm/localization/index.mjs +3 -1
- package/esm/localization/translation-usage-graph.d.mts +49 -0
- package/esm/localization/translation-usage-graph.d.mts.map +1 -0
- package/esm/localization/translation-usage-graph.mjs +128 -0
- package/esm/localization/translation-usage-graph.mjs.map +1 -0
- package/esm/localization/translation-usage.d.mts +85 -0
- package/esm/localization/translation-usage.d.mts.map +1 -0
- package/esm/localization/translation-usage.mjs +307 -0
- package/esm/localization/translation-usage.mjs.map +1 -0
- package/esm/production/build-budgets.d.mts +18 -0
- package/esm/production/build-budgets.d.mts.map +1 -1
- package/esm/production/build-budgets.mjs.map +1 -1
- package/esm/production/route-registration-snapshot.mjs +12 -3
- package/esm/production/route-registration-snapshot.mjs.map +1 -1
- package/esm/release/activate.mjs +261 -0
- package/esm/release/activate.mjs.map +1 -0
- package/esm/release/candidate.mjs +107 -0
- package/esm/release/candidate.mjs.map +1 -0
- package/esm/release/cascade-migration-provider.mjs +32 -0
- package/esm/release/cascade-migration-provider.mjs.map +1 -0
- package/esm/release/config.mjs +60 -0
- package/esm/release/config.mjs.map +1 -0
- package/esm/release/gate.mjs +67 -0
- package/esm/release/gate.mjs.map +1 -0
- package/esm/release/migrations-proof.mjs +100 -0
- package/esm/release/migrations-proof.mjs.map +1 -0
- package/esm/release/prune.mjs +42 -0
- package/esm/release/prune.mjs.map +1 -0
- package/esm/release/report.mjs +25 -0
- package/esm/release/report.mjs.map +1 -0
- package/esm/release/runner.mjs +55 -0
- package/esm/release/runner.mjs.map +1 -0
- package/esm/release/semver.mjs +53 -0
- package/esm/release/semver.mjs.map +1 -0
- package/esm/release/stage.mjs +122 -0
- package/esm/release/stage.mjs.map +1 -0
- package/esm/release/store.mjs +131 -0
- package/esm/release/store.mjs.map +1 -0
- package/esm/release/types.d.mts +102 -0
- package/esm/release/types.d.mts.map +1 -0
- package/esm/release/verify.mjs +94 -0
- package/esm/release/verify.mjs.map +1 -0
- package/esm/router/index.d.mts +2 -2
- package/esm/router/index.mjs +2 -2
- package/esm/router/router.d.mts +4 -0
- package/esm/router/router.d.mts.map +1 -1
- package/esm/router/router.mjs +14 -3
- package/esm/router/router.mjs.map +1 -1
- package/esm/router/types.d.mts +45 -0
- package/esm/router/types.d.mts.map +1 -1
- package/esm/router/unguarded-route-diagnostics.d.mts +6 -0
- package/esm/router/unguarded-route-diagnostics.d.mts.map +1 -1
- package/esm/router/unguarded-route-diagnostics.mjs +10 -2
- package/esm/router/unguarded-route-diagnostics.mjs.map +1 -1
- package/esm/tooling/check/api-route-references.d.mts +16 -0
- package/esm/tooling/check/api-route-references.d.mts.map +1 -0
- package/esm/tooling/check/api-route-references.mjs +146 -0
- package/esm/tooling/check/api-route-references.mjs.map +1 -0
- package/esm/tooling/check/conventions-step.d.mts +6 -3
- package/esm/tooling/check/conventions-step.d.mts.map +1 -1
- package/esm/tooling/check/conventions-step.mjs +19 -10
- package/esm/tooling/check/conventions-step.mjs.map +1 -1
- package/esm/tooling/check/run-check.d.mts.map +1 -1
- package/esm/tooling/check/run-check.mjs +4 -2
- package/esm/tooling/check/run-check.mjs.map +1 -1
- package/esm/tooling/check/security-conventions.mjs +19 -1
- package/esm/tooling/check/security-conventions.mjs.map +1 -1
- package/esm/tooling/check/translation-conventions.mjs +32 -0
- package/esm/tooling/check/translation-conventions.mjs.map +1 -0
- package/esm/tooling/inspect/collect-files.mjs +1 -1
- package/esm/tooling/inspect/collect-routes.mjs +3 -2
- package/esm/tooling/inspect/collect-routes.mjs.map +1 -1
- package/esm/upgrade/codemods/index.mjs +2 -0
- package/esm/upgrade/codemods/index.mjs.map +1 -1
- package/esm/upgrade/codemods/vite-vitest.mjs +170 -0
- package/esm/upgrade/codemods/vite-vitest.mjs.map +1 -0
- package/esm/upgrade/notes.mjs +4 -0
- package/esm/upgrade/notes.mjs.map +1 -1
- package/esm/validation/init.mjs +11 -4
- package/esm/validation/init.mjs.map +1 -1
- package/esm/validation/translate-rule.mjs +63 -0
- package/esm/validation/translate-rule.mjs.map +1 -0
- package/esm/warlock-config/index.d.mts +3 -2
- package/esm/warlock-config/types.d.mts +8 -0
- package/esm/warlock-config/types.d.mts.map +1 -1
- package/llms-full.txt +221 -18
- package/llms.txt +1 -0
- package/package.json +13 -13
- package/skills/deploy-release/SKILL.md +76 -0
- package/skills/index.md +1 -1
- package/skills/register-route/SKILL.md +25 -0
- package/skills/test-service/SKILL.md +8 -8
- package/skills/upgrade-from-5-29/SKILL.md +91 -0
- package/skills/use-localization/SKILL.md +4 -0
- package/skills/warlock-check/SKILL.md +11 -8
- package/skills/warlock-conventions/SKILL.md +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load-hook.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/dev-server/loader/load-hook.ts"],"mappings":";KAMK;EACH;EACA,mBAAmB;;KAGhB;EACH;EACA,iBAAiB;EACjB;;KAGG,YAAY,aAAa,UAAU,gBAAgB,QAAQ;;;;;;YAOpD;;EAEV;;EAEA;;EAEA;;EAEA;;;;;;EAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"load-hook.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/dev-server/loader/load-hook.ts"],"mappings":";KAMK;EACH;EACA,mBAAmB;;KAGhB;EACH;EACA,iBAAiB;EACjB;;KAGG,YAAY,aAAa,UAAU,gBAAgB,QAAQ;;;;;;YAOpD;;EAEV;;EAEA;;EAEA;;EAEA;;;;;;EAMA;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAsDoB,KACpB,aACA,SAAS,aACT,UAAU,WACT,QAAQ"}
|
|
@@ -7,6 +7,7 @@ import { transformSync } from "esbuild";
|
|
|
7
7
|
//#region ../../packages/core/src/dev-server/loader/load-hook.ts
|
|
8
8
|
const VERSION_QUERY = /\?v=\d+$/;
|
|
9
9
|
const TS_FILE = /\.(ts|tsx|mts|cts)$/;
|
|
10
|
+
const STYLESHEET_FILE = /\.(css|scss|sass|less|styl)$/;
|
|
10
11
|
let transpile;
|
|
11
12
|
let cache;
|
|
12
13
|
/**
|
|
@@ -50,6 +51,11 @@ function configureTranspile(init) {
|
|
|
50
51
|
*/
|
|
51
52
|
async function load(url, context, nextLoad) {
|
|
52
53
|
const cleanUrl = url.replace(VERSION_QUERY, "");
|
|
54
|
+
if (STYLESHEET_FILE.test(cleanUrl)) return {
|
|
55
|
+
format: "module",
|
|
56
|
+
source: "export default {};\n",
|
|
57
|
+
shortCircuit: true
|
|
58
|
+
};
|
|
53
59
|
if (!TS_FILE.test(cleanUrl)) return nextLoad(url, context);
|
|
54
60
|
const absolutePath = fileURLToPath(cleanUrl);
|
|
55
61
|
const source = readFileSync(absolutePath, "utf8");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load-hook.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/dev-server/loader/load-hook.ts"],"sourcesContent":["import { transformSync } from \"esbuild\";\nimport { readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { sourceSlug } from \"./source-slug.js\";\nimport { cacheKey, TranspileCache } from \"./transpile-cache.js\";\n\ntype LoadContext = {\n format?: string;\n importAttributes?: Record<string, string>;\n};\n\ntype LoadResult = {\n format: string;\n source: string | Buffer;\n shortCircuit?: boolean;\n};\n\ntype NextLoad = (url: string, context?: LoadContext) => Promise<LoadResult>;\n\n/**\n * Everything the transpile path needs, computed once on the main thread and\n * shipped into the hook worker via `initialize()`. Always present — esbuild\n * transpile is unconditional now (tsx is no longer in the TS path).\n */\nexport type TranspileInit = {\n /** Absolute `.warlock/transpile` directory. */\n cacheDir: string;\n /** Source-content key salt: esbuild version + epoch + tsconfig blob. */\n fingerprint: string;\n /** esbuild `target` (e.g. `\"node22\"` — must match the prod builder). */\n target: string;\n /** JSON string of `{ compilerOptions }` handed to esbuild as tsconfigRaw. */\n tsconfigRaw: string;\n /**\n * Debug-only: name cache files `<slug>.<hash>.js` and append a trailing\n * `// @source <path>` marker so entries are eyeball-identifiable. Off by\n * default (opaque `<hash>.js`). Cosmetic — never affects keys or lookup.\n */\n debugNames: boolean;\n};\n\nconst VERSION_QUERY = /\\?v=\\d+$/;\nconst TS_FILE = /\\.(ts|tsx|mts|cts)$/;\n\nlet transpile: TranspileInit;\nlet cache: TranspileCache;\n\n/**\n * Called once from the hook worker's `initialize()`. Wires the persisted\n * transpile cache and runs one opportunistic GC pass at boot — cheap, off\n * the hot path, single directory scan.\n */\nexport function configureTranspile(init: TranspileInit): void {\n transpile = init;\n cache = new TranspileCache(init.cacheDir);\n\n // Boot-time eviction so the cache can't grow unbounded across weeks of\n // dev. Bounds are generous; correctness never depends on GC (content\n // hashing already guarantees that) — this is purely disk hygiene.\n cache.gc({\n maxBytes: 256 * 1024 * 1024,\n maxAgeMs: 14 * 24 * 60 * 60 * 1000,\n });\n}\n\n/**\n * ESM loader `load()` hook.\n *\n * Owns the transpile for **every** TypeScript file — project `src/`,\n * `@warlock.js/*` framework source, and `warlock.config.ts` alike. There\n * is no tsx in the TypeScript path any more: we read the source, key it by\n * a content hash + options fingerprint, serve the cached JS on a hit, and\n * otherwise transform it with esbuild directly and persist. Non-TypeScript\n * URLs (npm `.js`/`.cjs`/`.mjs`, `node:` builtins, JSON) are not ours —\n * they fall through to the next loader (Node's default).\n *\n * The `?v=<N>` query drives Node's module identity (HMR) for `src/` files\n * and is **never** part of the cache key — the cache is keyed purely by\n * source content, so the two mechanisms are fully orthogonal. Framework\n * and config `.ts` carry no `?v` (no HMR) but are transpiled and cached\n * exactly the same way.\n *\n * The source map esbuild emits is inline base64 with `sourcefile` set to\n * the clean absolute `.ts` path, so V8 (run with source maps enabled)\n * reports stack frames at the original TypeScript location.\n *\n * @example\n * // load(\"file:///src/user.model.ts?v=3\") → esbuild transpile + cache\n * // load(\"file:///@warlock.js/core/src/x.ts\") → esbuild transpile + cache\n * // load(\"file:///node_modules/ms/index.js\") → nextLoad (Node default)\n */\nexport async function load(\n url: string,\n context: LoadContext,\n nextLoad: NextLoad,\n): Promise<LoadResult> {\n const cleanUrl = url.replace(VERSION_QUERY, \"\");\n\n // Not TypeScript → not ours. npm packages, node: builtins, JSON, etc.\n if (!TS_FILE.test(cleanUrl)) {\n return nextLoad(url, context);\n }\n\n const absolutePath = fileURLToPath(cleanUrl);\n const source = readFileSync(absolutePath, \"utf8\");\n const key = cacheKey(source, transpile.fingerprint);\n\n // Cosmetic filename label; undefined keeps opaque <hash>.js names.\n const label = transpile.debugNames ? sourceSlug(absolutePath) : undefined;\n\n const hit = cache.get(key, label);\n if (hit) {\n return { format: \"module\", source: hit.code, shortCircuit: true };\n }\n\n const loader = absolutePath.endsWith(\".tsx\") ? \"tsx\" : \"ts\";\n\n const result = transformSync(source, {\n loader,\n format: \"esm\",\n target: transpile.target,\n sourcefile: absolutePath,\n // Inline base64 map, self-contained (sourcesContent on by default), so\n // it survives the ?v=N URL with no extra resolution step.\n sourcemap: \"inline\",\n tsconfigRaw: transpile.tsconfigRaw,\n });\n\n // result.code already carries the inline //# sourceMappingURL. The\n // marker goes AFTER that line: a trailing comment can't shift earlier\n // generated lines, so the inline map (and therefore stack-frame line\n // numbers) stays exact. A leading marker would desync it by one line.\n const code = label ? `${result.code}\\n// @source ${absolutePath}\\n` : result.code;\n\n cache.put(key, { code, map: \"\" }, label);\n\n return { format: \"module\", source: code, shortCircuit: true };\n}\n"],"mappings":";;;;;;;AAyCA,MAAM,gBAAgB;AACtB,MAAM,UAAU;
|
|
1
|
+
{"version":3,"file":"load-hook.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/dev-server/loader/load-hook.ts"],"sourcesContent":["import { transformSync } from \"esbuild\";\nimport { readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { sourceSlug } from \"./source-slug.js\";\nimport { cacheKey, TranspileCache } from \"./transpile-cache.js\";\n\ntype LoadContext = {\n format?: string;\n importAttributes?: Record<string, string>;\n};\n\ntype LoadResult = {\n format: string;\n source: string | Buffer;\n shortCircuit?: boolean;\n};\n\ntype NextLoad = (url: string, context?: LoadContext) => Promise<LoadResult>;\n\n/**\n * Everything the transpile path needs, computed once on the main thread and\n * shipped into the hook worker via `initialize()`. Always present — esbuild\n * transpile is unconditional now (tsx is no longer in the TS path).\n */\nexport type TranspileInit = {\n /** Absolute `.warlock/transpile` directory. */\n cacheDir: string;\n /** Source-content key salt: esbuild version + epoch + tsconfig blob. */\n fingerprint: string;\n /** esbuild `target` (e.g. `\"node22\"` — must match the prod builder). */\n target: string;\n /** JSON string of `{ compilerOptions }` handed to esbuild as tsconfigRaw. */\n tsconfigRaw: string;\n /**\n * Debug-only: name cache files `<slug>.<hash>.js` and append a trailing\n * `// @source <path>` marker so entries are eyeball-identifiable. Off by\n * default (opaque `<hash>.js`). Cosmetic — never affects keys or lookup.\n */\n debugNames: boolean;\n};\n\nconst VERSION_QUERY = /\\?v=\\d+$/;\nconst TS_FILE = /\\.(ts|tsx|mts|cts)$/;\nconst STYLESHEET_FILE = /\\.(css|scss|sass|less|styl)$/;\n\nlet transpile: TranspileInit;\nlet cache: TranspileCache;\n\n/**\n * Called once from the hook worker's `initialize()`. Wires the persisted\n * transpile cache and runs one opportunistic GC pass at boot — cheap, off\n * the hot path, single directory scan.\n */\nexport function configureTranspile(init: TranspileInit): void {\n transpile = init;\n cache = new TranspileCache(init.cacheDir);\n\n // Boot-time eviction so the cache can't grow unbounded across weeks of\n // dev. Bounds are generous; correctness never depends on GC (content\n // hashing already guarantees that) — this is purely disk hygiene.\n cache.gc({\n maxBytes: 256 * 1024 * 1024,\n maxAgeMs: 14 * 24 * 60 * 60 * 1000,\n });\n}\n\n/**\n * ESM loader `load()` hook.\n *\n * Owns the transpile for **every** TypeScript file — project `src/`,\n * `@warlock.js/*` framework source, and `warlock.config.ts` alike. There\n * is no tsx in the TypeScript path any more: we read the source, key it by\n * a content hash + options fingerprint, serve the cached JS on a hit, and\n * otherwise transform it with esbuild directly and persist. Non-TypeScript\n * URLs (npm `.js`/`.cjs`/`.mjs`, `node:` builtins, JSON) are not ours —\n * they fall through to the next loader (Node's default).\n *\n * The `?v=<N>` query drives Node's module identity (HMR) for `src/` files\n * and is **never** part of the cache key — the cache is keyed purely by\n * source content, so the two mechanisms are fully orthogonal. Framework\n * and config `.ts` carry no `?v` (no HMR) but are transpiled and cached\n * exactly the same way.\n *\n * The source map esbuild emits is inline base64 with `sourcefile` set to\n * the clean absolute `.ts` path, so V8 (run with source maps enabled)\n * reports stack frames at the original TypeScript location.\n *\n * @example\n * // load(\"file:///src/user.model.ts?v=3\") → esbuild transpile + cache\n * // load(\"file:///@warlock.js/core/src/x.ts\") → esbuild transpile + cache\n * // load(\"file:///node_modules/ms/index.js\") → nextLoad (Node default)\n */\nexport async function load(\n url: string,\n context: LoadContext,\n nextLoad: NextLoad,\n): Promise<LoadResult> {\n const cleanUrl = url.replace(VERSION_QUERY, \"\");\n\n // A stylesheet imported by a component. Node cannot load one, and in Node the\n // styles have no meaning: a module graph imported for its exports (sitemap\n // discovery, page listing) only needs the import to resolve. CSS modules get\n // an empty class map.\n if (STYLESHEET_FILE.test(cleanUrl)) {\n return { format: \"module\", source: \"export default {};\\n\", shortCircuit: true };\n }\n\n // Not TypeScript → not ours. npm packages, node: builtins, JSON, etc.\n if (!TS_FILE.test(cleanUrl)) {\n return nextLoad(url, context);\n }\n\n const absolutePath = fileURLToPath(cleanUrl);\n const source = readFileSync(absolutePath, \"utf8\");\n const key = cacheKey(source, transpile.fingerprint);\n\n // Cosmetic filename label; undefined keeps opaque <hash>.js names.\n const label = transpile.debugNames ? sourceSlug(absolutePath) : undefined;\n\n const hit = cache.get(key, label);\n if (hit) {\n return { format: \"module\", source: hit.code, shortCircuit: true };\n }\n\n const loader = absolutePath.endsWith(\".tsx\") ? \"tsx\" : \"ts\";\n\n const result = transformSync(source, {\n loader,\n format: \"esm\",\n target: transpile.target,\n sourcefile: absolutePath,\n // Inline base64 map, self-contained (sourcesContent on by default), so\n // it survives the ?v=N URL with no extra resolution step.\n sourcemap: \"inline\",\n tsconfigRaw: transpile.tsconfigRaw,\n });\n\n // result.code already carries the inline //# sourceMappingURL. The\n // marker goes AFTER that line: a trailing comment can't shift earlier\n // generated lines, so the inline map (and therefore stack-frame line\n // numbers) stays exact. A leading marker would desync it by one line.\n const code = label ? `${result.code}\\n// @source ${absolutePath}\\n` : result.code;\n\n cache.put(key, { code, map: \"\" }, label);\n\n return { format: \"module\", source: code, shortCircuit: true };\n}\n"],"mappings":";;;;;;;AAyCA,MAAM,gBAAgB;AACtB,MAAM,UAAU;AAChB,MAAM,kBAAkB;AAExB,IAAI;AACJ,IAAI;;;;;;AAOJ,SAAgB,mBAAmB,MAA2B;CAC5D,YAAY;CACZ,QAAQ,IAAI,eAAe,KAAK,QAAQ;CAKxC,MAAM,GAAG;EACP,UAAU;EACV,UAAU;CACZ,CAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BA,eAAsB,KACpB,KACA,SACA,UACqB;CACrB,MAAM,WAAW,IAAI,QAAQ,eAAe,EAAE;CAM9C,IAAI,gBAAgB,KAAK,QAAQ,GAC/B,OAAO;EAAE,QAAQ;EAAU,QAAQ;EAAwB,cAAc;CAAK;CAIhF,IAAI,CAAC,QAAQ,KAAK,QAAQ,GACxB,OAAO,SAAS,KAAK,OAAO;CAG9B,MAAM,eAAe,cAAc,QAAQ;CAC3C,MAAM,SAAS,aAAa,cAAc,MAAM;CAChD,MAAM,MAAM,SAAS,QAAQ,UAAU,WAAW;CAGlD,MAAM,QAAQ,UAAU,aAAa,WAAW,YAAY,IAAI;CAEhE,MAAM,MAAM,MAAM,IAAI,KAAK,KAAK;CAChC,IAAI,KACF,OAAO;EAAE,QAAQ;EAAU,QAAQ,IAAI;EAAM,cAAc;CAAK;CAGlE,MAAM,SAAS,aAAa,SAAS,MAAM,IAAI,QAAQ;CAEvD,MAAM,SAAS,cAAc,QAAQ;EACnC;EACA,QAAQ;EACR,QAAQ,UAAU;EAClB,YAAY;EAGZ,WAAW;EACX,aAAa,UAAU;CACzB,CAAC;CAMD,MAAM,OAAO,QAAQ,GAAG,OAAO,KAAK,eAAe,aAAa,MAAM,OAAO;CAE7E,MAAM,IAAI,KAAK;EAAE;EAAM,KAAK;CAAG,GAAG,KAAK;CAEvC,OAAO;EAAE,QAAQ;EAAU,QAAQ;EAAM,cAAc;CAAK;AAC9D"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { router } from "../router/router.mjs";
|
|
2
2
|
import { registerGroupedTranslationKeys, registerLocaleDictionary } from "../localization/register-locale-dictionary.mjs";
|
|
3
|
+
import { parseSourceFile } from "../tooling/syntax/ast.mjs";
|
|
3
4
|
import "../localization/index.mjs";
|
|
4
5
|
import { devLogError, formatModuleNotFoundError } from "./dev-logger.mjs";
|
|
5
|
-
import { parseSourceFile } from "../tooling/syntax/ast.mjs";
|
|
6
6
|
import { importAppModule } from "../loader/app-module-importer.mjs";
|
|
7
7
|
import { extractTranslationKeys } from "./extract-translation-keys.mjs";
|
|
8
8
|
import { warnForLegacyLocales } from "./legacy-locales-warning.mjs";
|
|
@@ -2,8 +2,8 @@ import { Path } from "../utils/normalized-path.mjs";
|
|
|
2
2
|
import { tsconfigManager } from "./tsconfig-manager.mjs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { directoryExistsAsync, fileExistsAsync } from "@warlock.js/fs";
|
|
5
|
-
import { parse } from "es-module-lexer";
|
|
6
5
|
import { parseSync } from "oxc-parser";
|
|
6
|
+
import { parse } from "es-module-lexer";
|
|
7
7
|
|
|
8
8
|
//#region ../../packages/core/src/dev-server/parse-imports.ts
|
|
9
9
|
/**
|
|
@@ -2,11 +2,11 @@ import { Path } from "../utils/normalized-path.mjs";
|
|
|
2
2
|
import { warlockPath } from "../utils/paths.mjs";
|
|
3
3
|
import "../utils/index.mjs";
|
|
4
4
|
import { parseLocaleDictionary } from "../localization/parse-locale-dictionary.mjs";
|
|
5
|
+
import { forEachChild, hasModifier, isImportDeclaration, isInterfaceDeclaration, isObjectLiteralExpression, isPropertyAssignment, isShorthandPropertyAssignment, isTypeAliasDeclaration, isVariableDeclaration, keyName, textOf } from "../tooling/syntax/ast.mjs";
|
|
5
6
|
import "../localization/index.mjs";
|
|
6
7
|
import { devLogDim, devLogError, devLogInfo, devLogSuccess, devServeLog } from "./dev-logger.mjs";
|
|
7
8
|
import { parseImports } from "./parse-imports.mjs";
|
|
8
9
|
import { getFilesFromDirectory } from "./utils.mjs";
|
|
9
|
-
import { forEachChild, hasModifier, isImportDeclaration, isInterfaceDeclaration, isObjectLiteralExpression, isPropertyAssignment, isShorthandPropertyAssignment, isTypeAliasDeclaration, isVariableDeclaration, keyName, textOf } from "../tooling/syntax/ast.mjs";
|
|
10
10
|
import { extractTranslationKeys } from "./extract-translation-keys.mjs";
|
|
11
11
|
import { filesOrchestrator } from "./files-orchestrator.mjs";
|
|
12
12
|
import { readConfigAst } from "./read-config-ast.mjs";
|
package/esm/e2e/cdp.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cdp.d.mts","names":[],"sources":["../../../../../../../../packages/core/src/e2e/cdp.ts"],"mappings":";;;;;;KAKK;EAAiB;EAAiB;;KAClC;EAAqB;EAAc,YAAY;;YACxC;EAEV;IAAoB,QAAQ;IAAuB,QAAQ;;EAE3D;IACE;MAAU;MAAoB;MAAwB;MAAuB;;IAC7E;MAAU,QAAQ;MAAc,mBAAmB;;;EAGrD;IAAiB,QAAQ;IAAuB,QAAQ;;EAExD;IACE;MAAU;;IACV;MAAU;MAAiB;MAAmB;;;EAGhD;IAA4B;MAAU;;IAAiB;MAAU;;;EAEjE;IACE;MAAU;MAAe;MAAgB;MAA2B;;IACpE,QAAQ;;EAGV;IACE;MACE;MACA;MACA;MACA;MACA;MACA;;IAEF,QAAQ;;EAGV;IAAsB;MAAU;;IAAgB,QAAQ;;EAExD;IACE;MAAU;MAA2B;MAAa;MAAc;;IAChE,QAAQ;;EAGV;IAAoB,QAAQ;IAAuB,QAAQ;;EAE3D;IAAgB,QAAQ;IAAuB,QAAQ;;;YAE7C;EAEV;IAAyB;;EAEzB;IAA8B;IAAc,MAAM;;EAElD;IAA6B,kBAAkB;;EAE/C;IAAoB;MAAS;MAAe;;;EAE5C;IAA+B;IAAmB;MAAW;;;EAE7D;IAA8B;IAAmB;MAAY;MAAa;;;EAE1E;IAA2B;IAAmB;IAAmB;;EAEjE;IAA6B;;;
|
|
1
|
+
{"version":3,"file":"cdp.d.mts","names":[],"sources":["../../../../../../../../packages/core/src/e2e/cdp.ts"],"mappings":";;;;;;KAKK;EAAiB;EAAiB;;KAClC;EAAqB;EAAc,YAAY;;YACxC;EAEV;IAAoB,QAAQ;IAAuB,QAAQ;;EAE3D;IACE;MAAU;MAAoB;MAAwB;MAAuB;;IAC7E;MAAU,QAAQ;MAAc,mBAAmB;;;EAGrD;IAAiB,QAAQ;IAAuB,QAAQ;;EAExD;IACE;MAAU;;IACV;MAAU;MAAiB;MAAmB;;;EAGhD;IAA4B;MAAU;;IAAiB;MAAU;;;EAEjE;IACE;MAAU;MAAe;MAAgB;MAA2B;;IACpE,QAAQ;;EAGV;IACE;MACE;MACA;MACA;MACA;MACA;MACA;;IAEF,QAAQ;;EAGV;IAAsB;MAAU;;IAAgB,QAAQ;;EAExD;IACE;MAAU;MAA2B;MAAa;MAAc;;IAChE,QAAQ;;EAGV;IAAoB,QAAQ;IAAuB,QAAQ;;EAE3D;IAAgB,QAAQ;IAAuB,QAAQ;;;YAE7C;EAEV;IAAyB;;EAEzB;IAA8B;IAAc,MAAM;;EAElD;IAA6B,kBAAkB;;EAE/C;IAAoB;MAAS;MAAe;;;EAE5C;IAA+B;IAAmB;MAAW;;;EAE7D;IAA8B;IAAmB;MAAY;MAAa;;;EAE1E;IAA2B;IAAmB;IAAmB;;EAEjE;IAA6B;;;qBAgBlB;UAMiB;UALpB;UACA;UACA;UACA;UAED;SA4BM,QAAQ,aAAa,qBAAqB,QAAQ;EAiC/D,QAAQ,gBAAgB,YACtB,QAAQ,GACR,QAAQ,WAAW,cACnB,qBACC,QAAQ,WAAW;EA0BtB,GAAG,gBAAgB,WAAW,QAAQ,GAAG,WAAW,QAAQ,UAAU;UAU9D;EASR"}
|
package/esm/e2e/cdp.mjs
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
//#region ../../packages/core/src/e2e/cdp.ts
|
|
2
|
+
/** A command got no reply within its budget. Retry loops that shrink their budget use this type to tell a timeout apart from a reply that failed. */
|
|
3
|
+
var CdpTimeoutError = class extends Error {
|
|
4
|
+
constructor(timeoutMs, method) {
|
|
5
|
+
super(`CDP timeout after ${timeoutMs}ms: ${method}`);
|
|
6
|
+
this.name = "CdpTimeoutError";
|
|
7
|
+
}
|
|
8
|
+
};
|
|
2
9
|
var CdpConnection = class CdpConnection {
|
|
3
10
|
constructor(socket) {
|
|
4
11
|
this.socket = socket;
|
|
@@ -57,7 +64,7 @@ var CdpConnection = class CdpConnection {
|
|
|
57
64
|
const id = ++this.sequence;
|
|
58
65
|
const timer = setTimeout(() => {
|
|
59
66
|
this.pending.delete(id);
|
|
60
|
-
reject(
|
|
67
|
+
reject(new CdpTimeoutError(timeoutMs, method));
|
|
61
68
|
}, Math.max(1, timeoutMs));
|
|
62
69
|
this.pending.set(id, {
|
|
63
70
|
resolve: (value) => resolve(value),
|
|
@@ -102,5 +109,5 @@ var CdpConnection = class CdpConnection {
|
|
|
102
109
|
};
|
|
103
110
|
|
|
104
111
|
//#endregion
|
|
105
|
-
export { CdpConnection };
|
|
112
|
+
export { CdpConnection, CdpTimeoutError };
|
|
106
113
|
//# sourceMappingURL=cdp.mjs.map
|
package/esm/e2e/cdp.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cdp.mjs","names":[],"sources":["../../../../../../../../packages/core/src/e2e/cdp.ts"],"sourcesContent":["/** Wire shapes verified against the official protocol viewer and its source JSON:\n * https://chromedevtools.github.io/devtools-protocol/\n * https://github.com/ChromeDevTools/devtools-protocol/tree/master/json\n * Only the fields consumed by this harness are modeled here.\n */\ntype RemoteObject = { value?: unknown; description?: string };\ntype ExceptionDetails = { text: string; exception?: RemoteObject };\nexport type CdpMethods = {\n // https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-enable\n \"Runtime.enable\": { params: Record<string, never>; result: Record<string, never> };\n // https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-evaluate\n \"Runtime.evaluate\": {\n params: { expression: string; returnByValue: boolean; awaitPromise: boolean; silent: boolean };\n result: { result: RemoteObject; exceptionDetails?: ExceptionDetails };\n };\n // https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-enable\n \"Page.enable\": { params: Record<string, never>; result: Record<string, never> };\n // https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-navigate\n \"Page.navigate\": {\n params: { url: string };\n result: { frameId: string; loaderId?: string; errorText?: string };\n };\n // https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-captureScreenshot\n \"Page.captureScreenshot\": { params: { format: \"png\" }; result: { data: string } };\n // https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-setDeviceMetricsOverride\n \"Emulation.setDeviceMetricsOverride\": {\n params: { width: number; height: number; deviceScaleFactor: number; mobile: boolean };\n result: Record<string, never>;\n };\n // https://chromedevtools.github.io/devtools-protocol/tot/Input/#method-dispatchMouseEvent\n \"Input.dispatchMouseEvent\": {\n params: {\n type: \"mouseMoved\" | \"mousePressed\" | \"mouseReleased\";\n x: number;\n y: number;\n button?: \"left\";\n buttons?: number;\n clickCount?: number;\n };\n result: Record<string, never>;\n };\n // https://chromedevtools.github.io/devtools-protocol/tot/Input/#method-insertText\n \"Input.insertText\": { params: { text: string }; result: Record<string, never> };\n // https://chromedevtools.github.io/devtools-protocol/tot/Input/#method-dispatchKeyEvent\n \"Input.dispatchKeyEvent\": {\n params: { type: \"keyDown\" | \"keyUp\"; key: string; code: string; windowsVirtualKeyCode: number };\n result: Record<string, never>;\n };\n // https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-enable\n \"Network.enable\": { params: Record<string, never>; result: Record<string, never> };\n // https://chromedevtools.github.io/devtools-protocol/tot/Log/#method-enable\n \"Log.enable\": { params: Record<string, never>; result: Record<string, never> };\n};\nexport type CdpEvents = {\n // https://chromedevtools.github.io/devtools-protocol/tot/Page/#event-loadEventFired\n \"Page.loadEventFired\": { timestamp: number };\n // https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#event-consoleAPICalled\n \"Runtime.consoleAPICalled\": { type: string; args: RemoteObject[] };\n // https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#event-exceptionThrown\n \"Runtime.exceptionThrown\": { exceptionDetails: ExceptionDetails };\n // https://chromedevtools.github.io/devtools-protocol/tot/Log/#event-entryAdded\n \"Log.entryAdded\": { entry: { level: string; text: string } };\n // https://chromedevtools.github.io/devtools-protocol/tot/Network/#event-requestWillBeSent\n \"Network.requestWillBeSent\": { requestId: string; request: { url: string } };\n // https://chromedevtools.github.io/devtools-protocol/tot/Network/#event-responseReceived\n \"Network.responseReceived\": { requestId: string; response: { url: string; status: number } };\n // https://chromedevtools.github.io/devtools-protocol/tot/Network/#event-loadingFailed\n \"Network.loadingFailed\": { requestId: string; errorText: string; canceled?: boolean };\n // https://chromedevtools.github.io/devtools-protocol/tot/Network/#event-loadingFinished\n \"Network.loadingFinished\": { requestId: string };\n};\ntype Pending = {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n};\n\nexport class CdpConnection {\n private sequence = 0;\n private pending = new Map<number, Pending>();\n private listeners = new Map<string, Set<(params: unknown) => void>>();\n private closed = false;\n\n private constructor(private socket: WebSocket) {\n socket.addEventListener(\"message\", ({ data }) => {\n try {\n const message = JSON.parse(String(data)) as {\n id?: number;\n method?: string;\n params?: unknown;\n result?: unknown;\n error?: { message: string };\n };\n if (typeof message.id === \"number\") {\n const pending = this.pending.get(message.id);\n if (!pending) return;\n clearTimeout(pending.timer);\n this.pending.delete(message.id);\n if (message.error) pending.reject(new Error(`CDP: ${message.error.message}`));\n else pending.resolve(message.result);\n } else if (message.method) {\n for (const listener of this.listeners.get(message.method) ?? []) listener(message.params);\n }\n } catch (error) {\n this.fail(new Error(`Invalid CDP message: ${String(error)}`));\n }\n });\n socket.addEventListener(\"close\", () => this.fail(new Error(\"CDP connection closed\")));\n socket.addEventListener(\"error\", () => this.fail(new Error(\"CDP WebSocket error\")));\n }\n\n static async connect(url: string, timeoutMs = 10_000): Promise<CdpConnection> {\n // Stable since Node 22.4, present in the minimum supported Node 22.15.\n // https://nodejs.org/download/release/v22.15.0/docs/api/globals.html#websocket\n if (typeof WebSocket !== \"function\")\n throw new Error(\n \"Browser e2e requires Node's global WebSocket (Node >=22.15, without --no-experimental-websocket)\",\n );\n const socket = new WebSocket(url);\n const connection = new CdpConnection(socket);\n await new Promise<void>((resolve, reject) => {\n const cleanup = () => {\n clearTimeout(timer);\n socket.removeEventListener(\"open\", opened);\n socket.removeEventListener(\"error\", failed);\n socket.removeEventListener(\"close\", failed);\n };\n const opened = () => {\n cleanup();\n resolve();\n };\n const failed = () => {\n cleanup();\n socket.close();\n reject(new Error(`Cannot connect to owned browser CDP endpoint ${url}`));\n };\n const timer = setTimeout(failed, timeoutMs);\n socket.addEventListener(\"open\", opened, { once: true });\n socket.addEventListener(\"error\", failed, { once: true });\n socket.addEventListener(\"close\", failed, { once: true });\n });\n return connection;\n }\n\n command<K extends keyof CdpMethods>(\n method: K,\n params: CdpMethods[K][\"params\"],\n timeoutMs = 10_000,\n ): Promise<CdpMethods[K][\"result\"]> {\n if (this.closed) return Promise.reject(new Error(`CDP closed before ${method}`));\n return new Promise<CdpMethods[K][\"result\"]>((resolve, reject) => {\n const id = ++this.sequence;\n const timer = setTimeout(\n () => {\n this.pending.delete(id);\n reject(new Error(`CDP timeout after ${timeoutMs}ms: ${method}`));\n },\n Math.max(1, timeoutMs),\n );\n this.pending.set(id, {\n resolve: (value) => resolve(value as CdpMethods[K][\"result\"]),\n reject,\n timer,\n });\n try {\n this.socket.send(JSON.stringify({ id, method, params }));\n } catch (error) {\n clearTimeout(timer);\n this.pending.delete(id);\n reject(error);\n }\n });\n }\n\n on<K extends keyof CdpEvents>(method: K, listener: (params: CdpEvents[K]) => void): () => void {\n const wrapped = (params: unknown) => listener(params as CdpEvents[K]);\n const listeners = this.listeners.get(method) ?? new Set();\n listeners.add(wrapped);\n this.listeners.set(method, listeners);\n return () => {\n listeners.delete(wrapped);\n };\n }\n\n private fail(error: Error): void {\n this.closed = true;\n for (const pending of this.pending.values()) {\n clearTimeout(pending.timer);\n pending.reject(error);\n }\n this.pending.clear();\n }\n\n close(): void {\n this.fail(new Error(\"CDP connection closed by harness\"));\n this.listeners.clear();\n this.socket.close();\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cdp.mjs","names":[],"sources":["../../../../../../../../packages/core/src/e2e/cdp.ts"],"sourcesContent":["/** Wire shapes verified against the official protocol viewer and its source JSON:\n * https://chromedevtools.github.io/devtools-protocol/\n * https://github.com/ChromeDevTools/devtools-protocol/tree/master/json\n * Only the fields consumed by this harness are modeled here.\n */\ntype RemoteObject = { value?: unknown; description?: string };\ntype ExceptionDetails = { text: string; exception?: RemoteObject };\nexport type CdpMethods = {\n // https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-enable\n \"Runtime.enable\": { params: Record<string, never>; result: Record<string, never> };\n // https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#method-evaluate\n \"Runtime.evaluate\": {\n params: { expression: string; returnByValue: boolean; awaitPromise: boolean; silent: boolean };\n result: { result: RemoteObject; exceptionDetails?: ExceptionDetails };\n };\n // https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-enable\n \"Page.enable\": { params: Record<string, never>; result: Record<string, never> };\n // https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-navigate\n \"Page.navigate\": {\n params: { url: string };\n result: { frameId: string; loaderId?: string; errorText?: string };\n };\n // https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-captureScreenshot\n \"Page.captureScreenshot\": { params: { format: \"png\" }; result: { data: string } };\n // https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-setDeviceMetricsOverride\n \"Emulation.setDeviceMetricsOverride\": {\n params: { width: number; height: number; deviceScaleFactor: number; mobile: boolean };\n result: Record<string, never>;\n };\n // https://chromedevtools.github.io/devtools-protocol/tot/Input/#method-dispatchMouseEvent\n \"Input.dispatchMouseEvent\": {\n params: {\n type: \"mouseMoved\" | \"mousePressed\" | \"mouseReleased\";\n x: number;\n y: number;\n button?: \"left\";\n buttons?: number;\n clickCount?: number;\n };\n result: Record<string, never>;\n };\n // https://chromedevtools.github.io/devtools-protocol/tot/Input/#method-insertText\n \"Input.insertText\": { params: { text: string }; result: Record<string, never> };\n // https://chromedevtools.github.io/devtools-protocol/tot/Input/#method-dispatchKeyEvent\n \"Input.dispatchKeyEvent\": {\n params: { type: \"keyDown\" | \"keyUp\"; key: string; code: string; windowsVirtualKeyCode: number };\n result: Record<string, never>;\n };\n // https://chromedevtools.github.io/devtools-protocol/tot/Network/#method-enable\n \"Network.enable\": { params: Record<string, never>; result: Record<string, never> };\n // https://chromedevtools.github.io/devtools-protocol/tot/Log/#method-enable\n \"Log.enable\": { params: Record<string, never>; result: Record<string, never> };\n};\nexport type CdpEvents = {\n // https://chromedevtools.github.io/devtools-protocol/tot/Page/#event-loadEventFired\n \"Page.loadEventFired\": { timestamp: number };\n // https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#event-consoleAPICalled\n \"Runtime.consoleAPICalled\": { type: string; args: RemoteObject[] };\n // https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#event-exceptionThrown\n \"Runtime.exceptionThrown\": { exceptionDetails: ExceptionDetails };\n // https://chromedevtools.github.io/devtools-protocol/tot/Log/#event-entryAdded\n \"Log.entryAdded\": { entry: { level: string; text: string } };\n // https://chromedevtools.github.io/devtools-protocol/tot/Network/#event-requestWillBeSent\n \"Network.requestWillBeSent\": { requestId: string; request: { url: string } };\n // https://chromedevtools.github.io/devtools-protocol/tot/Network/#event-responseReceived\n \"Network.responseReceived\": { requestId: string; response: { url: string; status: number } };\n // https://chromedevtools.github.io/devtools-protocol/tot/Network/#event-loadingFailed\n \"Network.loadingFailed\": { requestId: string; errorText: string; canceled?: boolean };\n // https://chromedevtools.github.io/devtools-protocol/tot/Network/#event-loadingFinished\n \"Network.loadingFinished\": { requestId: string };\n};\ntype Pending = {\n resolve: (value: unknown) => void;\n reject: (error: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n};\n\n/** A command got no reply within its budget. Retry loops that shrink their budget use this type to tell a timeout apart from a reply that failed. */\nexport class CdpTimeoutError extends Error {\n constructor(timeoutMs: number, method: string) {\n super(`CDP timeout after ${timeoutMs}ms: ${method}`);\n this.name = \"CdpTimeoutError\";\n }\n}\n\nexport class CdpConnection {\n private sequence = 0;\n private pending = new Map<number, Pending>();\n private listeners = new Map<string, Set<(params: unknown) => void>>();\n private closed = false;\n\n private constructor(private socket: WebSocket) {\n socket.addEventListener(\"message\", ({ data }) => {\n try {\n const message = JSON.parse(String(data)) as {\n id?: number;\n method?: string;\n params?: unknown;\n result?: unknown;\n error?: { message: string };\n };\n if (typeof message.id === \"number\") {\n const pending = this.pending.get(message.id);\n if (!pending) return;\n clearTimeout(pending.timer);\n this.pending.delete(message.id);\n if (message.error) pending.reject(new Error(`CDP: ${message.error.message}`));\n else pending.resolve(message.result);\n } else if (message.method) {\n for (const listener of this.listeners.get(message.method) ?? []) listener(message.params);\n }\n } catch (error) {\n this.fail(new Error(`Invalid CDP message: ${String(error)}`));\n }\n });\n socket.addEventListener(\"close\", () => this.fail(new Error(\"CDP connection closed\")));\n socket.addEventListener(\"error\", () => this.fail(new Error(\"CDP WebSocket error\")));\n }\n\n static async connect(url: string, timeoutMs = 10_000): Promise<CdpConnection> {\n // Stable since Node 22.4, present in the minimum supported Node 22.15.\n // https://nodejs.org/download/release/v22.15.0/docs/api/globals.html#websocket\n if (typeof WebSocket !== \"function\")\n throw new Error(\n \"Browser e2e requires Node's global WebSocket (Node >=22.15, without --no-experimental-websocket)\",\n );\n const socket = new WebSocket(url);\n const connection = new CdpConnection(socket);\n await new Promise<void>((resolve, reject) => {\n const cleanup = () => {\n clearTimeout(timer);\n socket.removeEventListener(\"open\", opened);\n socket.removeEventListener(\"error\", failed);\n socket.removeEventListener(\"close\", failed);\n };\n const opened = () => {\n cleanup();\n resolve();\n };\n const failed = () => {\n cleanup();\n socket.close();\n reject(new Error(`Cannot connect to owned browser CDP endpoint ${url}`));\n };\n const timer = setTimeout(failed, timeoutMs);\n socket.addEventListener(\"open\", opened, { once: true });\n socket.addEventListener(\"error\", failed, { once: true });\n socket.addEventListener(\"close\", failed, { once: true });\n });\n return connection;\n }\n\n command<K extends keyof CdpMethods>(\n method: K,\n params: CdpMethods[K][\"params\"],\n timeoutMs = 10_000,\n ): Promise<CdpMethods[K][\"result\"]> {\n if (this.closed) return Promise.reject(new Error(`CDP closed before ${method}`));\n return new Promise<CdpMethods[K][\"result\"]>((resolve, reject) => {\n const id = ++this.sequence;\n const timer = setTimeout(\n () => {\n this.pending.delete(id);\n reject(new CdpTimeoutError(timeoutMs, method));\n },\n Math.max(1, timeoutMs),\n );\n this.pending.set(id, {\n resolve: (value) => resolve(value as CdpMethods[K][\"result\"]),\n reject,\n timer,\n });\n try {\n this.socket.send(JSON.stringify({ id, method, params }));\n } catch (error) {\n clearTimeout(timer);\n this.pending.delete(id);\n reject(error);\n }\n });\n }\n\n on<K extends keyof CdpEvents>(method: K, listener: (params: CdpEvents[K]) => void): () => void {\n const wrapped = (params: unknown) => listener(params as CdpEvents[K]);\n const listeners = this.listeners.get(method) ?? new Set();\n listeners.add(wrapped);\n this.listeners.set(method, listeners);\n return () => {\n listeners.delete(wrapped);\n };\n }\n\n private fail(error: Error): void {\n this.closed = true;\n for (const pending of this.pending.values()) {\n clearTimeout(pending.timer);\n pending.reject(error);\n }\n this.pending.clear();\n }\n\n close(): void {\n this.fail(new Error(\"CDP connection closed by harness\"));\n this.listeners.clear();\n this.socket.close();\n }\n}\n"],"mappings":"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"}
|
package/esm/e2e/page.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CdpConnection } from "./cdp.mjs";
|
|
2
|
-
import { AccessibilityEvidence, AccessibilityOptions, E2EEvidence, E2ESpec, Viewport } from "./types.mjs";
|
|
2
|
+
import { AccessibilityEvidence, AccessibilityOptions, E2EEvidence, E2ESpec, PayloadEvidence, Viewport } from "./types.mjs";
|
|
3
3
|
//#region ../../packages/core/src/e2e/page.d.ts
|
|
4
4
|
type WaitOptions = {
|
|
5
5
|
selector?: string;
|
|
@@ -57,6 +57,14 @@ export declare class BrowserPage {
|
|
|
57
57
|
* API: https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axerun
|
|
58
58
|
* No CDN, DOM script element, or application dependency is required.
|
|
59
59
|
*/
|
|
60
|
+
/**
|
|
61
|
+
* Measures the inline payload of the document the page currently shows and
|
|
62
|
+
* records it under `evidence.payloads`. Measure after a full load: a client
|
|
63
|
+
* navigation replaces the data it reads. Pass `limit` to mark an overage.
|
|
64
|
+
*/
|
|
65
|
+
measurePayload(options?: {
|
|
66
|
+
limit?: number;
|
|
67
|
+
}): Promise<PayloadEvidence>;
|
|
60
68
|
assertAccessible(options?: AccessibilityOptions): Promise<AccessibilityEvidence>;
|
|
61
69
|
assertViewport(): Promise<ViewportReport>;
|
|
62
70
|
screenshot(name: string): Promise<string>;
|
package/esm/e2e/page.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.d.mts","names":[],"sources":["../../../../../../../../packages/core/src/e2e/page.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"page.d.mts","names":[],"sources":["../../../../../../../../packages/core/src/e2e/page.ts"],"mappings":";;;KAiBK;EAAgB;EAAmB;EAAe;EAAc;;KAEhE;EACH;EACA;EACA;EACA;EACA;IACE;IACA;IACA;IACA;IACA;IACA;IACA;;;qBAgES;UAQD;UACA;UACA;UACA;UACA;UAXF;UACA;UACA;UACA;UACA;EAER,YACU,KAAK,eACL,gBACA,yBACA,UAAU,aACV,MAAM;UAgDR;EAMF,cAAc;EAQd,KAAK,GAAG,cAAc,cAAc,QAAQ,KAAK,QAAQ;EAqBzD,SAAS,aAAa,oBAAoB,qBAAqB,QAAQ;UAa/D;EAoBR,KAAK,cAAc,qBAAqB;EAkBxC,QAAQ,SAAS,cAAc;;;;EA0B/B,kBACJ,cAAc,kBACd;IAAW;IAAc;MACxB;EAkBG,MAAM,kBAAkB,qBAAqB;EA6E7C,KAAK,kBAAkB,gBAAgB;;EA4BvC,KAAK,kBAAkB,eAAe;EA0BtC,YAAY,UAAU,WAAW;;;;;;;;;;EAgCjC,eAAe;IAAW;MAAwB,QAAQ;EA2B1D,iBAAiB,UAAS,uBAA4B,QAAQ;EA8C9D,kBAAkB,QAAQ;EAoB1B,WAAW,eAAe;EAY1B,iBACJ,cACA,qBAAS,aACR;EAuBG,mBAAmB,qBAAqB;EAgB9C"}
|
package/esm/e2e/page.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CdpTimeoutError } from "./cdp.mjs";
|
|
1
2
|
import { defaultViewports, errorMessage, matches } from "./types.mjs";
|
|
2
3
|
import { createRequire } from "node:module";
|
|
3
4
|
import { join } from "node:path";
|
|
@@ -55,6 +56,14 @@ function boxesStable(first, second) {
|
|
|
55
56
|
"height"
|
|
56
57
|
].every((key) => Math.abs(first[key] - second[key]) < .25);
|
|
57
58
|
}
|
|
59
|
+
/** Reason to report after a failed probe in a retry loop. A CDP timeout comes from
|
|
60
|
+
* the deadline shrinking under the probe, not from the target, so it must not
|
|
61
|
+
* replace a reason already observed on the target. Any other error is reported.
|
|
62
|
+
*/
|
|
63
|
+
function probeReason(error, observed) {
|
|
64
|
+
if (error instanceof CdpTimeoutError && observed !== void 0) return observed;
|
|
65
|
+
return errorMessage(error);
|
|
66
|
+
}
|
|
58
67
|
var BrowserPage = class {
|
|
59
68
|
constructor(cdp, origin, outputDirectory, evidence, spec) {
|
|
60
69
|
this.cdp = cdp;
|
|
@@ -153,16 +162,16 @@ var BrowserPage = class {
|
|
|
153
162
|
}
|
|
154
163
|
async poll(description, check, timeoutMs) {
|
|
155
164
|
const deadline = Date.now() + timeoutMs;
|
|
156
|
-
let reason
|
|
165
|
+
let reason;
|
|
157
166
|
while (Date.now() < deadline) {
|
|
158
167
|
try {
|
|
159
168
|
if (await check(Math.max(1, deadline - Date.now()))) return;
|
|
160
169
|
} catch (error) {
|
|
161
|
-
reason =
|
|
170
|
+
reason = probeReason(error, reason);
|
|
162
171
|
}
|
|
163
172
|
await setTimeout(Math.min(50, Math.max(0, deadline - Date.now())));
|
|
164
173
|
}
|
|
165
|
-
throw new Error(`${description} timed out after ${timeoutMs}ms: ${reason}`);
|
|
174
|
+
throw new Error(`${description} timed out after ${timeoutMs}ms: ${reason ?? "condition stayed false"}`);
|
|
166
175
|
}
|
|
167
176
|
async goto(path, timeoutMs = 1e4) {
|
|
168
177
|
await this.step(`goto ${path}`, async () => {
|
|
@@ -198,14 +207,14 @@ var BrowserPage = class {
|
|
|
198
207
|
await this.step(`click ${selector}`, async () => {
|
|
199
208
|
const deadline = Date.now() + timeoutMs;
|
|
200
209
|
let previous;
|
|
201
|
-
let reason
|
|
210
|
+
let reason;
|
|
202
211
|
while (Date.now() < deadline) {
|
|
203
212
|
const remaining = () => Math.max(1, deadline - Date.now());
|
|
204
213
|
let box;
|
|
205
214
|
try {
|
|
206
215
|
box = await this.evaluate(`(${clickProbe.toString()})(${JSON.stringify(selector)})`, remaining());
|
|
207
216
|
} catch (error) {
|
|
208
|
-
reason =
|
|
217
|
+
reason = probeReason(error, reason);
|
|
209
218
|
previous = void 0;
|
|
210
219
|
await setTimeout(25);
|
|
211
220
|
continue;
|
|
@@ -221,7 +230,7 @@ var BrowserPage = class {
|
|
|
221
230
|
}, remaining());
|
|
222
231
|
hovered = await this.evaluate(`(${clickProbe.toString()})(${JSON.stringify(selector)})`, remaining());
|
|
223
232
|
} catch (error) {
|
|
224
|
-
reason =
|
|
233
|
+
reason = probeReason(error, reason);
|
|
225
234
|
previous = void 0;
|
|
226
235
|
await setTimeout(Math.min(25, remaining()));
|
|
227
236
|
continue;
|
|
@@ -250,7 +259,7 @@ var BrowserPage = class {
|
|
|
250
259
|
} else previous = box;
|
|
251
260
|
await setTimeout(Math.min(50, remaining()));
|
|
252
261
|
}
|
|
253
|
-
throw new Error(`Cannot click ${JSON.stringify(selector)} within ${timeoutMs}ms: ${reason}`);
|
|
262
|
+
throw new Error(`Cannot click ${JSON.stringify(selector)} within ${timeoutMs}ms: ${reason ?? "layout has not settled"}`);
|
|
254
263
|
});
|
|
255
264
|
}
|
|
256
265
|
async fill(selector, value) {
|
|
@@ -311,6 +320,35 @@ var BrowserPage = class {
|
|
|
311
320
|
* API: https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axerun
|
|
312
321
|
* No CDN, DOM script element, or application dependency is required.
|
|
313
322
|
*/
|
|
323
|
+
/**
|
|
324
|
+
* Measures the inline payload of the document the page currently shows and
|
|
325
|
+
* records it under `evidence.payloads`. Measure after a full load: a client
|
|
326
|
+
* navigation replaces the data it reads. Pass `limit` to mark an overage.
|
|
327
|
+
*/
|
|
328
|
+
async measurePayload(options = {}) {
|
|
329
|
+
return this.step(`measurePayload ${this.viewport.name}`, async () => {
|
|
330
|
+
const measured = await this.evaluate(`(() => {
|
|
331
|
+
const bytes = (id) => {
|
|
332
|
+
const node = document.getElementById(id);
|
|
333
|
+
return node === null ? 0 : new TextEncoder().encode(node.textContent || "").length;
|
|
334
|
+
};
|
|
335
|
+
return { url: location.href, data: bytes("__WARLOCK_DATA__"), routes: bytes("__WARLOCK_NAMED_API_ROUTES__") };
|
|
336
|
+
})()`, 1e4);
|
|
337
|
+
const total = measured.data + measured.routes;
|
|
338
|
+
const report = {
|
|
339
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
340
|
+
viewport: { ...this.viewport },
|
|
341
|
+
...measured,
|
|
342
|
+
total,
|
|
343
|
+
...options.limit === void 0 ? {} : {
|
|
344
|
+
limit: options.limit,
|
|
345
|
+
overBudget: total > options.limit
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
(this.evidence.payloads ??= []).push(report);
|
|
349
|
+
return report;
|
|
350
|
+
});
|
|
351
|
+
}
|
|
314
352
|
async assertAccessible(options = {}) {
|
|
315
353
|
return this.step(`assertAccessible ${this.viewport.name}`, async () => {
|
|
316
354
|
const source = await readFile(createRequire(import.meta.url).resolve("axe-core/axe.min.js"), "utf8");
|
package/esm/e2e/page.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.mjs","names":["delay"],"sources":["../../../../../../../../packages/core/src/e2e/page.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport { CdpConnection } from \"./cdp\";\nimport {\n type AccessibilityOptions,\n type AccessibilityEvidence,\n defaultViewports,\n errorMessage,\n matches,\n type E2EEvidence,\n type E2ESpec,\n type Viewport,\n} from \"./types\";\n\ntype WaitOptions = { selector?: string; text?: string; url?: string; timeoutMs?: number };\ntype ClickBox = { x: number; y: number; width: number; height: number; reason: string };\ntype ViewportReport = {\n requestedWidth: number;\n innerWidth: number;\n documentWidth: number;\n bodyWidth: number;\n offenders: {\n tag: string;\n id: string;\n className: string;\n width: number;\n scrollWidth: number;\n right: number;\n left: number;\n }[];\n};\n\n/** Runs inside the browser. Two paints plus cross-probe box comparison detect\n * scroll/animation/layout races. The hit test also accepts target descendants.\n */\nfunction clickProbe(selector: string): Promise<ClickBox> {\n return (async () => {\n const empty = (reason: string): ClickBox => ({ x: 0, y: 0, width: 0, height: 0, reason });\n const element = document.querySelector(selector);\n if (!(element instanceof HTMLElement || element instanceof SVGElement))\n return empty(\"target is missing or is not an HTML/SVG element\");\n element.scrollIntoView({ block: \"center\", inline: \"center\", behavior: \"instant\" });\n await new Promise<void>((resolve) =>\n requestAnimationFrame(() => requestAnimationFrame(() => resolve())),\n );\n if (!element.isConnected || document.querySelector(selector) !== element)\n return empty(\"target was replaced during layout\");\n const box = element.getBoundingClientRect();\n const x = box.x + box.width / 2;\n const y = box.y + box.height / 2;\n const style = getComputedStyle(element);\n let reason = \"\";\n if (\n box.width <= 0 ||\n box.height <= 0 ||\n style.visibility !== \"visible\" ||\n style.display === \"none\" ||\n Number(style.opacity) === 0\n )\n reason = \"target is hidden or has an empty box\";\n else if (element.matches(\":disabled\") || element.closest('[inert], [aria-disabled=\"true\"]'))\n reason = \"target is disabled or inert\";\n else if (x < 0 || y < 0 || x >= innerWidth || y >= innerHeight)\n reason = \"target center is outside the viewport\";\n else {\n const top = document.elementFromPoint(x, y);\n if (!top || !element.contains(top))\n reason = `target is covered by ${top?.tagName ?? \"no element\"}${top?.id ? \"#\" + top.id : \"\"}`;\n }\n return { x, y, width: box.width, height: box.height, reason };\n })();\n}\n\nexport function boxesStable(first: ClickBox, second: ClickBox): boolean {\n return (\n !first.reason &&\n !second.reason &&\n ([\"x\", \"y\", \"width\", \"height\"] as const).every(\n (key) => Math.abs(first[key] - second[key]) < 0.25,\n )\n );\n}\n\nexport class BrowserPage {\n private viewport: Viewport = { ...defaultViewports[0] };\n private loads = 0;\n private pendingRequests = new Map<string, string>();\n private requestUrls = new Map<string, string>();\n private lastNetworkActivity = Date.now();\n\n constructor(\n private cdp: CdpConnection,\n private origin: string,\n private outputDirectory: string,\n private evidence: E2EEvidence,\n private spec: E2ESpec,\n ) {\n cdp.on(\"Page.loadEventFired\", () => {\n this.loads++;\n });\n cdp.on(\"Runtime.consoleAPICalled\", ({ type, args }) =>\n evidence.console.push({\n at: new Date().toISOString(),\n level: type === \"assert\" ? \"error\" : type,\n text: args.map((arg) => String(arg.value ?? arg.description ?? \"\")).join(\" \"),\n }),\n );\n cdp.on(\"Runtime.exceptionThrown\", ({ exceptionDetails }) =>\n evidence.console.push({\n at: new Date().toISOString(),\n level: \"error\",\n text: exceptionDetails.exception?.description ?? exceptionDetails.text,\n }),\n );\n cdp.on(\"Log.entryAdded\", ({ entry }) =>\n evidence.console.push({ at: new Date().toISOString(), level: entry.level, text: entry.text }),\n );\n cdp.on(\"Network.requestWillBeSent\", ({ requestId, request }) => {\n this.pendingRequests.set(requestId, request.url);\n this.requestUrls.set(requestId, request.url);\n this.lastNetworkActivity = Date.now();\n });\n cdp.on(\"Network.responseReceived\", ({ requestId, response }) => {\n this.requestUrls.set(requestId, response.url);\n if (response.status >= 400)\n evidence.networkFailures.push({\n at: new Date().toISOString(),\n url: response.url,\n status: response.status,\n });\n });\n cdp.on(\"Network.loadingFailed\", ({ requestId, errorText, canceled }) => {\n evidence.networkFailures.push({\n at: new Date().toISOString(),\n url: this.requestUrls.get(requestId) ?? `unknown request ${requestId}`,\n errorText,\n canceled,\n });\n this.completeRequest(requestId);\n });\n cdp.on(\"Network.loadingFinished\", ({ requestId }) => this.completeRequest(requestId));\n }\n\n private completeRequest(requestId: string): void {\n this.pendingRequests.delete(requestId);\n this.requestUrls.delete(requestId);\n this.lastNetworkActivity = Date.now();\n }\n\n async initialize(): Promise<void> {\n await this.cdp.command(\"Page.enable\", {});\n await this.cdp.command(\"Runtime.enable\", {});\n await this.cdp.command(\"Network.enable\", {});\n await this.cdp.command(\"Log.enable\", {});\n await this.setViewport(this.spec.viewports?.[0] ?? defaultViewports[0]);\n }\n\n async step<T>(name: string, action: () => Promise<T>): Promise<T> {\n const start = performance.now();\n const entry = {\n name,\n startedAt: new Date().toISOString(),\n durationMs: 0,\n status: \"passed\" as \"passed\" | \"failed\",\n error: undefined as string | undefined,\n };\n this.evidence.steps.push(entry);\n try {\n return await action();\n } catch (error) {\n entry.status = \"failed\";\n entry.error = errorMessage(error);\n throw error;\n } finally {\n entry.durationMs = Math.round(performance.now() - start);\n }\n }\n\n async evaluate<T = unknown>(expression: string, timeoutMs = 10_000): Promise<T> {\n const response = await this.cdp.command(\n \"Runtime.evaluate\",\n { expression, returnByValue: true, awaitPromise: true, silent: true },\n timeoutMs,\n );\n if (response.exceptionDetails)\n throw new Error(\n `Browser evaluation failed: ${response.exceptionDetails.exception?.description ?? response.exceptionDetails.text}`,\n );\n return response.result.value as T;\n }\n\n private async poll(\n description: string,\n check: (remainingMs: number) => Promise<boolean>,\n timeoutMs: number,\n ): Promise<void> {\n const deadline = Date.now() + timeoutMs;\n let reason = \"condition stayed false\";\n while (Date.now() < deadline) {\n try {\n if (await check(Math.max(1, deadline - Date.now()))) return;\n } catch (error) {\n reason = errorMessage(error);\n }\n await delay(Math.min(50, Math.max(0, deadline - Date.now())));\n }\n throw new Error(`${description} timed out after ${timeoutMs}ms: ${reason}`);\n }\n\n async goto(path: string, timeoutMs = 10_000): Promise<void> {\n await this.step(`goto ${path}`, async () => {\n const url = new URL(path, this.origin).href;\n const before = this.loads;\n const navigation = await this.cdp.command(\"Page.navigate\", { url }, timeoutMs);\n if (navigation.errorText) throw new Error(`Navigation failed: ${navigation.errorText}`);\n await this.poll(\n `Navigation to ${url}`,\n (remaining) =>\n this.evaluate<boolean>(\n `document.readyState === 'complete' && ${navigation.loaderId ? this.loads > before : \"true\"}`,\n remaining,\n ),\n timeoutMs,\n );\n });\n }\n\n async waitFor(options: WaitOptions): Promise<void> {\n if (options.selector === undefined && options.text === undefined && options.url === undefined)\n throw new Error(\"waitFor requires a selector, text, or URL\");\n await this.step(`waitFor ${JSON.stringify(options)}`, () =>\n this.poll(\n \"waitFor \" + JSON.stringify(options),\n (remaining) =>\n this.evaluate<boolean>(\n `(() => {\n const options = ${JSON.stringify(options)};\n const element = options.selector ? document.querySelector(options.selector) : document.body;\n if (!element) return false;\n if (options.selector) { const box=element.getBoundingClientRect(); const css=getComputedStyle(element); if (!box.width || !box.height || css.visibility !== 'visible') return false; }\n return (options.text === undefined || (element.innerText ?? element.textContent ?? '').includes(options.text)) &&\n (options.url === undefined || location.href === new URL(options.url, ${JSON.stringify(this.origin)}).href);\n })()`,\n remaining,\n ),\n options.timeoutMs ?? 10_000,\n ),\n );\n }\n\n /** Arms the document/URL comparison BEFORE invoking the navigation action,\n * covering full loads, reloads, hash changes and client-side routing.\n */\n async waitForNavigation(\n action: () => Promise<unknown>,\n options: { url?: string; timeoutMs?: number } = {},\n ): Promise<void> {\n await this.step(\"waitForNavigation\", async () => {\n const before = await this.evaluate<{ href: string; timeOrigin: number }>(\n \"({href:location.href,timeOrigin:performance.timeOrigin})\",\n );\n await action();\n await this.poll(\n \"Navigation\",\n (remaining) =>\n this.evaluate<boolean>(\n `document.readyState === 'complete' && (location.href !== ${JSON.stringify(before.href)} || performance.timeOrigin !== ${before.timeOrigin}) && ${options.url ? `location.href === ${JSON.stringify(new URL(options.url, this.origin).href)}` : \"true\"}`,\n remaining,\n ),\n options.timeoutMs ?? 10_000,\n );\n });\n }\n\n async click(selector: string, timeoutMs = 10_000): Promise<void> {\n await this.step(`click ${selector}`, async () => {\n const deadline = Date.now() + timeoutMs;\n let previous: ClickBox | undefined;\n let reason = \"layout has not settled\";\n while (Date.now() < deadline) {\n const remaining = () => Math.max(1, deadline - Date.now());\n let box: ClickBox;\n try {\n box = await this.evaluate<ClickBox>(\n `(${clickProbe.toString()})(${JSON.stringify(selector)})`,\n remaining(),\n );\n } catch (error) {\n reason = errorMessage(error);\n previous = undefined;\n await delay(25);\n continue;\n }\n reason = box.reason || \"target box is moving\";\n if (previous && boxesStable(previous, box)) {\n // Hover can move menus and overlays. Re-measure and hit-test after it.\n let hovered: ClickBox;\n try {\n await this.cdp.command(\n \"Input.dispatchMouseEvent\",\n { type: \"mouseMoved\", x: box.x, y: box.y },\n remaining(),\n );\n hovered = await this.evaluate<ClickBox>(\n `(${clickProbe.toString()})(${JSON.stringify(selector)})`,\n remaining(),\n );\n } catch (error) {\n reason = errorMessage(error);\n previous = undefined;\n await delay(Math.min(25, remaining()));\n continue;\n }\n if (Date.now() < deadline && boxesStable(box, hovered)) {\n await this.cdp.command(\n \"Input.dispatchMouseEvent\",\n {\n type: \"mousePressed\",\n x: hovered.x,\n y: hovered.y,\n button: \"left\",\n buttons: 1,\n clickCount: 1,\n },\n remaining(),\n );\n await this.cdp.command(\n \"Input.dispatchMouseEvent\",\n {\n type: \"mouseReleased\",\n x: hovered.x,\n y: hovered.y,\n button: \"left\",\n buttons: 0,\n clickCount: 1,\n },\n remaining(),\n );\n return;\n }\n reason = hovered.reason || \"hover changed the target box\";\n previous = undefined;\n } else previous = box;\n await delay(Math.min(50, remaining()));\n }\n throw new Error(`Cannot click ${JSON.stringify(selector)} within ${timeoutMs}ms: ${reason}`);\n });\n }\n\n async fill(selector: string, value: string): Promise<void> {\n await this.step(`fill ${selector}`, async () => {\n await this.click(selector);\n // The native value setter works with controlled inputs; input/change are\n // emitted after clearing. CDP insertText then performs actual text input.\n await this.evaluate(`(() => {\n const element=document.querySelector(${JSON.stringify(selector)});\n if (element !== document.activeElement) throw new Error('Fill target lost focus');\n if ((element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) && !element.readOnly && !element.disabled) {\n const prototype=element instanceof HTMLInputElement ? HTMLInputElement.prototype : HTMLTextAreaElement.prototype;\n const setter=Object.getOwnPropertyDescriptor(prototype,'value')?.set;\n if (!setter) throw new Error('Fill target has no native value setter');\n setter.call(element,'');\n } else if (element instanceof HTMLElement && element.isContentEditable) element.textContent='';\n else throw new Error('Fill target must be an editable input, textarea or contenteditable');\n element.dispatchEvent(new Event('input',{bubbles:true}));\n })()`);\n await this.evaluate(\n `document.activeElement === document.querySelector(${JSON.stringify(selector)}) || (() => { throw new Error(\"Fill target lost focus after input\"); })()`,\n );\n if (value) await this.cdp.command(\"Input.insertText\", { text: value });\n await this.evaluate(\n \"document.activeElement?.dispatchEvent(new Event('change',{bubbles:true}))\",\n );\n });\n }\n\n /** Appends Unicode text through the browser's text-input path. */\n async type(selector: string, text: string): Promise<void> {\n await this.step(`type ${selector}`, async () => {\n await this.click(selector);\n const needsEndKey = await this.evaluate<boolean>(\n `(() => { const element=document.querySelector(${JSON.stringify(selector)}); if (element !== document.activeElement || !((element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) && !element.readOnly && !element.disabled || element instanceof HTMLElement && element.isContentEditable)) throw new Error('Type target is not focused and editable'); if(element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) { if (typeof element.selectionStart !== \"number\") return true; element.setSelectionRange(element.value.length,element.value.length); } else { const range=document.createRange(); range.selectNodeContents(element); range.collapse(false); const selection=getSelection(); selection?.removeAllRanges(); selection?.addRange(range); } return false; })()`,\n );\n // Email/number inputs do not expose selectionRange; use their native\n // keyboard editing path instead of throwing on setSelectionRange.\n if (needsEndKey) {\n await this.cdp.command(\"Input.dispatchKeyEvent\", {\n type: \"keyDown\",\n key: \"End\",\n code: \"End\",\n windowsVirtualKeyCode: 35,\n });\n await this.cdp.command(\"Input.dispatchKeyEvent\", {\n type: \"keyUp\",\n key: \"End\",\n code: \"End\",\n windowsVirtualKeyCode: 35,\n });\n }\n await this.cdp.command(\"Input.insertText\", { text });\n });\n }\n\n async setViewport(viewport: Viewport): Promise<void> {\n if (\n !/^[a-z0-9_-]+$/i.test(viewport.name) ||\n !Number.isInteger(viewport.width) ||\n !Number.isInteger(viewport.height) ||\n viewport.width <= 0 ||\n viewport.height <= 0\n )\n throw new Error(\"Viewport requires a safe name and positive integer width/height\");\n await this.step(`viewport ${viewport.name} ${viewport.width}x${viewport.height}`, async () => {\n await this.cdp.command(\"Emulation.setDeviceMetricsOverride\", {\n width: viewport.width,\n height: viewport.height,\n deviceScaleFactor: 1,\n mobile: viewport.mobile ?? false,\n });\n this.viewport = { ...viewport };\n await this.evaluate(\n \"new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(() => resolve(true))))\",\n );\n });\n }\n\n /** Inject the installed axe distribution through Runtime.evaluate on every scan.\n * API: https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axerun\n * No CDN, DOM script element, or application dependency is required.\n */\n async assertAccessible(options: AccessibilityOptions = {}): Promise<AccessibilityEvidence> {\n return this.step(`assertAccessible ${this.viewport.name}`, async () => {\n const source = await readFile(\n createRequire(import.meta.url).resolve(\"axe-core/axe.min.js\"),\n \"utf8\",\n );\n const timeout = options.timeoutMs ?? 30_000;\n await this.evaluate(source, timeout);\n const result = await this.evaluate<\n Pick<AccessibilityEvidence, \"url\" | \"violations\" | \"incomplete\">\n >(\n `(async () => {\n const selector = ${JSON.stringify(options.selector ?? null)};\n const context = selector === null ? document : document.querySelector(selector);\n if (!context) throw new Error('Accessibility scan selector did not match: ' + selector);\n const results = await axe.run(context, ${JSON.stringify(options.tags ? { runOnly: { type: \"tag\", values: options.tags } } : {})});\n const summarize = entries => entries.map(({id, impact, help, helpUrl, nodes}) => ({\n id, impact, help, helpUrl, nodes: nodes.map(({target, failureSummary}) => ({target, failureSummary}))\n }));\n return {url: location.href, violations: summarize(results.violations), incomplete: summarize(results.incomplete)};\n })()`,\n timeout,\n );\n for (const violation of result.violations) {\n for (const node of violation.nodes) {\n node.allowed =\n options.allow?.some(\n (rule) =>\n rule.id === violation.id &&\n (rule.selector === undefined ||\n (node.target.length === 1 && node.target[0] === rule.selector)),\n ) ?? false;\n }\n }\n const report = { at: new Date().toISOString(), viewport: { ...this.viewport }, ...result };\n (this.evidence.accessibility ??= []).push(report);\n const failures = report.violations.flatMap((violation) =>\n violation.nodes\n .filter((node) => !node.allowed)\n .map((node) => `${violation.id}: ${JSON.stringify(node.target)} — ${violation.help}`),\n );\n if (failures.length) throw new Error(`Accessibility violations:\\n${failures.join(\"\\n\")}`);\n return report;\n });\n }\n\n async assertViewport(): Promise<ViewportReport> {\n return this.step(`assertViewport ${this.viewport.name}`, async () => {\n const report = await this.evaluate<ViewportReport>(`({\n requestedWidth:${this.viewport.width},innerWidth,documentWidth:document.documentElement.scrollWidth,bodyWidth:document.body?.scrollWidth ?? 0,\n offenders:[...document.querySelectorAll('*')].map(element=>{const box=element.getBoundingClientRect();return {tag:element.tagName,id:element.id,className:element.getAttribute('class')??'',width:box.width,scrollWidth:element.scrollWidth,right:box.right,left:box.left}})\n .filter(element=>element.right>${this.viewport.width} || element.left<0 || element.width>${this.viewport.width} || element.scrollWidth>${this.viewport.width})\n .sort((a,b)=>Math.max(b.width,b.scrollWidth,b.right)-Math.max(a.width,a.scrollWidth,a.right)).slice(0,10)\n })`);\n if (\n report.innerWidth !== report.requestedWidth ||\n report.documentWidth > report.requestedWidth ||\n report.bodyWidth > report.requestedWidth\n )\n throw new Error(\n `Horizontal overflow or expanded viewport at ${this.viewport.name}: ${JSON.stringify(report)}`,\n );\n return report;\n });\n }\n\n async screenshot(name: string): Promise<string> {\n if (!/^[a-z0-9_-]+$/i.test(name))\n throw new Error(\"Screenshot names must contain only letters, digits, '_' or '-'\");\n return this.step(`screenshot ${name}`, async () => {\n const file = `${String(this.evidence.screenshots.length + 1).padStart(3, \"0\")}-${name}-${this.viewport.name}.png`;\n const { data } = await this.cdp.command(\"Page.captureScreenshot\", { format: \"png\" });\n await writeFile(join(this.outputDirectory, file), Buffer.from(data, \"base64\"));\n this.evidence.screenshots.push({ name, file, viewport: { ...this.viewport } });\n return join(this.outputDirectory, file);\n });\n }\n\n async captureViewports(\n name: string,\n viewports = this.spec.viewports ?? defaultViewports,\n ): Promise<void> {\n const failures: unknown[] = [];\n const original = this.viewport;\n for (const viewport of viewports) {\n try {\n await this.setViewport(viewport);\n try {\n await this.assertViewport();\n } finally {\n await this.screenshot(name);\n }\n } catch (error) {\n failures.push(error);\n }\n }\n try {\n await this.setViewport(original);\n } catch (error) {\n failures.push(error);\n }\n if (failures.length) throw new AggregateError(failures, failures.map(errorMessage).join(\"; \"));\n }\n\n async waitForNetworkIdle(timeoutMs = 10_000): Promise<void> {\n await this.step(\"waitForNetworkIdle\", () =>\n this.poll(\n \"Network idle\",\n async () => {\n const pending = [...this.pendingRequests.values()].filter(\n (url) => !this.spec.allowPendingRequests?.some((pattern) => matches(pattern, url)),\n );\n if (pending.length) throw new Error(`Pending requests: ${pending.join(\", \")}`);\n return Date.now() - this.lastNetworkActivity >= 300;\n },\n timeoutMs,\n ),\n );\n }\n\n assertHealthy(): void {\n for (const entry of this.evidence.console)\n if (entry.level === \"error\")\n entry.allowed =\n this.spec.allowConsoleErrors?.some((pattern) => matches(pattern, entry.text)) ?? false;\n for (const entry of this.evidence.networkFailures)\n entry.allowed =\n this.spec.allowNetworkFailures?.some(\n (rule) =>\n matches(rule.url, entry.url) &&\n (rule.status === undefined || rule.status === entry.status) &&\n (rule.errorText === undefined || matches(rule.errorText, entry.errorText ?? \"\")),\n ) ?? false;\n const consoleErrors = this.evidence.console.filter(\n (entry) => entry.level === \"error\" && !entry.allowed,\n );\n const networkErrors = this.evidence.networkFailures.filter((entry) => !entry.allowed);\n if (consoleErrors.length || networkErrors.length)\n throw new Error(\n `Browser health failed: ${consoleErrors.length} console errors, ${networkErrors.length} failed HTTP/network requests\\n${JSON.stringify({ console: consoleErrors, network: networkErrors })}`,\n );\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"page.mjs","names":["delay"],"sources":["../../../../../../../../packages/core/src/e2e/page.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { setTimeout as delay } from \"node:timers/promises\";\nimport { CdpConnection, CdpTimeoutError } from \"./cdp\";\nimport {\n type AccessibilityOptions,\n type AccessibilityEvidence,\n defaultViewports,\n errorMessage,\n matches,\n type E2EEvidence,\n type E2ESpec,\n type PayloadEvidence,\n type Viewport,\n} from \"./types\";\n\ntype WaitOptions = { selector?: string; text?: string; url?: string; timeoutMs?: number };\ntype ClickBox = { x: number; y: number; width: number; height: number; reason: string };\ntype ViewportReport = {\n requestedWidth: number;\n innerWidth: number;\n documentWidth: number;\n bodyWidth: number;\n offenders: {\n tag: string;\n id: string;\n className: string;\n width: number;\n scrollWidth: number;\n right: number;\n left: number;\n }[];\n};\n\n/** Runs inside the browser. Two paints plus cross-probe box comparison detect\n * scroll/animation/layout races. The hit test also accepts target descendants.\n */\nfunction clickProbe(selector: string): Promise<ClickBox> {\n return (async () => {\n const empty = (reason: string): ClickBox => ({ x: 0, y: 0, width: 0, height: 0, reason });\n const element = document.querySelector(selector);\n if (!(element instanceof HTMLElement || element instanceof SVGElement))\n return empty(\"target is missing or is not an HTML/SVG element\");\n element.scrollIntoView({ block: \"center\", inline: \"center\", behavior: \"instant\" });\n await new Promise<void>((resolve) =>\n requestAnimationFrame(() => requestAnimationFrame(() => resolve())),\n );\n if (!element.isConnected || document.querySelector(selector) !== element)\n return empty(\"target was replaced during layout\");\n const box = element.getBoundingClientRect();\n const x = box.x + box.width / 2;\n const y = box.y + box.height / 2;\n const style = getComputedStyle(element);\n let reason = \"\";\n if (\n box.width <= 0 ||\n box.height <= 0 ||\n style.visibility !== \"visible\" ||\n style.display === \"none\" ||\n Number(style.opacity) === 0\n )\n reason = \"target is hidden or has an empty box\";\n else if (element.matches(\":disabled\") || element.closest('[inert], [aria-disabled=\"true\"]'))\n reason = \"target is disabled or inert\";\n else if (x < 0 || y < 0 || x >= innerWidth || y >= innerHeight)\n reason = \"target center is outside the viewport\";\n else {\n const top = document.elementFromPoint(x, y);\n if (!top || !element.contains(top))\n reason = `target is covered by ${top?.tagName ?? \"no element\"}${top?.id ? \"#\" + top.id : \"\"}`;\n }\n return { x, y, width: box.width, height: box.height, reason };\n })();\n}\n\nexport function boxesStable(first: ClickBox, second: ClickBox): boolean {\n return (\n !first.reason &&\n !second.reason &&\n ([\"x\", \"y\", \"width\", \"height\"] as const).every(\n (key) => Math.abs(first[key] - second[key]) < 0.25,\n )\n );\n}\n\n/** Reason to report after a failed probe in a retry loop. A CDP timeout comes from\n * the deadline shrinking under the probe, not from the target, so it must not\n * replace a reason already observed on the target. Any other error is reported.\n */\nfunction probeReason(error: unknown, observed: string | undefined): string {\n if (error instanceof CdpTimeoutError && observed !== undefined) return observed;\n return errorMessage(error);\n}\n\nexport class BrowserPage {\n private viewport: Viewport = { ...defaultViewports[0] };\n private loads = 0;\n private pendingRequests = new Map<string, string>();\n private requestUrls = new Map<string, string>();\n private lastNetworkActivity = Date.now();\n\n constructor(\n private cdp: CdpConnection,\n private origin: string,\n private outputDirectory: string,\n private evidence: E2EEvidence,\n private spec: E2ESpec,\n ) {\n cdp.on(\"Page.loadEventFired\", () => {\n this.loads++;\n });\n cdp.on(\"Runtime.consoleAPICalled\", ({ type, args }) =>\n evidence.console.push({\n at: new Date().toISOString(),\n level: type === \"assert\" ? \"error\" : type,\n text: args.map((arg) => String(arg.value ?? arg.description ?? \"\")).join(\" \"),\n }),\n );\n cdp.on(\"Runtime.exceptionThrown\", ({ exceptionDetails }) =>\n evidence.console.push({\n at: new Date().toISOString(),\n level: \"error\",\n text: exceptionDetails.exception?.description ?? exceptionDetails.text,\n }),\n );\n cdp.on(\"Log.entryAdded\", ({ entry }) =>\n evidence.console.push({ at: new Date().toISOString(), level: entry.level, text: entry.text }),\n );\n cdp.on(\"Network.requestWillBeSent\", ({ requestId, request }) => {\n this.pendingRequests.set(requestId, request.url);\n this.requestUrls.set(requestId, request.url);\n this.lastNetworkActivity = Date.now();\n });\n cdp.on(\"Network.responseReceived\", ({ requestId, response }) => {\n this.requestUrls.set(requestId, response.url);\n if (response.status >= 400)\n evidence.networkFailures.push({\n at: new Date().toISOString(),\n url: response.url,\n status: response.status,\n });\n });\n cdp.on(\"Network.loadingFailed\", ({ requestId, errorText, canceled }) => {\n evidence.networkFailures.push({\n at: new Date().toISOString(),\n url: this.requestUrls.get(requestId) ?? `unknown request ${requestId}`,\n errorText,\n canceled,\n });\n this.completeRequest(requestId);\n });\n cdp.on(\"Network.loadingFinished\", ({ requestId }) => this.completeRequest(requestId));\n }\n\n private completeRequest(requestId: string): void {\n this.pendingRequests.delete(requestId);\n this.requestUrls.delete(requestId);\n this.lastNetworkActivity = Date.now();\n }\n\n async initialize(): Promise<void> {\n await this.cdp.command(\"Page.enable\", {});\n await this.cdp.command(\"Runtime.enable\", {});\n await this.cdp.command(\"Network.enable\", {});\n await this.cdp.command(\"Log.enable\", {});\n await this.setViewport(this.spec.viewports?.[0] ?? defaultViewports[0]);\n }\n\n async step<T>(name: string, action: () => Promise<T>): Promise<T> {\n const start = performance.now();\n const entry = {\n name,\n startedAt: new Date().toISOString(),\n durationMs: 0,\n status: \"passed\" as \"passed\" | \"failed\",\n error: undefined as string | undefined,\n };\n this.evidence.steps.push(entry);\n try {\n return await action();\n } catch (error) {\n entry.status = \"failed\";\n entry.error = errorMessage(error);\n throw error;\n } finally {\n entry.durationMs = Math.round(performance.now() - start);\n }\n }\n\n async evaluate<T = unknown>(expression: string, timeoutMs = 10_000): Promise<T> {\n const response = await this.cdp.command(\n \"Runtime.evaluate\",\n { expression, returnByValue: true, awaitPromise: true, silent: true },\n timeoutMs,\n );\n if (response.exceptionDetails)\n throw new Error(\n `Browser evaluation failed: ${response.exceptionDetails.exception?.description ?? response.exceptionDetails.text}`,\n );\n return response.result.value as T;\n }\n\n private async poll(\n description: string,\n check: (remainingMs: number) => Promise<boolean>,\n timeoutMs: number,\n ): Promise<void> {\n const deadline = Date.now() + timeoutMs;\n let reason: string | undefined;\n while (Date.now() < deadline) {\n try {\n if (await check(Math.max(1, deadline - Date.now()))) return;\n } catch (error) {\n reason = probeReason(error, reason);\n }\n await delay(Math.min(50, Math.max(0, deadline - Date.now())));\n }\n throw new Error(\n `${description} timed out after ${timeoutMs}ms: ${reason ?? \"condition stayed false\"}`,\n );\n }\n\n async goto(path: string, timeoutMs = 10_000): Promise<void> {\n await this.step(`goto ${path}`, async () => {\n const url = new URL(path, this.origin).href;\n const before = this.loads;\n const navigation = await this.cdp.command(\"Page.navigate\", { url }, timeoutMs);\n if (navigation.errorText) throw new Error(`Navigation failed: ${navigation.errorText}`);\n await this.poll(\n `Navigation to ${url}`,\n (remaining) =>\n this.evaluate<boolean>(\n `document.readyState === 'complete' && ${navigation.loaderId ? this.loads > before : \"true\"}`,\n remaining,\n ),\n timeoutMs,\n );\n });\n }\n\n async waitFor(options: WaitOptions): Promise<void> {\n if (options.selector === undefined && options.text === undefined && options.url === undefined)\n throw new Error(\"waitFor requires a selector, text, or URL\");\n await this.step(`waitFor ${JSON.stringify(options)}`, () =>\n this.poll(\n \"waitFor \" + JSON.stringify(options),\n (remaining) =>\n this.evaluate<boolean>(\n `(() => {\n const options = ${JSON.stringify(options)};\n const element = options.selector ? document.querySelector(options.selector) : document.body;\n if (!element) return false;\n if (options.selector) { const box=element.getBoundingClientRect(); const css=getComputedStyle(element); if (!box.width || !box.height || css.visibility !== 'visible') return false; }\n return (options.text === undefined || (element.innerText ?? element.textContent ?? '').includes(options.text)) &&\n (options.url === undefined || location.href === new URL(options.url, ${JSON.stringify(this.origin)}).href);\n })()`,\n remaining,\n ),\n options.timeoutMs ?? 10_000,\n ),\n );\n }\n\n /** Arms the document/URL comparison BEFORE invoking the navigation action,\n * covering full loads, reloads, hash changes and client-side routing.\n */\n async waitForNavigation(\n action: () => Promise<unknown>,\n options: { url?: string; timeoutMs?: number } = {},\n ): Promise<void> {\n await this.step(\"waitForNavigation\", async () => {\n const before = await this.evaluate<{ href: string; timeOrigin: number }>(\n \"({href:location.href,timeOrigin:performance.timeOrigin})\",\n );\n await action();\n await this.poll(\n \"Navigation\",\n (remaining) =>\n this.evaluate<boolean>(\n `document.readyState === 'complete' && (location.href !== ${JSON.stringify(before.href)} || performance.timeOrigin !== ${before.timeOrigin}) && ${options.url ? `location.href === ${JSON.stringify(new URL(options.url, this.origin).href)}` : \"true\"}`,\n remaining,\n ),\n options.timeoutMs ?? 10_000,\n );\n });\n }\n\n async click(selector: string, timeoutMs = 10_000): Promise<void> {\n await this.step(`click ${selector}`, async () => {\n const deadline = Date.now() + timeoutMs;\n let previous: ClickBox | undefined;\n let reason: string | undefined;\n while (Date.now() < deadline) {\n const remaining = () => Math.max(1, deadline - Date.now());\n let box: ClickBox;\n try {\n box = await this.evaluate<ClickBox>(\n `(${clickProbe.toString()})(${JSON.stringify(selector)})`,\n remaining(),\n );\n } catch (error) {\n reason = probeReason(error, reason);\n previous = undefined;\n await delay(25);\n continue;\n }\n reason = box.reason || \"target box is moving\";\n if (previous && boxesStable(previous, box)) {\n // Hover can move menus and overlays. Re-measure and hit-test after it.\n let hovered: ClickBox;\n try {\n await this.cdp.command(\n \"Input.dispatchMouseEvent\",\n { type: \"mouseMoved\", x: box.x, y: box.y },\n remaining(),\n );\n hovered = await this.evaluate<ClickBox>(\n `(${clickProbe.toString()})(${JSON.stringify(selector)})`,\n remaining(),\n );\n } catch (error) {\n reason = probeReason(error, reason);\n previous = undefined;\n await delay(Math.min(25, remaining()));\n continue;\n }\n if (Date.now() < deadline && boxesStable(box, hovered)) {\n await this.cdp.command(\n \"Input.dispatchMouseEvent\",\n {\n type: \"mousePressed\",\n x: hovered.x,\n y: hovered.y,\n button: \"left\",\n buttons: 1,\n clickCount: 1,\n },\n remaining(),\n );\n await this.cdp.command(\n \"Input.dispatchMouseEvent\",\n {\n type: \"mouseReleased\",\n x: hovered.x,\n y: hovered.y,\n button: \"left\",\n buttons: 0,\n clickCount: 1,\n },\n remaining(),\n );\n return;\n }\n reason = hovered.reason || \"hover changed the target box\";\n previous = undefined;\n } else previous = box;\n await delay(Math.min(50, remaining()));\n }\n throw new Error(\n `Cannot click ${JSON.stringify(selector)} within ${timeoutMs}ms: ${reason ?? \"layout has not settled\"}`,\n );\n });\n }\n\n async fill(selector: string, value: string): Promise<void> {\n await this.step(`fill ${selector}`, async () => {\n await this.click(selector);\n // The native value setter works with controlled inputs; input/change are\n // emitted after clearing. CDP insertText then performs actual text input.\n await this.evaluate(`(() => {\n const element=document.querySelector(${JSON.stringify(selector)});\n if (element !== document.activeElement) throw new Error('Fill target lost focus');\n if ((element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) && !element.readOnly && !element.disabled) {\n const prototype=element instanceof HTMLInputElement ? HTMLInputElement.prototype : HTMLTextAreaElement.prototype;\n const setter=Object.getOwnPropertyDescriptor(prototype,'value')?.set;\n if (!setter) throw new Error('Fill target has no native value setter');\n setter.call(element,'');\n } else if (element instanceof HTMLElement && element.isContentEditable) element.textContent='';\n else throw new Error('Fill target must be an editable input, textarea or contenteditable');\n element.dispatchEvent(new Event('input',{bubbles:true}));\n })()`);\n await this.evaluate(\n `document.activeElement === document.querySelector(${JSON.stringify(selector)}) || (() => { throw new Error(\"Fill target lost focus after input\"); })()`,\n );\n if (value) await this.cdp.command(\"Input.insertText\", { text: value });\n await this.evaluate(\n \"document.activeElement?.dispatchEvent(new Event('change',{bubbles:true}))\",\n );\n });\n }\n\n /** Appends Unicode text through the browser's text-input path. */\n async type(selector: string, text: string): Promise<void> {\n await this.step(`type ${selector}`, async () => {\n await this.click(selector);\n const needsEndKey = await this.evaluate<boolean>(\n `(() => { const element=document.querySelector(${JSON.stringify(selector)}); if (element !== document.activeElement || !((element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) && !element.readOnly && !element.disabled || element instanceof HTMLElement && element.isContentEditable)) throw new Error('Type target is not focused and editable'); if(element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) { if (typeof element.selectionStart !== \"number\") return true; element.setSelectionRange(element.value.length,element.value.length); } else { const range=document.createRange(); range.selectNodeContents(element); range.collapse(false); const selection=getSelection(); selection?.removeAllRanges(); selection?.addRange(range); } return false; })()`,\n );\n // Email/number inputs do not expose selectionRange; use their native\n // keyboard editing path instead of throwing on setSelectionRange.\n if (needsEndKey) {\n await this.cdp.command(\"Input.dispatchKeyEvent\", {\n type: \"keyDown\",\n key: \"End\",\n code: \"End\",\n windowsVirtualKeyCode: 35,\n });\n await this.cdp.command(\"Input.dispatchKeyEvent\", {\n type: \"keyUp\",\n key: \"End\",\n code: \"End\",\n windowsVirtualKeyCode: 35,\n });\n }\n await this.cdp.command(\"Input.insertText\", { text });\n });\n }\n\n async setViewport(viewport: Viewport): Promise<void> {\n if (\n !/^[a-z0-9_-]+$/i.test(viewport.name) ||\n !Number.isInteger(viewport.width) ||\n !Number.isInteger(viewport.height) ||\n viewport.width <= 0 ||\n viewport.height <= 0\n )\n throw new Error(\"Viewport requires a safe name and positive integer width/height\");\n await this.step(`viewport ${viewport.name} ${viewport.width}x${viewport.height}`, async () => {\n await this.cdp.command(\"Emulation.setDeviceMetricsOverride\", {\n width: viewport.width,\n height: viewport.height,\n deviceScaleFactor: 1,\n mobile: viewport.mobile ?? false,\n });\n this.viewport = { ...viewport };\n await this.evaluate(\n \"new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(() => resolve(true))))\",\n );\n });\n }\n\n /** Inject the installed axe distribution through Runtime.evaluate on every scan.\n * API: https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axerun\n * No CDN, DOM script element, or application dependency is required.\n */\n /**\n * Measures the inline payload of the document the page currently shows and\n * records it under `evidence.payloads`. Measure after a full load: a client\n * navigation replaces the data it reads. Pass `limit` to mark an overage.\n */\n async measurePayload(options: { limit?: number } = {}): Promise<PayloadEvidence> {\n return this.step(`measurePayload ${this.viewport.name}`, async () => {\n const measured = await this.evaluate<Pick<PayloadEvidence, \"url\" | \"data\" | \"routes\">>(\n `(() => {\n const bytes = (id) => {\n const node = document.getElementById(id);\n return node === null ? 0 : new TextEncoder().encode(node.textContent || \"\").length;\n };\n return { url: location.href, data: bytes(\"__WARLOCK_DATA__\"), routes: bytes(\"__WARLOCK_NAMED_API_ROUTES__\") };\n })()`,\n 10_000,\n );\n const total = measured.data + measured.routes;\n const report: PayloadEvidence = {\n at: new Date().toISOString(),\n viewport: { ...this.viewport },\n ...measured,\n total,\n ...(options.limit === undefined\n ? {}\n : { limit: options.limit, overBudget: total > options.limit }),\n };\n (this.evidence.payloads ??= []).push(report);\n return report;\n });\n }\n\n async assertAccessible(options: AccessibilityOptions = {}): Promise<AccessibilityEvidence> {\n return this.step(`assertAccessible ${this.viewport.name}`, async () => {\n const source = await readFile(\n createRequire(import.meta.url).resolve(\"axe-core/axe.min.js\"),\n \"utf8\",\n );\n const timeout = options.timeoutMs ?? 30_000;\n await this.evaluate(source, timeout);\n const result = await this.evaluate<\n Pick<AccessibilityEvidence, \"url\" | \"violations\" | \"incomplete\">\n >(\n `(async () => {\n const selector = ${JSON.stringify(options.selector ?? null)};\n const context = selector === null ? document : document.querySelector(selector);\n if (!context) throw new Error('Accessibility scan selector did not match: ' + selector);\n const results = await axe.run(context, ${JSON.stringify(options.tags ? { runOnly: { type: \"tag\", values: options.tags } } : {})});\n const summarize = entries => entries.map(({id, impact, help, helpUrl, nodes}) => ({\n id, impact, help, helpUrl, nodes: nodes.map(({target, failureSummary}) => ({target, failureSummary}))\n }));\n return {url: location.href, violations: summarize(results.violations), incomplete: summarize(results.incomplete)};\n })()`,\n timeout,\n );\n for (const violation of result.violations) {\n for (const node of violation.nodes) {\n node.allowed =\n options.allow?.some(\n (rule) =>\n rule.id === violation.id &&\n (rule.selector === undefined ||\n (node.target.length === 1 && node.target[0] === rule.selector)),\n ) ?? false;\n }\n }\n const report = { at: new Date().toISOString(), viewport: { ...this.viewport }, ...result };\n (this.evidence.accessibility ??= []).push(report);\n const failures = report.violations.flatMap((violation) =>\n violation.nodes\n .filter((node) => !node.allowed)\n .map((node) => `${violation.id}: ${JSON.stringify(node.target)} — ${violation.help}`),\n );\n if (failures.length) throw new Error(`Accessibility violations:\\n${failures.join(\"\\n\")}`);\n return report;\n });\n }\n\n async assertViewport(): Promise<ViewportReport> {\n return this.step(`assertViewport ${this.viewport.name}`, async () => {\n const report = await this.evaluate<ViewportReport>(`({\n requestedWidth:${this.viewport.width},innerWidth,documentWidth:document.documentElement.scrollWidth,bodyWidth:document.body?.scrollWidth ?? 0,\n offenders:[...document.querySelectorAll('*')].map(element=>{const box=element.getBoundingClientRect();return {tag:element.tagName,id:element.id,className:element.getAttribute('class')??'',width:box.width,scrollWidth:element.scrollWidth,right:box.right,left:box.left}})\n .filter(element=>element.right>${this.viewport.width} || element.left<0 || element.width>${this.viewport.width} || element.scrollWidth>${this.viewport.width})\n .sort((a,b)=>Math.max(b.width,b.scrollWidth,b.right)-Math.max(a.width,a.scrollWidth,a.right)).slice(0,10)\n })`);\n if (\n report.innerWidth !== report.requestedWidth ||\n report.documentWidth > report.requestedWidth ||\n report.bodyWidth > report.requestedWidth\n )\n throw new Error(\n `Horizontal overflow or expanded viewport at ${this.viewport.name}: ${JSON.stringify(report)}`,\n );\n return report;\n });\n }\n\n async screenshot(name: string): Promise<string> {\n if (!/^[a-z0-9_-]+$/i.test(name))\n throw new Error(\"Screenshot names must contain only letters, digits, '_' or '-'\");\n return this.step(`screenshot ${name}`, async () => {\n const file = `${String(this.evidence.screenshots.length + 1).padStart(3, \"0\")}-${name}-${this.viewport.name}.png`;\n const { data } = await this.cdp.command(\"Page.captureScreenshot\", { format: \"png\" });\n await writeFile(join(this.outputDirectory, file), Buffer.from(data, \"base64\"));\n this.evidence.screenshots.push({ name, file, viewport: { ...this.viewport } });\n return join(this.outputDirectory, file);\n });\n }\n\n async captureViewports(\n name: string,\n viewports = this.spec.viewports ?? defaultViewports,\n ): Promise<void> {\n const failures: unknown[] = [];\n const original = this.viewport;\n for (const viewport of viewports) {\n try {\n await this.setViewport(viewport);\n try {\n await this.assertViewport();\n } finally {\n await this.screenshot(name);\n }\n } catch (error) {\n failures.push(error);\n }\n }\n try {\n await this.setViewport(original);\n } catch (error) {\n failures.push(error);\n }\n if (failures.length) throw new AggregateError(failures, failures.map(errorMessage).join(\"; \"));\n }\n\n async waitForNetworkIdle(timeoutMs = 10_000): Promise<void> {\n await this.step(\"waitForNetworkIdle\", () =>\n this.poll(\n \"Network idle\",\n async () => {\n const pending = [...this.pendingRequests.values()].filter(\n (url) => !this.spec.allowPendingRequests?.some((pattern) => matches(pattern, url)),\n );\n if (pending.length) throw new Error(`Pending requests: ${pending.join(\", \")}`);\n return Date.now() - this.lastNetworkActivity >= 300;\n },\n timeoutMs,\n ),\n );\n }\n\n assertHealthy(): void {\n for (const entry of this.evidence.console)\n if (entry.level === \"error\")\n entry.allowed =\n this.spec.allowConsoleErrors?.some((pattern) => matches(pattern, entry.text)) ?? false;\n for (const entry of this.evidence.networkFailures)\n entry.allowed =\n this.spec.allowNetworkFailures?.some(\n (rule) =>\n matches(rule.url, entry.url) &&\n (rule.status === undefined || rule.status === entry.status) &&\n (rule.errorText === undefined || matches(rule.errorText, entry.errorText ?? \"\")),\n ) ?? false;\n const consoleErrors = this.evidence.console.filter(\n (entry) => entry.level === \"error\" && !entry.allowed,\n );\n const networkErrors = this.evidence.networkFailures.filter((entry) => !entry.allowed);\n if (consoleErrors.length || networkErrors.length)\n throw new Error(\n `Browser health failed: ${consoleErrors.length} console errors, ${networkErrors.length} failed HTTP/network requests\\n${JSON.stringify({ console: consoleErrors, network: networkErrors })}`,\n );\n }\n}\n"],"mappings":"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"}
|
package/esm/e2e/types.d.mts
CHANGED
|
@@ -108,6 +108,23 @@ export type AccessibilityEvidence = {
|
|
|
108
108
|
violations: AccessibilityViolation[];
|
|
109
109
|
incomplete: AccessibilityViolation[];
|
|
110
110
|
};
|
|
111
|
+
/**
|
|
112
|
+
* The inline payload of one loaded document, in bytes as the HTML carries it:
|
|
113
|
+
* the hydration data script and the browser route table. `limit` and
|
|
114
|
+
* `overBudget` are present when the caller passed a limit to `measurePayload`.
|
|
115
|
+
*/
|
|
116
|
+
export type PayloadEvidence = {
|
|
117
|
+
at: string;
|
|
118
|
+
url: string;
|
|
119
|
+
viewport: Viewport;
|
|
120
|
+
/** The `__WARLOCK_DATA__` script: page, layout and app data, translations, session. */
|
|
121
|
+
data: number;
|
|
122
|
+
/** The `__WARLOCK_NAMED_API_ROUTES__` script: the page's browser route table. */
|
|
123
|
+
routes: number;
|
|
124
|
+
total: number;
|
|
125
|
+
limit?: number;
|
|
126
|
+
overBudget?: boolean;
|
|
127
|
+
};
|
|
111
128
|
export type E2EEvidence = {
|
|
112
129
|
schemaVersion: 1;
|
|
113
130
|
startedAt: string;
|
|
@@ -123,6 +140,7 @@ export type E2EEvidence = {
|
|
|
123
140
|
viewport: Viewport;
|
|
124
141
|
}[];
|
|
125
142
|
accessibility?: AccessibilityEvidence[];
|
|
143
|
+
payloads?: PayloadEvidence[];
|
|
126
144
|
processes: ProcessEvidence[];
|
|
127
145
|
errors: string[];
|
|
128
146
|
};
|
package/esm/e2e/types.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","names":[],"sources":["../../../../../../../../packages/core/src/e2e/types.ts"],"mappings":";;YAEY,oBAAoB,uBAAuB;YAC3C,mBAAmB;YACnB;EAAa;EAAc;EAAe;EAAgB;;qBACzD,2BAA2B;YAK5B;;EAEV;EACA;;EAEA;EACA;;EAEA;;YAEU;EACV;;EAEA,QAAQ,YAAY,SAAS,mBAAmB;;EAEhD,QAAQ,YAAY,SAAS,mBAAmB;;EAEhD,MAAM,2BAA2B,SAAS,mBAAmB;;EAE7D;;EAEA,WAAW,SAAS,0BAA0B;;EAE9C;EACA;;EAEA;EACA;;YAEU;EACV;;EAEA;;;;;;EAMA;;YAEU;EACV;EACA;EACA;EACA;EACA;EACA;;YAEU;EAAiB;EAAY;EAAe;EAAc;;YAC1D;EACV;EACA;EACA;EACA;EACA;;YAEU;EACV;EACA;EACA;EACA;EACA;EACA;;YAEU;;EAEV;;EAEA;;EAEA;IAAU;IAAY;;EACtB;;YAEU;EACV;EACA;EACA;EACA;EACA;IAAS;IAA+B;IAAyB;;;YAEvD;EACV;EACA;EACA,UAAU;EACV,YAAY;EACZ,YAAY;;
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../../../../../../../../packages/core/src/e2e/types.ts"],"mappings":";;YAEY,oBAAoB,uBAAuB;YAC3C,mBAAmB;YACnB;EAAa;EAAc;EAAe;EAAgB;;qBACzD,2BAA2B;YAK5B;;EAEV;EACA;;EAEA;EACA;;EAEA;;YAEU;EACV;;EAEA,QAAQ,YAAY,SAAS,mBAAmB;;EAEhD,QAAQ,YAAY,SAAS,mBAAmB;;EAEhD,MAAM,2BAA2B,SAAS,mBAAmB;;EAE7D;;EAEA,WAAW,SAAS,0BAA0B;;EAE9C;EACA;;EAEA;EACA;;YAEU;EACV;;EAEA;;;;;;EAMA;;YAEU;EACV;EACA;EACA;EACA;EACA;EACA;;YAEU;EAAiB;EAAY;EAAe;EAAc;;YAC1D;EACV;EACA;EACA;EACA;EACA;;YAEU;EACV;EACA;EACA;EACA;EACA;EACA;;YAEU;;EAEV;;EAEA;;EAEA;IAAU;IAAY;;EACtB;;YAEU;EACV;EACA;EACA;EACA;EACA;IAAS;IAA+B;IAAyB;;;YAEvD;EACV;EACA;EACA,UAAU;EACV,YAAY;EACZ,YAAY;;;;;;;YAOF;EACV;EACA;EACA,UAAU;;EAEV;;EAEA;EACA;EACA;EACA;;YAEU;EACV;EACA;EACA;EACA;EACA;EACA,OAAO;EACP,SAAS;EACT,iBAAiB;EACjB;IAAe;IAAc;IAAc,UAAU;;EACrD,gBAAgB;EAChB,WAAW;EACX,WAAW;EACX;;YAEU;EAAqB,KAAK;EAAS;EAAiB,YAAY;;YAChE,aAAa;EACvB,MAAM;EACN,UAAU;EACV;EACA,QAAQ;EACR,OAAO,GAAG,cAAc,cAAc,QAAQ,OAAO,QAAQ;;YAEnD;EACV,KAAK;EACL,UAAU;EACV,qBAAqB;EACrB,qBAAqB;EACrB,uBAAuB;;EAEvB,uBAAuB;EACvB;EACA,MAAM,SAAS,eAAe;;YAEpB;EACV;EACA;EACA;EACA,SAAS;;wBAGK,UAAU,MAAM,UAAU"}
|
package/esm/e2e/types.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.mjs","names":[],"sources":["../../../../../../../../packages/core/src/e2e/types.ts"],"sourcesContent":["import type { BrowserPage } from \"./page\";\n\nexport type Command = readonly [executable: string, ...args: string[]];\nexport type Pattern = string | RegExp;\nexport type Viewport = { name: string; width: number; height: number; mobile?: boolean };\nexport const defaultViewports: readonly Viewport[] = [\n { name: \"desktop\", width: 1280, height: 800 },\n { name: \"phone\", width: 390, height: 844, mobile: true },\n];\n\nexport type FixtureContext = {\n /** Disposable copy of the app. All commands run here. */\n directory: string;\n dataRoot: string;\n /** OS-selected ephemeral port, reserved until immediately before app startup. */\n port: number;\n url: string;\n /** Write an actual port here when the app binds port 0 itself. */\n portFile: string;\n};\nexport type AppFixtureOptions = {\n directory?: string;\n /** Optional build, executed inside the disposable copy before start. */\n build?: Command | ((fixture: FixtureContext) => Command);\n /** Defaults to [process.execPath, \"dist/app.js\"]. Must stay in the foreground. */\n start?: Command | ((fixture: FixtureContext) => Command);\n /** Only these app variables are added to the isolated environment. */\n env?: Record<string, string> | ((fixture: FixtureContext) => Record<string, string>);\n /** Directories prepended to PATH, for fixture-owned fake engines/binaries. */\n path?: string[];\n /** Prepare data/fake binaries in the disposable fixture before build/start. */\n prepare?: (fixture: FixtureContext) => void | Promise<void>;\n /** Additional relative directories to omit when copying app files. */\n exclude?: string[];\n readyPath?: string;\n /** If true, await portFile instead of using the preallocated port. */\n portFromFile?: boolean;\n startupTimeoutMs?: number;\n};\nexport type BrowserOptions = {\n binary?: string;\n /** Additional Chrome flags, e.g. --no-sandbox in a controlled root container. */\n args?: string[];\n /**\n * How long to wait for the browser to report its DevTools endpoint.\n * A first launch with a fresh profile on a busy machine can be slow.\n * @default 30_000\n */\n startupTimeoutMs?: number;\n};\nexport type NetworkFailure = {\n at: string;\n url: string;\n status?: number;\n errorText?: string;\n canceled?: boolean;\n allowed?: boolean;\n};\nexport type ConsoleEntry = { at: string; level: string; text: string; allowed?: boolean };\nexport type StepEvidence = {\n name: string;\n startedAt: string;\n durationMs: number;\n status: \"passed\" | \"failed\";\n error?: string;\n};\nexport type ProcessEvidence = {\n role: string;\n pid: number;\n childPid?: number;\n command: string[];\n ownerFile: string;\n stopped?: boolean;\n};\nexport type AccessibilityOptions = {\n /** CSS selector limiting the scan; defaults to the document. */\n selector?: string;\n /** axe rule tags, for example wcag2a and wcag2aa. Defaults to all enabled rules. */\n tags?: string[];\n /** Exact rule ID, optionally limited to an exact reported selector. */\n allow?: { id: string; selector?: string }[];\n timeoutMs?: number;\n};\nexport type AccessibilityViolation = {\n id: string;\n impact: string | null;\n help: string;\n helpUrl: string;\n nodes: { target: (string | string[])[]; failureSummary?: string; allowed?: boolean }[];\n};\nexport type AccessibilityEvidence = {\n at: string;\n url: string;\n viewport: Viewport;\n violations: AccessibilityViolation[];\n incomplete: AccessibilityViolation[];\n};\nexport type E2EEvidence = {\n schemaVersion: 1;\n startedAt: string;\n durationMs: number;\n status: \"running\" | \"passed\" | \"failed\";\n url?: string;\n steps: StepEvidence[];\n console: ConsoleEntry[];\n networkFailures: NetworkFailure[];\n screenshots: { name: string; file: string; viewport: Viewport }[];\n accessibility?: AccessibilityEvidence[];\n processes: ProcessEvidence[];\n errors: string[];\n};\nexport type NetworkAllowance = { url: Pattern; status?: number; errorText?: Pattern };\nexport type E2EContext = FixtureContext & {\n page: BrowserPage;\n evidence: E2EEvidence;\n outputDirectory: string;\n signal: AbortSignal;\n step: <T>(name: string, action: () => Promise<T>) => Promise<T>;\n};\nexport type E2ESpec = {\n app: AppFixtureOptions;\n browser?: BrowserOptions;\n viewports?: readonly Viewport[];\n allowConsoleErrors?: Pattern[];\n allowNetworkFailures?: NetworkAllowance[];\n /** Long-lived HTTP requests excluded from the final network-idle barrier. */\n allowPendingRequests?: Pattern[];\n timeoutMs?: number;\n run: (context: E2EContext) => Promise<void>;\n};\nexport type RunE2EOptions = {\n browser?: string;\n path?: string[];\n outputDirectory?: string;\n signal?: AbortSignal;\n};\n\nexport function defineE2E(spec: E2ESpec): E2ESpec {\n return spec;\n}\nexport function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\nexport function matches(pattern: Pattern, value: string): boolean {\n // A fresh regexp avoids stateful /g and /y allowlists changing their verdict.\n return typeof pattern === \"string\"\n ? value.includes(pattern)\n : new RegExp(pattern.source, pattern.flags).test(value);\n}\n"],"mappings":";AAKA,MAAa,mBAAwC,CACnD;CAAE,MAAM;CAAW,OAAO;CAAM,QAAQ;AAAI,GAC5C;CAAE,MAAM;CAAS,OAAO;CAAK,QAAQ;CAAK,QAAQ;AAAK,CACzD;
|
|
1
|
+
{"version":3,"file":"types.mjs","names":[],"sources":["../../../../../../../../packages/core/src/e2e/types.ts"],"sourcesContent":["import type { BrowserPage } from \"./page\";\n\nexport type Command = readonly [executable: string, ...args: string[]];\nexport type Pattern = string | RegExp;\nexport type Viewport = { name: string; width: number; height: number; mobile?: boolean };\nexport const defaultViewports: readonly Viewport[] = [\n { name: \"desktop\", width: 1280, height: 800 },\n { name: \"phone\", width: 390, height: 844, mobile: true },\n];\n\nexport type FixtureContext = {\n /** Disposable copy of the app. All commands run here. */\n directory: string;\n dataRoot: string;\n /** OS-selected ephemeral port, reserved until immediately before app startup. */\n port: number;\n url: string;\n /** Write an actual port here when the app binds port 0 itself. */\n portFile: string;\n};\nexport type AppFixtureOptions = {\n directory?: string;\n /** Optional build, executed inside the disposable copy before start. */\n build?: Command | ((fixture: FixtureContext) => Command);\n /** Defaults to [process.execPath, \"dist/app.js\"]. Must stay in the foreground. */\n start?: Command | ((fixture: FixtureContext) => Command);\n /** Only these app variables are added to the isolated environment. */\n env?: Record<string, string> | ((fixture: FixtureContext) => Record<string, string>);\n /** Directories prepended to PATH, for fixture-owned fake engines/binaries. */\n path?: string[];\n /** Prepare data/fake binaries in the disposable fixture before build/start. */\n prepare?: (fixture: FixtureContext) => void | Promise<void>;\n /** Additional relative directories to omit when copying app files. */\n exclude?: string[];\n readyPath?: string;\n /** If true, await portFile instead of using the preallocated port. */\n portFromFile?: boolean;\n startupTimeoutMs?: number;\n};\nexport type BrowserOptions = {\n binary?: string;\n /** Additional Chrome flags, e.g. --no-sandbox in a controlled root container. */\n args?: string[];\n /**\n * How long to wait for the browser to report its DevTools endpoint.\n * A first launch with a fresh profile on a busy machine can be slow.\n * @default 30_000\n */\n startupTimeoutMs?: number;\n};\nexport type NetworkFailure = {\n at: string;\n url: string;\n status?: number;\n errorText?: string;\n canceled?: boolean;\n allowed?: boolean;\n};\nexport type ConsoleEntry = { at: string; level: string; text: string; allowed?: boolean };\nexport type StepEvidence = {\n name: string;\n startedAt: string;\n durationMs: number;\n status: \"passed\" | \"failed\";\n error?: string;\n};\nexport type ProcessEvidence = {\n role: string;\n pid: number;\n childPid?: number;\n command: string[];\n ownerFile: string;\n stopped?: boolean;\n};\nexport type AccessibilityOptions = {\n /** CSS selector limiting the scan; defaults to the document. */\n selector?: string;\n /** axe rule tags, for example wcag2a and wcag2aa. Defaults to all enabled rules. */\n tags?: string[];\n /** Exact rule ID, optionally limited to an exact reported selector. */\n allow?: { id: string; selector?: string }[];\n timeoutMs?: number;\n};\nexport type AccessibilityViolation = {\n id: string;\n impact: string | null;\n help: string;\n helpUrl: string;\n nodes: { target: (string | string[])[]; failureSummary?: string; allowed?: boolean }[];\n};\nexport type AccessibilityEvidence = {\n at: string;\n url: string;\n viewport: Viewport;\n violations: AccessibilityViolation[];\n incomplete: AccessibilityViolation[];\n};\n/**\n * The inline payload of one loaded document, in bytes as the HTML carries it:\n * the hydration data script and the browser route table. `limit` and\n * `overBudget` are present when the caller passed a limit to `measurePayload`.\n */\nexport type PayloadEvidence = {\n at: string;\n url: string;\n viewport: Viewport;\n /** The `__WARLOCK_DATA__` script: page, layout and app data, translations, session. */\n data: number;\n /** The `__WARLOCK_NAMED_API_ROUTES__` script: the page's browser route table. */\n routes: number;\n total: number;\n limit?: number;\n overBudget?: boolean;\n};\nexport type E2EEvidence = {\n schemaVersion: 1;\n startedAt: string;\n durationMs: number;\n status: \"running\" | \"passed\" | \"failed\";\n url?: string;\n steps: StepEvidence[];\n console: ConsoleEntry[];\n networkFailures: NetworkFailure[];\n screenshots: { name: string; file: string; viewport: Viewport }[];\n accessibility?: AccessibilityEvidence[];\n payloads?: PayloadEvidence[];\n processes: ProcessEvidence[];\n errors: string[];\n};\nexport type NetworkAllowance = { url: Pattern; status?: number; errorText?: Pattern };\nexport type E2EContext = FixtureContext & {\n page: BrowserPage;\n evidence: E2EEvidence;\n outputDirectory: string;\n signal: AbortSignal;\n step: <T>(name: string, action: () => Promise<T>) => Promise<T>;\n};\nexport type E2ESpec = {\n app: AppFixtureOptions;\n browser?: BrowserOptions;\n viewports?: readonly Viewport[];\n allowConsoleErrors?: Pattern[];\n allowNetworkFailures?: NetworkAllowance[];\n /** Long-lived HTTP requests excluded from the final network-idle barrier. */\n allowPendingRequests?: Pattern[];\n timeoutMs?: number;\n run: (context: E2EContext) => Promise<void>;\n};\nexport type RunE2EOptions = {\n browser?: string;\n path?: string[];\n outputDirectory?: string;\n signal?: AbortSignal;\n};\n\nexport function defineE2E(spec: E2ESpec): E2ESpec {\n return spec;\n}\nexport function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\nexport function matches(pattern: Pattern, value: string): boolean {\n // A fresh regexp avoids stateful /g and /y allowlists changing their verdict.\n return typeof pattern === \"string\"\n ? value.includes(pattern)\n : new RegExp(pattern.source, pattern.flags).test(value);\n}\n"],"mappings":";AAKA,MAAa,mBAAwC,CACnD;CAAE,MAAM;CAAW,OAAO;CAAM,QAAQ;AAAI,GAC5C;CAAE,MAAM;CAAS,OAAO;CAAK,QAAQ;CAAK,QAAQ;AAAK,CACzD;AAmJA,SAAgB,UAAU,MAAwB;CAChD,OAAO;AACT;AACA,SAAgB,aAAa,OAAwB;CACnD,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;AACA,SAAgB,QAAQ,SAAkB,OAAwB;CAEhE,OAAO,OAAO,YAAY,WACtB,MAAM,SAAS,OAAO,IACtB,IAAI,OAAO,QAAQ,QAAQ,QAAQ,KAAK,CAAC,CAAC,KAAK,KAAK;AAC1D"}
|