@alchemy.run/test 0.0.0 → 2.0.0-beta.85
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/LICENSE +201 -0
- package/bin/alchemy-test.ts +2 -0
- package/lib/Alchemy.d.ts +78 -0
- package/lib/Alchemy.d.ts.map +1 -0
- package/lib/Alchemy.js +194 -0
- package/lib/Alchemy.js.map +1 -0
- package/lib/Api.d.ts +134 -0
- package/lib/Api.d.ts.map +1 -0
- package/lib/Api.js +245 -0
- package/lib/Api.js.map +1 -0
- package/lib/Bun.d.ts +67 -0
- package/lib/Bun.d.ts.map +1 -0
- package/lib/Bun.js +143 -0
- package/lib/Bun.js.map +1 -0
- package/lib/Capture.d.ts +10 -0
- package/lib/Capture.d.ts.map +1 -0
- package/lib/Capture.js +68 -0
- package/lib/Capture.js.map +1 -0
- package/lib/Core.d.ts +287 -0
- package/lib/Core.d.ts.map +1 -0
- package/lib/Core.js +429 -0
- package/lib/Core.js.map +1 -0
- package/lib/DevCli.d.ts +47 -0
- package/lib/DevCli.d.ts.map +1 -0
- package/lib/DevCli.js +181 -0
- package/lib/DevCli.js.map +1 -0
- package/lib/Expect.d.ts +84 -0
- package/lib/Expect.d.ts.map +1 -0
- package/lib/Expect.js +518 -0
- package/lib/Expect.js.map +1 -0
- package/lib/FileLog.d.ts +27 -0
- package/lib/FileLog.d.ts.map +1 -0
- package/lib/FileLog.js +136 -0
- package/lib/FileLog.js.map +1 -0
- package/lib/Http.d.ts +109 -0
- package/lib/Http.d.ts.map +1 -0
- package/lib/Http.js +123 -0
- package/lib/Http.js.map +1 -0
- package/lib/Model.d.ts +98 -0
- package/lib/Model.d.ts.map +1 -0
- package/lib/Model.js +59 -0
- package/lib/Model.js.map +1 -0
- package/lib/PlainReporter.d.ts +19 -0
- package/lib/PlainReporter.d.ts.map +1 -0
- package/lib/PlainReporter.js +348 -0
- package/lib/PlainReporter.js.map +1 -0
- package/lib/Plan.d.ts +19 -0
- package/lib/Plan.d.ts.map +1 -0
- package/lib/Plan.js +32 -0
- package/lib/Plan.js.map +1 -0
- package/lib/Registry.d.ts +34 -0
- package/lib/Registry.d.ts.map +1 -0
- package/lib/Registry.js +80 -0
- package/lib/Registry.js.map +1 -0
- package/lib/Reporter.d.ts +160 -0
- package/lib/Reporter.d.ts.map +1 -0
- package/lib/Reporter.js +9 -0
- package/lib/Reporter.js.map +1 -0
- package/lib/Runner.d.ts +51 -0
- package/lib/Runner.d.ts.map +1 -0
- package/lib/Runner.js +1052 -0
- package/lib/Runner.js.map +1 -0
- package/lib/StrayOutput.d.ts +8 -0
- package/lib/StrayOutput.d.ts.map +1 -0
- package/lib/StrayOutput.js +259 -0
- package/lib/StrayOutput.js.map +1 -0
- package/lib/Tags.d.ts +17 -0
- package/lib/Tags.d.ts.map +1 -0
- package/lib/Tags.js +84 -0
- package/lib/Tags.js.map +1 -0
- package/lib/TestState.d.ts +12 -0
- package/lib/TestState.d.ts.map +1 -0
- package/lib/TestState.js +15 -0
- package/lib/TestState.js.map +1 -0
- package/lib/Tui.d.ts +4 -0
- package/lib/Tui.d.ts.map +1 -0
- package/lib/Tui.js +1137 -0
- package/lib/Tui.js.map +1 -0
- package/lib/Vitest.d.ts +58 -0
- package/lib/Vitest.d.ts.map +1 -0
- package/lib/Vitest.js +132 -0
- package/lib/Vitest.js.map +1 -0
- package/lib/WorktreeStage.d.ts +17 -0
- package/lib/WorktreeStage.d.ts.map +1 -0
- package/lib/WorktreeStage.js +48 -0
- package/lib/WorktreeStage.js.map +1 -0
- package/lib/cli.d.ts +2 -0
- package/lib/cli.d.ts.map +1 -0
- package/lib/cli.js +222 -0
- package/lib/cli.js.map +1 -0
- package/lib/index.d.ts +14 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +12 -0
- package/lib/index.js.map +1 -0
- package/package.json +73 -3
- package/src/Alchemy.ts +335 -0
- package/src/Api.ts +521 -0
- package/src/Bun.ts +256 -0
- package/src/Capture.ts +72 -0
- package/src/Core.ts +872 -0
- package/src/DevCli.ts +229 -0
- package/src/Expect.ts +763 -0
- package/src/FileLog.ts +158 -0
- package/src/Http.ts +201 -0
- package/src/Model.ts +160 -0
- package/src/PlainReporter.ts +426 -0
- package/src/Plan.ts +45 -0
- package/src/Registry.ts +101 -0
- package/src/Reporter.ts +171 -0
- package/src/Runner.ts +1341 -0
- package/src/StrayOutput.ts +283 -0
- package/src/Tags.ts +100 -0
- package/src/TestState.ts +35 -0
- package/src/Tui.ts +1272 -0
- package/src/Vitest.ts +239 -0
- package/src/WorktreeStage.ts +45 -0
- package/src/cli.ts +330 -0
- package/src/index.ts +57 -0
- package/README.md +0 -9
package/src/Reporter.ts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Reporter is an Effect service the runner emits structured events into.
|
|
3
|
+
* Two implementations ship with the CLI: a plain line-oriented reporter for
|
|
4
|
+
* non-interactive terminals / CI, and an opentui TUI for interactive use.
|
|
5
|
+
*/
|
|
6
|
+
import * as Context from "effect/Context";
|
|
7
|
+
import type * as Effect from "effect/Effect";
|
|
8
|
+
import type { LogEntry } from "./Model.ts";
|
|
9
|
+
|
|
10
|
+
export type TestStatus = "pass" | "fail" | "skip" | "todo";
|
|
11
|
+
|
|
12
|
+
export interface TestMeta {
|
|
13
|
+
readonly tags: ReadonlyArray<string>;
|
|
14
|
+
readonly optInTags: ReadonlyArray<string>;
|
|
15
|
+
/** Unique test identity, stable across retries; use titlePath for display. */
|
|
16
|
+
readonly id: string;
|
|
17
|
+
readonly file: string;
|
|
18
|
+
readonly titlePath: ReadonlyArray<string>;
|
|
19
|
+
readonly name: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface TestResult {
|
|
23
|
+
readonly status: TestStatus;
|
|
24
|
+
readonly durationMs: number;
|
|
25
|
+
/** Pretty-printed failure (message + relevant stack), if failed. */
|
|
26
|
+
readonly error?: string | undefined;
|
|
27
|
+
/** Buffered Effect log / Console output captured during the test. */
|
|
28
|
+
readonly logs: ReadonlyArray<LogEntry>;
|
|
29
|
+
/** Number of retries that were attempted before this result. */
|
|
30
|
+
readonly retries: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface RunSummary {
|
|
34
|
+
readonly dryRun?: boolean;
|
|
35
|
+
/** Coverage within the command's path, name, .only and global tag filters. */
|
|
36
|
+
readonly plan?:
|
|
37
|
+
| {
|
|
38
|
+
readonly found: number;
|
|
39
|
+
readonly selected: number;
|
|
40
|
+
readonly excluded: number;
|
|
41
|
+
}
|
|
42
|
+
| undefined;
|
|
43
|
+
readonly files: number;
|
|
44
|
+
readonly passed: number;
|
|
45
|
+
readonly failed: number;
|
|
46
|
+
readonly skipped: number;
|
|
47
|
+
readonly todo: number;
|
|
48
|
+
readonly durationMs: number;
|
|
49
|
+
readonly failures: ReadonlyArray<{ meta: TestMeta; result: TestResult }>;
|
|
50
|
+
/**
|
|
51
|
+
* Files that failed as a whole (import error, or a `beforeAll`/`afterAll`
|
|
52
|
+
* hook failure) rather than through an individual test. Counted in
|
|
53
|
+
* {@link failed} alongside `failures`.
|
|
54
|
+
*/
|
|
55
|
+
readonly fileFailures: ReadonlyArray<{ file: string; error: string }>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type TestEvent =
|
|
59
|
+
| {
|
|
60
|
+
readonly _tag: "PlanPreview";
|
|
61
|
+
readonly phases: ReadonlyArray<
|
|
62
|
+
ReadonlyArray<{
|
|
63
|
+
readonly tags: ReadonlyArray<string>;
|
|
64
|
+
readonly concurrency: number | "unbounded";
|
|
65
|
+
readonly tests: number;
|
|
66
|
+
readonly files: number;
|
|
67
|
+
readonly skipped: number;
|
|
68
|
+
}>
|
|
69
|
+
>;
|
|
70
|
+
}
|
|
71
|
+
| {
|
|
72
|
+
readonly _tag: "PlanPhaseStart";
|
|
73
|
+
readonly phase: number;
|
|
74
|
+
readonly phases: number;
|
|
75
|
+
readonly tests: number;
|
|
76
|
+
}
|
|
77
|
+
| { readonly _tag: "CollectStart"; readonly files: ReadonlyArray<string> }
|
|
78
|
+
| {
|
|
79
|
+
/** Import progress: one per file during the collection phase. */
|
|
80
|
+
readonly _tag: "FileCollected";
|
|
81
|
+
readonly file: string;
|
|
82
|
+
}
|
|
83
|
+
| {
|
|
84
|
+
/**
|
|
85
|
+
* Collection is complete; execution is about to begin. Carries the
|
|
86
|
+
* full (filtered) test list for the whole run.
|
|
87
|
+
*/
|
|
88
|
+
readonly _tag: "RunStart";
|
|
89
|
+
readonly files: number;
|
|
90
|
+
readonly tests: ReadonlyArray<TestMeta>;
|
|
91
|
+
}
|
|
92
|
+
| {
|
|
93
|
+
readonly _tag: "FileStart";
|
|
94
|
+
readonly file: string;
|
|
95
|
+
/**
|
|
96
|
+
* LIVE reference to the file's hook log buffer (deploy/destroy). The
|
|
97
|
+
* runner appends to it as hooks execute — single-process, so reporters
|
|
98
|
+
* may read it incrementally (e.g. the TUI tailing a detail pane).
|
|
99
|
+
*/
|
|
100
|
+
readonly logs?: ReadonlyArray<LogEntry>;
|
|
101
|
+
}
|
|
102
|
+
| {
|
|
103
|
+
/** A file-level hook (deploy/destroy) started running. */
|
|
104
|
+
readonly _tag: "HookStart";
|
|
105
|
+
readonly file: string;
|
|
106
|
+
readonly hook: "beforeAll" | "afterAll";
|
|
107
|
+
}
|
|
108
|
+
| {
|
|
109
|
+
readonly _tag: "HookEnd";
|
|
110
|
+
readonly file: string;
|
|
111
|
+
readonly hook: "beforeAll" | "afterAll";
|
|
112
|
+
}
|
|
113
|
+
| {
|
|
114
|
+
readonly _tag: "FileEnd";
|
|
115
|
+
readonly file: string;
|
|
116
|
+
/** Buffered output of file-level hooks (deploy/destroy). */
|
|
117
|
+
readonly logs: ReadonlyArray<LogEntry>;
|
|
118
|
+
readonly error?: string | undefined;
|
|
119
|
+
}
|
|
120
|
+
| {
|
|
121
|
+
readonly _tag: "TestStart";
|
|
122
|
+
readonly test: TestMeta;
|
|
123
|
+
/** LIVE reference to the test's captured-output buffer (see FileStart). */
|
|
124
|
+
readonly logs?: ReadonlyArray<LogEntry>;
|
|
125
|
+
}
|
|
126
|
+
| {
|
|
127
|
+
/**
|
|
128
|
+
* The test holds its run lock (`exclusive`) and starts executing. Until
|
|
129
|
+
* then it is queued: an exclusive test can wait out a busy phase.
|
|
130
|
+
*/
|
|
131
|
+
readonly _tag: "TestLocked";
|
|
132
|
+
readonly test: TestMeta;
|
|
133
|
+
}
|
|
134
|
+
| {
|
|
135
|
+
readonly _tag: "TestEnd";
|
|
136
|
+
readonly test: TestMeta;
|
|
137
|
+
readonly result: TestResult;
|
|
138
|
+
}
|
|
139
|
+
| { readonly _tag: "RunEnd"; readonly summary: RunSummary };
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Interactive control over a live (or finished) run. The runner hands this
|
|
143
|
+
* to the Reporter so the TUI can retry and kill tests.
|
|
144
|
+
*
|
|
145
|
+
* Retries re-run the test body as-is: for files whose state was torn down by
|
|
146
|
+
* `afterAll` (deploy-once suites) the retried body may fail on missing
|
|
147
|
+
* infrastructure — `test.provider`-style self-contained tests retry cleanly.
|
|
148
|
+
*/
|
|
149
|
+
export interface RunController {
|
|
150
|
+
/** Re-run a finished test. No-op while the test is still running/queued. */
|
|
151
|
+
readonly retryTest: (id: string) => void;
|
|
152
|
+
/** Re-run every finished test of a file. */
|
|
153
|
+
readonly retryFile: (file: string) => void;
|
|
154
|
+
/** Interrupt a currently-running test (reported as failed/killed). */
|
|
155
|
+
readonly killTest: (id: string) => void;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface ReporterService {
|
|
159
|
+
readonly emit: (event: TestEvent) => Effect.Effect<void>;
|
|
160
|
+
/**
|
|
161
|
+
* Runs after RunEnd. The plain reporter returns immediately; the TUI blocks
|
|
162
|
+
* until the user quits so results can be inspected.
|
|
163
|
+
*/
|
|
164
|
+
readonly waitForExit: (summary: RunSummary) => Effect.Effect<void>;
|
|
165
|
+
/** Called once by the runner when interactive control becomes available. */
|
|
166
|
+
readonly attachController?: (controller: RunController) => Effect.Effect<void>;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export class Reporter extends Context.Service<Reporter, ReporterService>()(
|
|
170
|
+
"alchemy-test/Reporter",
|
|
171
|
+
) {}
|