@aplaytest/runner-playwright 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/api-fixtures.d.ts +71 -0
  3. package/dist/api-fixtures.d.ts.map +1 -0
  4. package/dist/api-fixtures.js +162 -0
  5. package/dist/api-fixtures.js.map +1 -0
  6. package/dist/assemble.d.ts +86 -0
  7. package/dist/assemble.d.ts.map +1 -0
  8. package/dist/assemble.js +176 -0
  9. package/dist/assemble.js.map +1 -0
  10. package/dist/bind.d.ts +43 -0
  11. package/dist/bind.d.ts.map +1 -0
  12. package/dist/bind.js +112 -0
  13. package/dist/bind.js.map +1 -0
  14. package/dist/fixtures.d.ts +54 -0
  15. package/dist/fixtures.d.ts.map +1 -0
  16. package/dist/fixtures.js +210 -0
  17. package/dist/fixtures.js.map +1 -0
  18. package/dist/index.d.ts +31 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +24 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/reporter.d.ts +79 -0
  23. package/dist/reporter.d.ts.map +1 -0
  24. package/dist/reporter.js +277 -0
  25. package/dist/reporter.js.map +1 -0
  26. package/dist/sidecar.d.ts +134 -0
  27. package/dist/sidecar.d.ts.map +1 -0
  28. package/dist/sidecar.js +111 -0
  29. package/dist/sidecar.js.map +1 -0
  30. package/dist/spawn.d.ts +57 -0
  31. package/dist/spawn.d.ts.map +1 -0
  32. package/dist/spawn.js +170 -0
  33. package/dist/spawn.js.map +1 -0
  34. package/dist/steps.d.ts +45 -0
  35. package/dist/steps.d.ts.map +1 -0
  36. package/dist/steps.js +106 -0
  37. package/dist/steps.js.map +1 -0
  38. package/dist-cjs/.tsbuildinfo +1 -0
  39. package/dist-cjs/api-fixtures.js +166 -0
  40. package/dist-cjs/api-fixtures.js.map +1 -0
  41. package/dist-cjs/assemble.js +181 -0
  42. package/dist-cjs/assemble.js.map +1 -0
  43. package/dist-cjs/bind.js +117 -0
  44. package/dist-cjs/bind.js.map +1 -0
  45. package/dist-cjs/fixtures.js +215 -0
  46. package/dist-cjs/fixtures.js.map +1 -0
  47. package/dist-cjs/index.js +64 -0
  48. package/dist-cjs/index.js.map +1 -0
  49. package/dist-cjs/package.json +3 -0
  50. package/dist-cjs/reporter.js +282 -0
  51. package/dist-cjs/reporter.js.map +1 -0
  52. package/dist-cjs/sidecar.js +116 -0
  53. package/dist-cjs/sidecar.js.map +1 -0
  54. package/dist-cjs/spawn.js +174 -0
  55. package/dist-cjs/spawn.js.map +1 -0
  56. package/dist-cjs/steps.js +112 -0
  57. package/dist-cjs/steps.js.map +1 -0
  58. package/package.json +51 -0
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @aplaytest/runner-playwright — the Playwright adapter.
3
+ *
4
+ * The only package that knows Playwright exists. Everything above it consumes
5
+ * EvidenceBundles and RunRecords, so swapping in a different runner means
6
+ * writing a sibling of this package and nothing else.
7
+ *
8
+ * NOTE: this package must NOT depend on @aplaytest/llm. The reporter runs inside
9
+ * the test process; pulling an HTTP client and a model SDK into every worker
10
+ * would be both slow and a place a credential should never be.
11
+ */
12
+ export { default as AtestReporter, ATEST_VERSION } from './reporter.js';
13
+ export type { AtestReporterOptions } from './reporter.js';
14
+ export { assembleBundle, toClassifiable, classifyResult } from './assemble.js';
15
+ export type { AssembleInput, AssembleContext, Sidecars, TestCaseLike, TestResultLike, TestErrorLike, } from './assemble.js';
16
+ export { parsePlaywrightError, splitCallLog, stripAnsi, joinErrors } from '@aplaytest/core';
17
+ export type { ParsedError, ErrorLike } from '@aplaytest/core';
18
+ export { atestFixtures, createCaptureFixture, test, expect } from './fixtures.js';
19
+ export type { CaptureOptions } from './fixtures.js';
20
+ export { bindPage, previewArgs, previewValue } from './bind.js';
21
+ export type { BoundPageObject } from './bind.js';
22
+ export { extractSteps, findFailingStep, parseStepTitle, domainStringArgs } from './steps.js';
23
+ export type { StepLike, ParsedStepTitle } from './steps.js';
24
+ export { SIDECAR, parseSidecar, SidecarParseError, PageSidecarSchema, NetworkSidecarSchema, ConsoleSidecarSchema, IntentSidecarSchema, CoverageSidecarSchema, } from './sidecar.js';
25
+ export type { SidecarName, PageSidecar, NetworkSidecar, ConsoleSidecar, IntentSidecar, CoverageSidecar, } from './sidecar.js';
26
+ export { runPlaywright, escapeForGrep } from './spawn.js';
27
+ export type { PlaywrightRunOptions, PlaywrightRunResult, SpecOutcome } from './spawn.js';
28
+ export { atestApiFixtures, createApiCaptureFixture, recordingContext, } from './api-fixtures.js';
29
+ export type { ApiCaptureOptions } from './api-fixtures.js';
30
+ export { runFileName } from './reporter.js';
31
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACxE,YAAY,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/E,YAAY,EACV,aAAa,EACb,eAAe,EACf,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,aAAa,GACd,MAAM,eAAe,CAAC;AAIvB,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC5F,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAClF,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAChE,YAAY,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC7F,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE5D,OAAO,EACL,OAAO,EACP,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,WAAW,EACX,WAAW,EACX,cAAc,EACd,cAAc,EACd,aAAa,EACb,eAAe,GAChB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC1D,YAAY,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzF,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @aplaytest/runner-playwright — the Playwright adapter.
3
+ *
4
+ * The only package that knows Playwright exists. Everything above it consumes
5
+ * EvidenceBundles and RunRecords, so swapping in a different runner means
6
+ * writing a sibling of this package and nothing else.
7
+ *
8
+ * NOTE: this package must NOT depend on @aplaytest/llm. The reporter runs inside
9
+ * the test process; pulling an HTTP client and a model SDK into every worker
10
+ * would be both slow and a place a credential should never be.
11
+ */
12
+ export { default as AtestReporter, ATEST_VERSION } from './reporter.js';
13
+ export { assembleBundle, toClassifiable, classifyResult } from './assemble.js';
14
+ // Re-exported from @aplaytest/core, where the parser now lives beside the
15
+ // classifier that consumes it. Kept here so existing importers do not break.
16
+ export { parsePlaywrightError, splitCallLog, stripAnsi, joinErrors } from '@aplaytest/core';
17
+ export { atestFixtures, createCaptureFixture, test, expect } from './fixtures.js';
18
+ export { bindPage, previewArgs, previewValue } from './bind.js';
19
+ export { extractSteps, findFailingStep, parseStepTitle, domainStringArgs } from './steps.js';
20
+ export { SIDECAR, parseSidecar, SidecarParseError, PageSidecarSchema, NetworkSidecarSchema, ConsoleSidecarSchema, IntentSidecarSchema, CoverageSidecarSchema, } from './sidecar.js';
21
+ export { runPlaywright, escapeForGrep } from './spawn.js';
22
+ export { atestApiFixtures, createApiCaptureFixture, recordingContext, } from './api-fixtures.js';
23
+ export { runFileName } from './reporter.js';
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGxE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAU/E,0EAA0E;AAC1E,6EAA6E;AAC7E,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG5F,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAGlF,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAGhE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG7F,OAAO,EACL,OAAO,EACP,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,cAAc,CAAC;AAUtB,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG1D,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * The atest Playwright reporter.
3
+ *
4
+ * INVARIANT: this reporter must never change a run's verdict. It reports no
5
+ * status from `onEnd`, swallows its own errors to stderr, and does its I/O
6
+ * after the run rather than inside it. If atest breaks, the suite still tells
7
+ * the truth about the application — that property is what makes adopting it a
8
+ * one-line, revertible change.
9
+ *
10
+ * Work is COLLECTED in `onTestEnd` (synchronous, cheap: a couple of object
11
+ * references) and FLUSHED in `onEnd` (asynchronous: attachment reads, JSON
12
+ * writes). Playwright's `onTestEnd` cannot await, and doing file I/O per test
13
+ * inside a parallel run is exactly the kind of overhead that would make people
14
+ * turn the tool off.
15
+ */
16
+ import type { FullConfig, FullResult, Reporter, TestCase, TestResult } from '@playwright/test/reporter';
17
+ import { ATEST_VERSION } from '@aplaytest/core';
18
+ export { ATEST_VERSION };
19
+ export interface AtestReporterOptions {
20
+ /** Directory for evidence bundles. */
21
+ readonly evidenceDir?: string;
22
+ /** Directory for run records. */
23
+ readonly runsDir?: string;
24
+ readonly retainRuns?: number;
25
+ readonly redactKeys?: readonly string[];
26
+ /** Reuse an existing run id — e.g. one shared across CI shards. */
27
+ readonly runId?: string | (() => string);
28
+ /**
29
+ * Reuse deterministic trace ids so history rows join to app spans that
30
+ * already exist, instead of minting a parallel id space.
31
+ */
32
+ readonly traceId?: (test: {
33
+ id: string;
34
+ }, retry: number) => string;
35
+ /** Set ATEST=0 or pass false to disable entirely. */
36
+ readonly enabled?: boolean;
37
+ }
38
+ export default class AtestReporter implements Reporter {
39
+ private readonly options;
40
+ private readonly collected;
41
+ private readonly workerTests;
42
+ private config;
43
+ private runId;
44
+ private startedAt;
45
+ private enabled;
46
+ constructor(options?: AtestReporterOptions);
47
+ /** We add a short footer only; other reporters own the main output. */
48
+ printsToStdio(): boolean;
49
+ onBegin(config: FullConfig): void;
50
+ onTestEnd(test: TestCase, result: TestResult): void;
51
+ onEnd(_result: FullResult): Promise<void>;
52
+ private flush;
53
+ private readAttachment;
54
+ private readCoverage;
55
+ private readSidecars;
56
+ }
57
+ /**
58
+ * One file per INVOCATION, not per run.
59
+ *
60
+ * Naming the file `<runId>.json` looks right until the suite is sharded, and
61
+ * then it silently destroys almost all of the data. Every shard shares one run
62
+ * id on purpose — that is how they get merged — so every shard wrote the same
63
+ * filename. Measured on a three-shard run: shards 1 and 2 recorded their
64
+ * attempts, shard 3 had no tests to run, and its empty record overwrote both.
65
+ * The surviving file reported `attempts: 0` for a run that passed four tests.
66
+ *
67
+ * It survives the upload too. CI downloads shard artifacts with
68
+ * `merge-multiple: true`, which flattens them into one directory — identical
69
+ * names collide there as well, so a 6-shard × 9-project matrix would keep one
70
+ * file in fifty-four.
71
+ *
72
+ * Shard and project both go in the name because their matrix varies both, and
73
+ * two jobs differing only by project would otherwise still collide.
74
+ */
75
+ export declare function runFileName(runId: string, shard: {
76
+ readonly current: number;
77
+ readonly total: number;
78
+ } | null, projects: readonly string[]): string;
79
+ //# sourceMappingURL=reporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,UAAU,EACX,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,aAAa,EASd,MAAM,iBAAiB,CAAC;AAKzB,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB,MAAM,WAAW,oBAAoB;IACnC,sCAAsC;IACtC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,iCAAiC;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,mEAAmE;IACnE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IACzC;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACnE,qDAAqD;IACrD,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AA8BD,MAAM,CAAC,OAAO,OAAO,aAAc,YAAW,QAAQ;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgD;IAC1E,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA+B;IAE3D,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,OAAO,CAAQ;gBAEX,OAAO,GAAE,oBAAyB;IAI9C,uEAAuE;IACvE,aAAa,IAAI,OAAO;IAIxB,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAgBjC,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IAS7C,KAAK,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;YAUjC,KAAK;YA8HL,cAAc;YAQd,YAAY;YAWZ,YAAY;CAU3B;AAID;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EAClE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,MAAM,CASR"}
@@ -0,0 +1,277 @@
1
+ /**
2
+ * The atest Playwright reporter.
3
+ *
4
+ * INVARIANT: this reporter must never change a run's verdict. It reports no
5
+ * status from `onEnd`, swallows its own errors to stderr, and does its I/O
6
+ * after the run rather than inside it. If atest breaks, the suite still tells
7
+ * the truth about the application — that property is what makes adopting it a
8
+ * one-line, revertible change.
9
+ *
10
+ * Work is COLLECTED in `onTestEnd` (synchronous, cheap: a couple of object
11
+ * references) and FLUSHED in `onEnd` (asynchronous: attachment reads, JSON
12
+ * writes). Playwright's `onTestEnd` cannot await, and doing file I/O per test
13
+ * inside a parallel run is exactly the kind of overhead that would make people
14
+ * turn the tool off.
15
+ */
16
+ import { readFile } from 'node:fs/promises';
17
+ import { mkdir, writeFile } from 'node:fs/promises';
18
+ import { dirname, join } from 'node:path';
19
+ import { ATEST_VERSION, EvidenceStore, RUN_SCHEMA_VERSION, isFailure, } from '@aplaytest/core';
20
+ import { assembleBundle, classifyResult } from './assemble.js';
21
+ import { SIDECAR, SidecarParseError, parseSidecar } from './sidecar.js';
22
+ export { ATEST_VERSION };
23
+ const DEFAULTS = {
24
+ evidenceDir: '.atest/evidence',
25
+ runsDir: '.atest/runs',
26
+ retainRuns: 50,
27
+ redactKeys: ['password', 'token', 'authorization', 'cookie', 'secret', 'api-key'],
28
+ };
29
+ function toOutcome(status) {
30
+ switch (status) {
31
+ case 'passed':
32
+ return 'passed';
33
+ case 'failed':
34
+ return 'failed';
35
+ case 'timedOut':
36
+ return 'timedOut';
37
+ case 'skipped':
38
+ return 'skipped';
39
+ case 'interrupted':
40
+ return 'interrupted';
41
+ default:
42
+ return 'failed';
43
+ }
44
+ }
45
+ function warn(message) {
46
+ process.stderr.write(`[atest] ${message}\n`);
47
+ }
48
+ export default class AtestReporter {
49
+ options;
50
+ collected = [];
51
+ workerTests = new Map();
52
+ config;
53
+ runId = '';
54
+ startedAt = '';
55
+ enabled = true;
56
+ constructor(options = {}) {
57
+ this.options = options;
58
+ }
59
+ /** We add a short footer only; other reporters own the main output. */
60
+ printsToStdio() {
61
+ return false;
62
+ }
63
+ onBegin(config) {
64
+ this.config = config;
65
+ this.enabled = this.options.enabled ?? process.env['ATEST'] !== '0';
66
+ this.startedAt = new Date().toISOString();
67
+ const fromOptions = typeof this.options.runId === 'function' ? this.options.runId() : this.options.runId;
68
+ // Environment wins over config, deliberately. Every shard of a CI run must
69
+ // share one run id, and only the runtime knows it — a value baked into
70
+ // playwright.config.ts cannot vary per invocation, so config-wins would
71
+ // make sharded runs silently collapse into a single overwritten record.
72
+ this.runId =
73
+ process.env['ATEST_RUN_ID'] ??
74
+ fromOptions ??
75
+ `${this.startedAt.replace(/[:.]/g, '-')}-${process.pid}`;
76
+ }
77
+ onTestEnd(test, result) {
78
+ if (!this.enabled)
79
+ return;
80
+ // Cheap and synchronous by design — two references and a string push.
81
+ this.collected.push({ test, result });
82
+ const onWorker = this.workerTests.get(result.workerIndex) ?? [];
83
+ onWorker.push(test.id);
84
+ this.workerTests.set(result.workerIndex, onWorker);
85
+ }
86
+ async onEnd(_result) {
87
+ if (!this.enabled)
88
+ return;
89
+ try {
90
+ await this.flush();
91
+ }
92
+ catch (error) {
93
+ // A reporting failure must never become a test failure.
94
+ warn(`failed to write evidence: ${error instanceof Error ? error.message : String(error)}`);
95
+ }
96
+ }
97
+ async flush() {
98
+ const evidenceStore = new EvidenceStore({
99
+ dir: this.options.evidenceDir ?? DEFAULTS.evidenceDir,
100
+ redactKeys: this.options.redactKeys ?? DEFAULTS.redactKeys,
101
+ retainRuns: this.options.retainRuns ?? DEFAULTS.retainRuns,
102
+ });
103
+ const attempts = [];
104
+ let bundlesWritten = 0;
105
+ for (const { test, result } of this.collected) {
106
+ const outcome = toOutcome(result.status);
107
+ // Playwright names the implicit project '' when a config declares no
108
+ // projects. Empty string is a poor grouping key: it is part of the
109
+ // scoring key and the evidence id, and it reads as missing data in
110
+ // every report.
111
+ const projectName = test.parent.project()?.name;
112
+ const project = projectName === undefined || projectName === '' ? 'default' : projectName;
113
+ const traceId = this.options.traceId?.({ id: test.id }, result.retry) ?? null;
114
+ let failureKind = null;
115
+ let evidenceIdValue = null;
116
+ // Coverage is read for EVERY attempt, not only failures: what a passing
117
+ // test visited is precisely what future selection needs.
118
+ const coverage = await this.readCoverage(result);
119
+ if (isFailure(outcome)) {
120
+ try {
121
+ const sidecars = await this.readSidecars(result);
122
+ const bundle = assembleBundle({
123
+ test: {
124
+ id: test.id,
125
+ title: test.title,
126
+ titlePath: () => test.titlePath(),
127
+ location: { file: test.location.file, line: test.location.line },
128
+ tags: test.tags,
129
+ },
130
+ result: result,
131
+ sidecars,
132
+ context: {
133
+ runId: this.runId,
134
+ traceId,
135
+ project,
136
+ shard: this.config?.shard ?? null,
137
+ workers: this.config?.workers ?? 1,
138
+ appEnv: process.env['APP_ENV'] ?? 'unknown',
139
+ baseUrl: process.env['BASE_URL'] ?? '',
140
+ browser: project,
141
+ platform: process.platform,
142
+ commit: process.env['GITHUB_SHA'] ?? '',
143
+ changedPaths: [],
144
+ timeoutMs: test.timeout,
145
+ },
146
+ });
147
+ await evidenceStore.write(bundle);
148
+ bundlesWritten += 1;
149
+ failureKind = bundle.failure.kind;
150
+ evidenceIdValue = bundle.id;
151
+ }
152
+ catch (error) {
153
+ if (error instanceof SidecarParseError) {
154
+ // Loud, named, and actionable — a drifted contract is a bug in the
155
+ // fixtures, not something to paper over with an empty bundle.
156
+ warn(error.message);
157
+ }
158
+ else {
159
+ warn(`could not build evidence for "${test.title}": ` +
160
+ `${error instanceof Error ? error.message : String(error)}`);
161
+ }
162
+ failureKind = classifyResult(result, EMPTY, test.timeout).kind;
163
+ }
164
+ }
165
+ attempts.push({
166
+ testId: test.id,
167
+ title: test.title,
168
+ titlePath: test.titlePath(),
169
+ file: test.location.file,
170
+ line: test.location.line,
171
+ project,
172
+ tags: test.tags,
173
+ retry: result.retry,
174
+ outcome,
175
+ failureKind,
176
+ durationMs: result.duration,
177
+ workerIndex: result.workerIndex,
178
+ shard: this.config?.shard ?? null,
179
+ traceId,
180
+ evidenceId: evidenceIdValue,
181
+ coScheduled: (this.workerTests.get(result.workerIndex) ?? []).filter(id => id !== test.id),
182
+ routes: coverage,
183
+ });
184
+ }
185
+ const run = {
186
+ schemaVersion: RUN_SCHEMA_VERSION,
187
+ runId: this.runId,
188
+ startedAt: this.startedAt,
189
+ finishedAt: new Date().toISOString(),
190
+ commit: process.env['GITHUB_SHA'] ?? null,
191
+ branch: process.env['GITHUB_REF_NAME'] ?? null,
192
+ appEnv: process.env['APP_ENV'] ?? null,
193
+ ci: process.env['CI'] === 'true' || process.env['CI'] === '1',
194
+ workers: this.config?.workers ?? 1,
195
+ shard: this.config?.shard ?? null,
196
+ atestVersion: ATEST_VERSION,
197
+ playwrightVersion: this.config?.version ?? null,
198
+ attempts,
199
+ };
200
+ const runPath = join(this.options.runsDir ?? DEFAULTS.runsDir, runFileName(this.runId, run.shard, attempts.map(a => a.project)));
201
+ await mkdir(dirname(runPath), { recursive: true });
202
+ await writeFile(runPath, `${JSON.stringify(run, null, 2)}\n`, 'utf8');
203
+ await evidenceStore.prune();
204
+ const failures = attempts.filter(a => isFailure(a.outcome)).length;
205
+ if (failures > 0) {
206
+ warn(`${bundlesWritten}/${failures} failures captured → ${runPath}`);
207
+ }
208
+ }
209
+ async readAttachment(result, name) {
210
+ const attachment = result.attachments.find(a => a.name === name);
211
+ if (attachment === undefined)
212
+ return undefined;
213
+ if (attachment.body !== undefined)
214
+ return attachment.body.toString('utf8');
215
+ if (attachment.path !== undefined)
216
+ return readFile(attachment.path, 'utf8').catch(() => undefined);
217
+ return undefined;
218
+ }
219
+ async readCoverage(result) {
220
+ try {
221
+ const parsed = parseSidecar(SIDECAR.coverage, await this.readAttachment(result, SIDECAR.coverage));
222
+ return parsed?.routes ?? [];
223
+ }
224
+ catch (error) {
225
+ // A drifted coverage sidecar must not cost us the attempt record.
226
+ warn(error instanceof Error ? error.message : String(error));
227
+ return [];
228
+ }
229
+ }
230
+ async readSidecars(result) {
231
+ const read = (name) => this.readAttachment(result, name);
232
+ return {
233
+ page: parseSidecar(SIDECAR.page, await read(SIDECAR.page)),
234
+ network: parseSidecar(SIDECAR.network, await read(SIDECAR.network)),
235
+ console: parseSidecar(SIDECAR.console, await read(SIDECAR.console)),
236
+ intent: parseSidecar(SIDECAR.intent, await read(SIDECAR.intent)),
237
+ };
238
+ }
239
+ }
240
+ const EMPTY = { page: null, network: null, console: null, intent: null };
241
+ /**
242
+ * One file per INVOCATION, not per run.
243
+ *
244
+ * Naming the file `<runId>.json` looks right until the suite is sharded, and
245
+ * then it silently destroys almost all of the data. Every shard shares one run
246
+ * id on purpose — that is how they get merged — so every shard wrote the same
247
+ * filename. Measured on a three-shard run: shards 1 and 2 recorded their
248
+ * attempts, shard 3 had no tests to run, and its empty record overwrote both.
249
+ * The surviving file reported `attempts: 0` for a run that passed four tests.
250
+ *
251
+ * It survives the upload too. CI downloads shard artifacts with
252
+ * `merge-multiple: true`, which flattens them into one directory — identical
253
+ * names collide there as well, so a 6-shard × 9-project matrix would keep one
254
+ * file in fifty-four.
255
+ *
256
+ * Shard and project both go in the name because their matrix varies both, and
257
+ * two jobs differing only by project would otherwise still collide.
258
+ */
259
+ export function runFileName(runId, shard, projects) {
260
+ const parts = [runId];
261
+ if (shard !== null)
262
+ parts.push(`shard-${shard.current}of${shard.total}`);
263
+ const distinct = [...new Set(projects)].sort();
264
+ if (distinct.length === 1 && distinct[0] !== undefined)
265
+ parts.push(distinct[0]);
266
+ else if (distinct.length > 1)
267
+ parts.push(shortHash(distinct.join(',')));
268
+ return `${parts.join('-').replace(/[^A-Za-z0-9._-]/g, '_')}.json`;
269
+ }
270
+ /** djb2, base36. Deterministic — re-ingesting the same file must be idempotent. */
271
+ function shortHash(input) {
272
+ let hash = 5381;
273
+ for (let i = 0; i < input.length; i += 1)
274
+ hash = ((hash * 33) ^ input.charCodeAt(i)) >>> 0;
275
+ return hash.toString(36).padStart(7, '0').slice(0, 7);
276
+ }
277
+ //# sourceMappingURL=reporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * The fixture → reporter channel.
3
+ *
4
+ * A Playwright reporter runs in the main process and cannot reach into the
5
+ * browser. Anything only the worker knows — the ARIA snapshot, the request
6
+ * ledger, console output — has to travel as a test ATTACHMENT, which is the
7
+ * runner's own supported channel and needs no side files or IPC.
8
+ *
9
+ * Both ends import these schemas, and the reporter PARSES rather than casts.
10
+ * A fixture that drifts from the contract fails loudly with a named error
11
+ * instead of silently producing a bundle with an empty ARIA snapshot — the
12
+ * same reasoning behind validating mocked response bodies against wire
13
+ * schemas rather than trusting them.
14
+ */
15
+ import { z } from 'zod';
16
+ export declare const SIDECAR: {
17
+ readonly page: "atest:page";
18
+ readonly network: "atest:network";
19
+ readonly console: "atest:console";
20
+ readonly intent: "atest:intent";
21
+ readonly coverage: "atest:coverage";
22
+ };
23
+ export type SidecarName = (typeof SIDECAR)[keyof typeof SIDECAR];
24
+ export declare const PageSidecarSchema: z.ZodObject<{
25
+ url: z.ZodString;
26
+ title: z.ZodString;
27
+ ariaSnapshot: z.ZodString;
28
+ testIdsPresent: z.ZodArray<z.ZodString>;
29
+ htmlDigest: z.ZodDefault<z.ZodNullable<z.ZodString>>;
30
+ }, z.core.$strip>;
31
+ export type PageSidecar = z.infer<typeof PageSidecarSchema>;
32
+ export declare const NetworkSidecarSchema: z.ZodObject<{
33
+ failed: z.ZodArray<z.ZodObject<{
34
+ url: z.ZodString;
35
+ method: z.ZodString;
36
+ status: z.ZodNullable<z.ZodNumber>;
37
+ durationMs: z.ZodNumber;
38
+ failureText: z.ZodDefault<z.ZodNullable<z.ZodString>>;
39
+ schemaError: z.ZodDefault<z.ZodNullable<z.ZodString>>;
40
+ }, z.core.$strip>>;
41
+ slow: z.ZodArray<z.ZodObject<{
42
+ url: z.ZodString;
43
+ method: z.ZodString;
44
+ status: z.ZodNullable<z.ZodNumber>;
45
+ durationMs: z.ZodNumber;
46
+ failureText: z.ZodDefault<z.ZodNullable<z.ZodString>>;
47
+ schemaError: z.ZodDefault<z.ZodNullable<z.ZodString>>;
48
+ }, z.core.$strip>>;
49
+ statusCounts: z.ZodRecord<z.ZodString, z.ZodNumber>;
50
+ }, z.core.$strip>;
51
+ export type NetworkSidecar = z.infer<typeof NetworkSidecarSchema>;
52
+ export declare const ConsoleSidecarSchema: z.ZodObject<{
53
+ errors: z.ZodArray<z.ZodString>;
54
+ warnings: z.ZodArray<z.ZodString>;
55
+ }, z.core.$strip>;
56
+ export type ConsoleSidecar = z.infer<typeof ConsoleSidecarSchema>;
57
+ export declare const IntentSidecarSchema: z.ZodObject<{
58
+ selector: z.ZodDefault<z.ZodNullable<z.ZodString>>;
59
+ selectorSource: z.ZodDefault<z.ZodNullable<z.ZodObject<{
60
+ file: z.ZodString;
61
+ line: z.ZodNumber;
62
+ constantPath: z.ZodString;
63
+ aliases: z.ZodDefault<z.ZodArray<z.ZodString>>;
64
+ }, z.core.$strip>>>;
65
+ }, z.core.$strip>;
66
+ export type IntentSidecar = z.infer<typeof IntentSidecarSchema>;
67
+ /**
68
+ * Routes a test actually visited.
69
+ *
70
+ * The one signal that survives a fixture barrel. Static imports say every spec
71
+ * depends on every feature (they compose one `test` object); what a test
72
+ * VISITED is independent of that, and is the only thing that can narrow
73
+ * selection in a suite built that way.
74
+ */
75
+ export declare const CoverageSidecarSchema: z.ZodObject<{
76
+ routes: z.ZodArray<z.ZodString>;
77
+ }, z.core.$strip>;
78
+ export type CoverageSidecar = z.infer<typeof CoverageSidecarSchema>;
79
+ declare const SCHEMAS: {
80
+ readonly "atest:page": z.ZodObject<{
81
+ url: z.ZodString;
82
+ title: z.ZodString;
83
+ ariaSnapshot: z.ZodString;
84
+ testIdsPresent: z.ZodArray<z.ZodString>;
85
+ htmlDigest: z.ZodDefault<z.ZodNullable<z.ZodString>>;
86
+ }, z.core.$strip>;
87
+ readonly "atest:network": z.ZodObject<{
88
+ failed: z.ZodArray<z.ZodObject<{
89
+ url: z.ZodString;
90
+ method: z.ZodString;
91
+ status: z.ZodNullable<z.ZodNumber>;
92
+ durationMs: z.ZodNumber;
93
+ failureText: z.ZodDefault<z.ZodNullable<z.ZodString>>;
94
+ schemaError: z.ZodDefault<z.ZodNullable<z.ZodString>>;
95
+ }, z.core.$strip>>;
96
+ slow: z.ZodArray<z.ZodObject<{
97
+ url: z.ZodString;
98
+ method: z.ZodString;
99
+ status: z.ZodNullable<z.ZodNumber>;
100
+ durationMs: z.ZodNumber;
101
+ failureText: z.ZodDefault<z.ZodNullable<z.ZodString>>;
102
+ schemaError: z.ZodDefault<z.ZodNullable<z.ZodString>>;
103
+ }, z.core.$strip>>;
104
+ statusCounts: z.ZodRecord<z.ZodString, z.ZodNumber>;
105
+ }, z.core.$strip>;
106
+ readonly "atest:console": z.ZodObject<{
107
+ errors: z.ZodArray<z.ZodString>;
108
+ warnings: z.ZodArray<z.ZodString>;
109
+ }, z.core.$strip>;
110
+ readonly "atest:intent": z.ZodObject<{
111
+ selector: z.ZodDefault<z.ZodNullable<z.ZodString>>;
112
+ selectorSource: z.ZodDefault<z.ZodNullable<z.ZodObject<{
113
+ file: z.ZodString;
114
+ line: z.ZodNumber;
115
+ constantPath: z.ZodString;
116
+ aliases: z.ZodDefault<z.ZodArray<z.ZodString>>;
117
+ }, z.core.$strip>>>;
118
+ }, z.core.$strip>;
119
+ readonly "atest:coverage": z.ZodObject<{
120
+ routes: z.ZodArray<z.ZodString>;
121
+ }, z.core.$strip>;
122
+ };
123
+ export declare class SidecarParseError extends Error {
124
+ readonly sidecar: string;
125
+ readonly issues: string;
126
+ constructor(sidecar: string, issues: string);
127
+ }
128
+ /**
129
+ * Parse a sidecar payload. Absent is fine (the fixtures are optional);
130
+ * PRESENT-BUT-WRONG is not, and throws.
131
+ */
132
+ export declare function parseSidecar<N extends keyof typeof SCHEMAS>(name: N, raw: string | undefined): z.infer<(typeof SCHEMAS)[N]> | null;
133
+ export {};
134
+ //# sourceMappingURL=sidecar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidecar.d.ts","sourceRoot":"","sources":["../src/sidecar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,OAAO;;;;;;CAMV,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,OAAO,OAAO,CAAC,CAAC;AAEjE,eAAO,MAAM,iBAAiB;;;;;;iBAM5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAW5D,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;iBAI/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,eAAO,MAAM,oBAAoB;;;iBAG/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,eAAO,MAAM,mBAAmB;;;;;;;;iBAW9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB;;iBAEhC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,QAAA,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAMH,CAAC;AAEX,qBAAa,iBAAkB,SAAQ,KAAK;IAExC,QAAQ,CAAC,OAAO,EAAE,MAAM;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM;gBADd,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM;CAQ1B;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,OAAO,OAAO,EACzD,IAAI,EAAE,CAAC,EACP,GAAG,EAAE,MAAM,GAAG,SAAS,GACtB,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAkBrC"}