@alchemy.run/test 0.0.0-stage → 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 +88 -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 -3
package/lib/Api.js
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The vitest-compatible registration API: `describe`, `it`/`test`, hooks and
|
|
3
|
+
* `layer`. Registration builds the {@link Model} tree; execution is the
|
|
4
|
+
* runner's job. Everything is Effect-first — plain-function tests are wrapped
|
|
5
|
+
* into Effects at registration time.
|
|
6
|
+
*/
|
|
7
|
+
import * as Effect from "effect/Effect";
|
|
8
|
+
import * as Exit from "effect/Exit";
|
|
9
|
+
import * as Layer from "effect/Layer";
|
|
10
|
+
import * as Scope from "effect/Scope";
|
|
11
|
+
import * as TestClock from "effect/testing/TestClock";
|
|
12
|
+
import * as TestConsole from "effect/testing/TestConsole";
|
|
13
|
+
import { makeSuite } from "./Model.js";
|
|
14
|
+
import { currentFileSuite, currentSuite, withSuite } from "./Registry.js";
|
|
15
|
+
import { mergeTags } from "./Tags.js";
|
|
16
|
+
export const timeoutOf = (options) => typeof options === "number" ? options : options?.timeout;
|
|
17
|
+
export const retryOf = (options) => typeof options === "object" && options !== null ? options.retry : undefined;
|
|
18
|
+
export const exclusiveOf = (options) => typeof options === "object" && options !== null ? (options.exclusive ?? false) : false;
|
|
19
|
+
export const tagsOf = (options) => typeof options === "object" ? options?.tags : undefined;
|
|
20
|
+
export const optInTagsOf = (options) => typeof options === "object" ? options?.optInTags : undefined;
|
|
21
|
+
const makeDescribe = (config) => {
|
|
22
|
+
const fn = (nameOrBody, second, third) => {
|
|
23
|
+
// Normalize the vitest signatures:
|
|
24
|
+
// describe(name, body)
|
|
25
|
+
// describe(name, body, timeout)
|
|
26
|
+
// describe(name, options, body)
|
|
27
|
+
// describe(body) (via describe.skipIf(...)(() => {}))
|
|
28
|
+
let name;
|
|
29
|
+
let body;
|
|
30
|
+
let sequential = config.sequential;
|
|
31
|
+
let tags;
|
|
32
|
+
let optInTags;
|
|
33
|
+
if (typeof nameOrBody === "function") {
|
|
34
|
+
name = "";
|
|
35
|
+
body = nameOrBody;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
name = nameOrBody;
|
|
39
|
+
if (typeof second === "function") {
|
|
40
|
+
body = second;
|
|
41
|
+
}
|
|
42
|
+
else if (typeof second === "object" && second !== null) {
|
|
43
|
+
tags = second.tags;
|
|
44
|
+
optInTags = second.optInTags;
|
|
45
|
+
if (second.concurrent === true || second.sequential === false) {
|
|
46
|
+
sequential = false;
|
|
47
|
+
}
|
|
48
|
+
else if (second.concurrent === false || second.sequential === true) {
|
|
49
|
+
sequential = true;
|
|
50
|
+
}
|
|
51
|
+
body = typeof third === "function" ? third : undefined;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
body = typeof third === "function" ? third : undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const parent = currentSuite();
|
|
58
|
+
const suite = makeSuite(name, parent, config.mode, tags, optInTags);
|
|
59
|
+
suite.sequential = sequential;
|
|
60
|
+
parent.children.push(suite);
|
|
61
|
+
// `describe.skip` still collects its children (they're reported as
|
|
62
|
+
// skipped, matching vitest); only `todo` suites skip collection.
|
|
63
|
+
if (body !== undefined && config.mode !== "todo") {
|
|
64
|
+
withSuite(suite, body);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
const withMethods = Object.assign(fn, {
|
|
68
|
+
each: (cases) => (name, eachBody, options) => {
|
|
69
|
+
cases.forEach((args, index) => {
|
|
70
|
+
fn(formatEachName(name, args, index), { tags: tagsOf(options), optInTags: optInTagsOf(options) }, () => eachBody(args));
|
|
71
|
+
});
|
|
72
|
+
},
|
|
73
|
+
skipIf: (condition) => makeDescribe(condition ? { ...config, mode: "skip" } : config),
|
|
74
|
+
runIf: (condition) => makeDescribe(condition ? config : { ...config, mode: "skip" }),
|
|
75
|
+
});
|
|
76
|
+
// Lazy getters — Object.assign would evaluate them eagerly and recurse
|
|
77
|
+
// forever (each modifier constructs another DescribeFn).
|
|
78
|
+
Object.defineProperties(withMethods, {
|
|
79
|
+
sequential: { get: () => makeDescribe({ ...config, sequential: true }) },
|
|
80
|
+
concurrent: { get: () => makeDescribe({ ...config, sequential: false }) },
|
|
81
|
+
skip: { get: () => makeDescribe({ ...config, mode: "skip" }) },
|
|
82
|
+
only: { get: () => makeDescribe({ ...config, mode: "only" }) },
|
|
83
|
+
todo: { get: () => makeDescribe({ ...config, mode: "todo" }) },
|
|
84
|
+
});
|
|
85
|
+
return withMethods;
|
|
86
|
+
};
|
|
87
|
+
export const describe = makeDescribe({
|
|
88
|
+
mode: "run",
|
|
89
|
+
sequential: true,
|
|
90
|
+
});
|
|
91
|
+
/** Low-level test registration — used by adapters (e.g. alchemy Test.make). */
|
|
92
|
+
export const registerTest = (options) => {
|
|
93
|
+
const parent = currentSuite();
|
|
94
|
+
parent.children.push({
|
|
95
|
+
type: "test",
|
|
96
|
+
name: options.name,
|
|
97
|
+
tags: mergeTags(parent.tags, options.tags),
|
|
98
|
+
optInTags: mergeTags(parent.optInTags, options.optInTags),
|
|
99
|
+
mode: options.mode,
|
|
100
|
+
fails: options.fails ?? false,
|
|
101
|
+
exclusive: options.exclusive ?? false,
|
|
102
|
+
retry: options.retry,
|
|
103
|
+
timeout: options.timeout,
|
|
104
|
+
body: options.body,
|
|
105
|
+
parent,
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
/** Wrap a plain (sync or async) test function into a self-contained Effect. */
|
|
109
|
+
const fromFn = (fn) => () => Effect.promise(async () => {
|
|
110
|
+
await fn(emptyContext);
|
|
111
|
+
});
|
|
112
|
+
const emptyContext = {};
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
// Effect testers (it.effect / it.live)
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
/**
|
|
117
|
+
* The environment `it.effect` provides, matching @effect/vitest: a TestClock
|
|
118
|
+
* and a TestConsole on top of a per-test Scope.
|
|
119
|
+
*/
|
|
120
|
+
const TestEnv = Layer.mergeAll(TestConsole.layer, TestClock.layer());
|
|
121
|
+
export const makeTester = (mapEffect) => {
|
|
122
|
+
const register = (name, self, options, overrides) => registerTest({
|
|
123
|
+
name,
|
|
124
|
+
mode: "run",
|
|
125
|
+
timeout: timeoutOf(options),
|
|
126
|
+
tags: tagsOf(options),
|
|
127
|
+
optInTags: optInTagsOf(options),
|
|
128
|
+
retry: retryOf(options),
|
|
129
|
+
exclusive: exclusiveOf(options),
|
|
130
|
+
body: () => mapEffect(Effect.suspend(() => self(emptyContext))),
|
|
131
|
+
...overrides,
|
|
132
|
+
});
|
|
133
|
+
const fn = ((name, self, options) => register(name, self, options));
|
|
134
|
+
return Object.assign(fn, {
|
|
135
|
+
skip: (name, self, options) => register(name, self, options, { mode: "skip" }),
|
|
136
|
+
skipIf: (condition) => (name, self, options) => register(name, self, options, { mode: condition ? "skip" : "run" }),
|
|
137
|
+
runIf: (condition) => (name, self, options) => register(name, self, options, { mode: condition ? "run" : "skip" }),
|
|
138
|
+
only: (name, self, options) => register(name, self, options, { mode: "only" }),
|
|
139
|
+
fails: (name, self, options) => register(name, self, options, { fails: true }),
|
|
140
|
+
each: (cases) => (name, self, options) => {
|
|
141
|
+
cases.forEach((args, index) => {
|
|
142
|
+
register(formatEachName(name, args, index), () => self(args), options);
|
|
143
|
+
});
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
};
|
|
147
|
+
const formatEachName = (name, args, index) => {
|
|
148
|
+
let out = name;
|
|
149
|
+
// `$prop` templating (vitest): "Container (dev: $dev)"
|
|
150
|
+
if (out.includes("$") && typeof args === "object" && args !== null) {
|
|
151
|
+
out = out.replace(/\$([a-zA-Z_$][\w.$]*)/g, (match, path) => {
|
|
152
|
+
const value = path
|
|
153
|
+
.split(".")
|
|
154
|
+
.reduce((acc, key) => acc !== null && typeof acc === "object"
|
|
155
|
+
? acc[key]
|
|
156
|
+
: undefined, args);
|
|
157
|
+
return value === undefined ? match : String(value);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
// printf-style templating: "adds %s"
|
|
161
|
+
if (out.includes("%")) {
|
|
162
|
+
out = out.replace(/%[sdifjo#]/g, () => typeof args === "object" ? JSON.stringify(args) : String(args));
|
|
163
|
+
}
|
|
164
|
+
return out === name ? `${name} [${index}]` : out;
|
|
165
|
+
};
|
|
166
|
+
const registerFnTest = (name, fn, options, mode, fails = false) => registerTest({
|
|
167
|
+
name,
|
|
168
|
+
mode: fn === undefined ? "todo" : mode,
|
|
169
|
+
fails,
|
|
170
|
+
timeout: timeoutOf(options),
|
|
171
|
+
tags: tagsOf(options),
|
|
172
|
+
optInTags: optInTagsOf(options),
|
|
173
|
+
retry: retryOf(options),
|
|
174
|
+
exclusive: exclusiveOf(options),
|
|
175
|
+
body: fn === undefined ? undefined : fromFn(fn),
|
|
176
|
+
});
|
|
177
|
+
const makeTestFn = () => {
|
|
178
|
+
const fn = ((name, body, options) => registerFnTest(name, body, options, "run"));
|
|
179
|
+
return Object.assign(fn, {
|
|
180
|
+
skip: (name, body, options) => registerFnTest(name, body, options, "skip"),
|
|
181
|
+
only: (name, body, options) => registerFnTest(name, body, options, "only"),
|
|
182
|
+
todo: (name, body, options) => registerFnTest(name, body, options, "todo"),
|
|
183
|
+
fails: (name, body, options) => registerFnTest(name, body, options, "run", true),
|
|
184
|
+
skipIf: (condition) => (name, body, options) => registerFnTest(name, body, options, condition ? "skip" : "run"),
|
|
185
|
+
runIf: (condition) => (name, body, options) => registerFnTest(name, body, options, condition ? "run" : "skip"),
|
|
186
|
+
each: (cases) => (name, body, options) => {
|
|
187
|
+
cases.forEach((args, index) => {
|
|
188
|
+
registerFnTest(formatEachName(name, args, index), () => body(args), options, "run");
|
|
189
|
+
});
|
|
190
|
+
},
|
|
191
|
+
effect: makeTester((self) => self.pipe(Effect.scoped, Effect.provide(TestEnv))),
|
|
192
|
+
live: makeTester((self) => Effect.scoped(self)),
|
|
193
|
+
});
|
|
194
|
+
};
|
|
195
|
+
export const it = makeTestFn();
|
|
196
|
+
export const test = it;
|
|
197
|
+
/** Framework cleanup after user teardown, including files with no runnable tests. */
|
|
198
|
+
export const registerFileCleanup = (hook) => {
|
|
199
|
+
currentFileSuite().cleanups.push(hook);
|
|
200
|
+
};
|
|
201
|
+
/** Low-level hook registration with an Effect body — used by adapters. */
|
|
202
|
+
export const registerHook = (kind, hook) => {
|
|
203
|
+
currentSuite()[kind].push(hook);
|
|
204
|
+
};
|
|
205
|
+
const hookFromFn = (fn) => () => Effect.promise(async () => {
|
|
206
|
+
await fn();
|
|
207
|
+
});
|
|
208
|
+
export const beforeAll = (fn, timeout) => registerHook("beforeAll", { body: hookFromFn(fn), timeout });
|
|
209
|
+
export const afterAll = (fn, timeout) => registerHook("afterAll", { body: hookFromFn(fn), timeout });
|
|
210
|
+
export const beforeEach = (fn, timeout) => registerHook("beforeEach", { body: hookFromFn(fn), timeout });
|
|
211
|
+
export const afterEach = (fn, timeout) => registerHook("afterEach", { body: hookFromFn(fn), timeout });
|
|
212
|
+
export const layer = (layer_, options) => (...args) => {
|
|
213
|
+
const excludeTestServices = options?.excludeTestServices ?? false;
|
|
214
|
+
const withTestEnv = excludeTestServices
|
|
215
|
+
? layer_
|
|
216
|
+
: Layer.provideMerge(layer_, TestEnv);
|
|
217
|
+
const memoMap = options?.memoMap ?? Effect.runSync(Layer.makeMemoMap);
|
|
218
|
+
const scope = Scope.makeUnsafe();
|
|
219
|
+
const contextEffect = Layer.buildWithMemoMap(withTestEnv, memoMap, scope).pipe(Effect.orDie, Effect.cached, Effect.runSync);
|
|
220
|
+
const makeMethods = () => ({
|
|
221
|
+
effect: makeTester((self) => Effect.flatMap(contextEffect, (context) => self.pipe(Effect.scoped, Effect.provide(context)))),
|
|
222
|
+
layer: (nested, nestedOptions) => layer(Layer.provideMerge(nested, withTestEnv), {
|
|
223
|
+
...nestedOptions,
|
|
224
|
+
memoMap: Layer.forkMemoMapUnsafe(memoMap),
|
|
225
|
+
excludeTestServices,
|
|
226
|
+
}),
|
|
227
|
+
});
|
|
228
|
+
const register = () => {
|
|
229
|
+
const cleanup = {
|
|
230
|
+
body: () => Scope.close(scope, Exit.void),
|
|
231
|
+
timeout: options?.timeout,
|
|
232
|
+
};
|
|
233
|
+
registerHook("afterAll", cleanup);
|
|
234
|
+
registerFileCleanup(cleanup);
|
|
235
|
+
const f = (args.length === 1 ? args[0] : args[1]);
|
|
236
|
+
f(makeMethods());
|
|
237
|
+
};
|
|
238
|
+
if (args.length === 2) {
|
|
239
|
+
describe(args[0], register);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
register();
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
//# sourceMappingURL=Api.js.map
|
package/lib/Api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Api.js","sourceRoot":"","sources":["../src/Api.ts"],"names":[],"mappings":"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"}
|
package/lib/Bun.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/** @effect-diagnostics anyUnknownInErrorContext:off */
|
|
2
|
+
import bun from "bun:test";
|
|
3
|
+
import type { HookOptions } from "node:test";
|
|
4
|
+
import type { StackDefinition } from "alchemy/Stack";
|
|
5
|
+
import * as Effect from "effect/Effect";
|
|
6
|
+
import * as Core from "./Core.ts";
|
|
7
|
+
export { executeWhenReady, getWhenReady, guardContentType, guardedFetchLayer, rpcClientLayer, WorkerNotReady, type EdgeGuardOptions, type WhenReadyOptions, } from "./Http.ts";
|
|
8
|
+
export type MakeOptions<ROut = any> = Core.MakeOptions<ROut>;
|
|
9
|
+
export type ScratchStack = Core.ScratchStack;
|
|
10
|
+
export type TestEffect<A, R = never> = Core.TestEffect<A, R>;
|
|
11
|
+
export declare const defaultStage: typeof Core.defaultStage;
|
|
12
|
+
export declare const resolveStage: typeof Core.resolveStage;
|
|
13
|
+
export interface TestApi {
|
|
14
|
+
test: TestFn;
|
|
15
|
+
beforeAll: BeforeAllFn;
|
|
16
|
+
beforeEach: BeforeEachFn;
|
|
17
|
+
afterAll: AfterAllFn;
|
|
18
|
+
afterEach: AfterEachFn;
|
|
19
|
+
deploy: Core.Deploy;
|
|
20
|
+
destroy: <ROut>(stack: StackDefinition<ROut>, options?: {
|
|
21
|
+
stage?: string;
|
|
22
|
+
include?: never;
|
|
23
|
+
exclude?: never;
|
|
24
|
+
}) => ReturnType<typeof Core.destroy>;
|
|
25
|
+
}
|
|
26
|
+
interface TestFn {
|
|
27
|
+
(name: string, eff: TestEffect<void>, options?: bun.TestOptions): void;
|
|
28
|
+
skip: (name: string, eff: TestEffect<void>, options?: bun.TestOptions) => void;
|
|
29
|
+
skipIf: (condition: boolean) => (name: string, eff: TestEffect<void>, options?: bun.TestOptions) => void;
|
|
30
|
+
only: (name: string, eff: TestEffect<void>, options?: bun.TestOptions) => void;
|
|
31
|
+
todo: (name: string, eff: TestEffect<void>, options?: bun.TestOptions) => void;
|
|
32
|
+
provider: ProviderFn;
|
|
33
|
+
}
|
|
34
|
+
interface ProviderFn {
|
|
35
|
+
(name: string, fn: (stack: ScratchStack) => Effect.Effect<void, any, any>, options?: bun.TestOptions): void;
|
|
36
|
+
skip: (name: string, fn: (stack: ScratchStack) => Effect.Effect<void, any, any>, options?: bun.TestOptions) => void;
|
|
37
|
+
skipIf: (condition: boolean) => (name: string, fn: (stack: ScratchStack) => Effect.Effect<void, any, any>, options?: bun.TestOptions) => void;
|
|
38
|
+
}
|
|
39
|
+
interface BeforeAllFn {
|
|
40
|
+
<A>(eff: TestEffect<A>, options?: HookOptions): Effect.Effect<A>;
|
|
41
|
+
}
|
|
42
|
+
interface BeforeEachFn {
|
|
43
|
+
(eff: TestEffect<void>, options?: HookOptions): void;
|
|
44
|
+
}
|
|
45
|
+
interface AfterAllFn {
|
|
46
|
+
(eff: TestEffect<any>, options?: HookOptions): void;
|
|
47
|
+
skipIf: (predicate: boolean) => (eff: TestEffect<any>, options?: HookOptions) => void;
|
|
48
|
+
}
|
|
49
|
+
interface AfterEachFn {
|
|
50
|
+
(eff: TestEffect<void>, options?: HookOptions): void;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Build the per-file test API. Configure providers / state once at the top of
|
|
54
|
+
* the test file:
|
|
55
|
+
*
|
|
56
|
+
* ```ts
|
|
57
|
+
* import * as Test from "@alchemy.run/test/Bun";
|
|
58
|
+
* import * as Cloudflare from "@alchemy.run/cloudflare";
|
|
59
|
+
*
|
|
60
|
+
* const { test, deploy, destroy, beforeAll, afterAll } = Test.make({
|
|
61
|
+
* providers: Cloudflare.providers(),
|
|
62
|
+
* state: Cloudflare.state(),
|
|
63
|
+
* });
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare const make: <ROut = any>(options: MakeOptions<ROut>) => TestApi;
|
|
67
|
+
//# sourceMappingURL=Bun.d.ts.map
|
package/lib/Bun.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Bun.d.ts","sourceRoot":"","sources":["../src/Bun.ts"],"names":[],"mappings":"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"}
|
package/lib/Bun.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/** @effect-diagnostics anyUnknownInErrorContext:off */
|
|
2
|
+
import bun from "bun:test";
|
|
3
|
+
import * as Cause from "effect/Cause";
|
|
4
|
+
import * as Duration from "effect/Duration";
|
|
5
|
+
import * as Effect from "effect/Effect";
|
|
6
|
+
import * as Exit from "effect/Exit";
|
|
7
|
+
import * as Scope from "effect/Scope";
|
|
8
|
+
import * as Core from "./Core.js";
|
|
9
|
+
export { executeWhenReady, getWhenReady, guardContentType, guardedFetchLayer, rpcClientLayer, WorkerNotReady, } from "./Http.js";
|
|
10
|
+
export const defaultStage = Core.defaultStage;
|
|
11
|
+
export const resolveStage = Core.resolveStage;
|
|
12
|
+
const DEFAULT_HOOK_TIMEOUT = { timeout: 120_000 };
|
|
13
|
+
/** The timeout bun applies to a test, from its options. */
|
|
14
|
+
const timeoutOf = (options) => typeof options === "number" ? options : options?.timeout;
|
|
15
|
+
/**
|
|
16
|
+
* Interrupt `eff` shortly before bun's own timeout. When bun times a test or
|
|
17
|
+
* hook out it only stops waiting: the effect keeps running, so the file's
|
|
18
|
+
* `afterAll` destroy races a deploy still creating resources, and whatever
|
|
19
|
+
* that deploy creates afterwards is never cleaned up. Interrupting it first
|
|
20
|
+
* lets the engine record what it created, so the destroy that follows finds
|
|
21
|
+
* it.
|
|
22
|
+
*/
|
|
23
|
+
const DEADLINE_MARGIN_MS = 5_000;
|
|
24
|
+
const withDeadline = (eff, timeout) => timeout === undefined || timeout <= DEADLINE_MARGIN_MS * 2
|
|
25
|
+
? eff
|
|
26
|
+
: eff.pipe(Effect.timeout(Duration.millis(timeout - DEADLINE_MARGIN_MS)));
|
|
27
|
+
/**
|
|
28
|
+
* Build the per-file test API. Configure providers / state once at the top of
|
|
29
|
+
* the test file:
|
|
30
|
+
*
|
|
31
|
+
* ```ts
|
|
32
|
+
* import * as Test from "@alchemy.run/test/Bun";
|
|
33
|
+
* import * as Cloudflare from "@alchemy.run/cloudflare";
|
|
34
|
+
*
|
|
35
|
+
* const { test, deploy, destroy, beforeAll, afterAll } = Test.make({
|
|
36
|
+
* providers: Cloudflare.providers(),
|
|
37
|
+
* state: Cloudflare.state(),
|
|
38
|
+
* });
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export const make = (options) => {
|
|
42
|
+
// Single scope shared across `beforeAll`, every `test`, and `afterAll`.
|
|
43
|
+
// Scoped resources in dev mode (the Cloudflare sidecar process and its
|
|
44
|
+
// workerd children) must outlive a single `Effect.runPromise` boundary,
|
|
45
|
+
// otherwise the proxy is killed the moment `beforeAll(deploy(Stack))`
|
|
46
|
+
// resolves and every later `HttpClient.get(workerUrl)` hits a dead port.
|
|
47
|
+
// The scope is closed by `destroy(...)` (or never — the next test run
|
|
48
|
+
// reclaims any leaked sidecar via the lock file).
|
|
49
|
+
const sharedScope = Scope.makeUnsafe("sequential");
|
|
50
|
+
// In dev mode, run local providers behind one file-scoped RPC sidecar
|
|
51
|
+
// (the `alchemy dev` topology). Lives in its own scope — NOT sharedScope,
|
|
52
|
+
// which `destroy(Stack)` closes mid-file in self-contained tests — and is
|
|
53
|
+
// closed by the fallback afterAll below.
|
|
54
|
+
const sidecar = Core.makeSidecarHandle(options);
|
|
55
|
+
const runEff = (eff, timeout) => Core.run(withDeadline(eff, timeout), options, sharedScope, sidecar);
|
|
56
|
+
const test = ((name, eff, opts) => {
|
|
57
|
+
bun.test(name, () => runEff(eff, timeoutOf(opts)), opts);
|
|
58
|
+
});
|
|
59
|
+
test.skip = (name, eff, opts) => {
|
|
60
|
+
bun.test.skip(name, () => runEff(eff, timeoutOf(opts)), opts);
|
|
61
|
+
};
|
|
62
|
+
test.skipIf = (condition) => (name, eff, opts) => {
|
|
63
|
+
bun.test.skipIf(condition)(name, () => runEff(eff, timeoutOf(opts)), opts);
|
|
64
|
+
};
|
|
65
|
+
test.only = (name, eff, opts) => {
|
|
66
|
+
bun.test.only(name, () => runEff(eff, timeoutOf(opts)), opts);
|
|
67
|
+
};
|
|
68
|
+
test.todo = (name, eff, opts) => {
|
|
69
|
+
bun.test.todo(name, () => runEff(eff, timeoutOf(opts)), opts);
|
|
70
|
+
};
|
|
71
|
+
const runProvider = (name, fn, timeout) => {
|
|
72
|
+
const scratch = Core.scratchStack(options, name);
|
|
73
|
+
return Core.run(withDeadline(Core.withProviders(fn(scratch), options, scratch.name), timeout), { ...options, state: scratch.state }, sharedScope, sidecar);
|
|
74
|
+
};
|
|
75
|
+
const provider = ((name, fn, opts) => {
|
|
76
|
+
bun.test(name, () => runProvider(name, fn, timeoutOf(opts)), opts);
|
|
77
|
+
});
|
|
78
|
+
provider.skip = (name, fn, opts) => {
|
|
79
|
+
bun.test.skip(name, () => runProvider(name, fn, timeoutOf(opts)), opts);
|
|
80
|
+
};
|
|
81
|
+
provider.skipIf = (condition) => (name, fn, opts) => {
|
|
82
|
+
bun.test.skipIf(condition)(name, () => runProvider(name, fn, timeoutOf(opts)), opts);
|
|
83
|
+
};
|
|
84
|
+
test.provider = provider;
|
|
85
|
+
const beforeAll = (eff, hookOptions) => {
|
|
86
|
+
let result;
|
|
87
|
+
const options = hookOptions ?? DEFAULT_HOOK_TIMEOUT;
|
|
88
|
+
bun.beforeAll(() => runEff(eff, options.timeout).then((v) => (result = v)), options);
|
|
89
|
+
return Effect.sync(() => result);
|
|
90
|
+
};
|
|
91
|
+
const beforeEach = (eff, hookOptions) => {
|
|
92
|
+
bun.beforeEach(() => runEff(eff), hookOptions);
|
|
93
|
+
};
|
|
94
|
+
// bun:test stops running later `afterAll` hooks once one throws, which
|
|
95
|
+
// would skip the fallback cleanup hook below — leaking the shared scope
|
|
96
|
+
// and the sidecar for the rest of the process whenever a teardown
|
|
97
|
+
// assertion fails. Guard every user teardown: on failure, run the
|
|
98
|
+
// (idempotent) cleanup before rethrowing so the failure still fails the
|
|
99
|
+
// suite. (`closeAll` is initialized below; hooks only run after `make`
|
|
100
|
+
// returns.)
|
|
101
|
+
const guardTeardown = (eff) => () => runEff(eff).catch(async (error) => {
|
|
102
|
+
await Effect.runPromise(closeAll);
|
|
103
|
+
throw error;
|
|
104
|
+
});
|
|
105
|
+
const afterAll = ((eff, hookOptions) => {
|
|
106
|
+
bun.afterAll(guardTeardown(eff), hookOptions ?? DEFAULT_HOOK_TIMEOUT);
|
|
107
|
+
});
|
|
108
|
+
afterAll.skipIf = (predicate) => (eff, hookOptions) => {
|
|
109
|
+
if (predicate)
|
|
110
|
+
return;
|
|
111
|
+
bun.afterAll(guardTeardown(eff), hookOptions ?? DEFAULT_HOOK_TIMEOUT);
|
|
112
|
+
};
|
|
113
|
+
const afterEach = (eff, hookOptions) => {
|
|
114
|
+
bun.afterEach(() => runEff(eff), hookOptions);
|
|
115
|
+
};
|
|
116
|
+
// `destroy(Stack)` needs the dev sidecar alive so it can call `sidecar.stop`
|
|
117
|
+
// for each worker. We close the shared scope only AFTER destroy completes.
|
|
118
|
+
// `Scope.close` on an already-closed scope is a no-op, so it's safe for both
|
|
119
|
+
// the destroy wrapper AND the fallback cleanup hook below to call it.
|
|
120
|
+
const closeScope = Effect.suspend(() => Scope.close(sharedScope, Exit.void)).pipe(Effect.ignore);
|
|
121
|
+
// Fallback cleanup: if the user never calls `destroy(Stack)` (e.g.
|
|
122
|
+
// `NO_DESTROY=1`), nothing else closes the shared scope and the sidecar
|
|
123
|
+
// child process leaks past the test process. Register an `afterAll` that
|
|
124
|
+
// closes it (and the RPC sidecar, which lives in its own scope so that
|
|
125
|
+
// mid-file `destroy(Stack)` calls can't kill it for later tests). We defer
|
|
126
|
+
// registration to a microtask so it runs AFTER any user-registered
|
|
127
|
+
// `afterAll` (including `destroy(Stack)`); bun runs afterAll hooks in
|
|
128
|
+
// registration order.
|
|
129
|
+
const closeAll = sidecar ? Effect.andThen(closeScope, sidecar.close) : closeScope;
|
|
130
|
+
queueMicrotask(() => {
|
|
131
|
+
bun.afterAll(() => Effect.runPromise(closeAll), DEFAULT_HOOK_TIMEOUT);
|
|
132
|
+
});
|
|
133
|
+
return {
|
|
134
|
+
test,
|
|
135
|
+
beforeAll,
|
|
136
|
+
beforeEach,
|
|
137
|
+
afterAll,
|
|
138
|
+
afterEach,
|
|
139
|
+
deploy: Core.makeDeploy(options, sharedScope),
|
|
140
|
+
destroy: (stack, callOpts) => Core.destroy(options, stack, { ...callOpts, scope: sharedScope }).pipe(Effect.ensuring(closeScope)),
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
//# sourceMappingURL=Bun.js.map
|
package/lib/Bun.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Bun.js","sourceRoot":"","sources":["../src/Bun.ts"],"names":[],"mappings":"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"}
|
package/lib/Capture.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { LogEntry } from "./Model.ts";
|
|
2
|
+
/** Bounded live previews; every original entry is persisted before trimming. */
|
|
3
|
+
export declare const makeCapture: (limits?: {
|
|
4
|
+
capture: number;
|
|
5
|
+
total: number;
|
|
6
|
+
}) => {
|
|
7
|
+
create: (persist: (entry: LogEntry) => void) => Array<LogEntry>;
|
|
8
|
+
release: (buffer: Array<LogEntry>) => void;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=Capture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Capture.d.ts","sourceRoot":"","sources":["../src/Capture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAM3C,gFAAgF;AAChF,eAAO,MAAM,WAAW;IAAe,OAAO;IAAiB,KAAK;;sBAgCzC,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,KAAG,KAAK,CAAC,QAAQ,CAAC;sBA5B3C,KAAK,CAAC,QAAQ,CAAC;CA4DzC,CAAC"}
|
package/lib/Capture.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const CAPTURE_BYTES = 256 * 1024;
|
|
2
|
+
const TOTAL_BYTES = 16 * 1024 * 1024;
|
|
3
|
+
const TRUNCATED = "[Earlier output omitted from preview; full output is in the run log.]";
|
|
4
|
+
/** Bounded live previews; every original entry is persisted before trimming. */
|
|
5
|
+
export const makeCapture = (limits = { capture: CAPTURE_BYTES, total: TOTAL_BYTES }) => {
|
|
6
|
+
const buffers = new Map();
|
|
7
|
+
let total = 0;
|
|
8
|
+
const size = (entry) => Buffer.byteLength(entry.message, "utf8") + 64;
|
|
9
|
+
const release = (buffer) => {
|
|
10
|
+
total -= buffers.get(buffer) ?? 0;
|
|
11
|
+
buffers.delete(buffer);
|
|
12
|
+
buffer.length = 0;
|
|
13
|
+
};
|
|
14
|
+
const trim = (buffer, limit) => {
|
|
15
|
+
let bytes = buffers.get(buffer) ?? 0;
|
|
16
|
+
let removed = false;
|
|
17
|
+
while (bytes > limit && buffer.length > 0) {
|
|
18
|
+
const entry = buffer.shift();
|
|
19
|
+
const cost = size(entry);
|
|
20
|
+
bytes -= cost;
|
|
21
|
+
total -= cost;
|
|
22
|
+
removed = true;
|
|
23
|
+
}
|
|
24
|
+
if (removed && buffer.length > 0 && buffer[0].message !== TRUNCATED) {
|
|
25
|
+
const entry = {
|
|
26
|
+
level: "info",
|
|
27
|
+
message: TRUNCATED,
|
|
28
|
+
time: buffer[0].time,
|
|
29
|
+
};
|
|
30
|
+
buffer.unshift(entry);
|
|
31
|
+
bytes += size(entry);
|
|
32
|
+
total += size(entry);
|
|
33
|
+
}
|
|
34
|
+
if (bytes === 0)
|
|
35
|
+
buffers.delete(buffer);
|
|
36
|
+
else
|
|
37
|
+
buffers.set(buffer, bytes);
|
|
38
|
+
};
|
|
39
|
+
const create = (persist) => {
|
|
40
|
+
const buffer = [];
|
|
41
|
+
buffer.push = (...entries) => {
|
|
42
|
+
for (const entry of entries) {
|
|
43
|
+
persist(entry);
|
|
44
|
+
// A single oversized message must not defeat either preview limit.
|
|
45
|
+
const maxChars = Math.max(0, Math.floor((Math.min(limits.capture, limits.total) - 256) / 4));
|
|
46
|
+
const preview = entry.message.length > maxChars
|
|
47
|
+
? {
|
|
48
|
+
...entry,
|
|
49
|
+
message: `${TRUNCATED}\n${maxChars === 0 ? "" : entry.message.slice(-maxChars)}`,
|
|
50
|
+
}
|
|
51
|
+
: entry;
|
|
52
|
+
Array.prototype.push.call(buffer, preview);
|
|
53
|
+
const cost = size(preview);
|
|
54
|
+
buffers.set(buffer, (buffers.get(buffer) ?? 0) + cost);
|
|
55
|
+
total += cost;
|
|
56
|
+
trim(buffer, Math.max(0, limits.capture - 256));
|
|
57
|
+
while (total > limits.total && buffers.size > 0) {
|
|
58
|
+
const oldest = buffers.keys().next().value;
|
|
59
|
+
release(oldest);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return buffer.length;
|
|
63
|
+
};
|
|
64
|
+
return buffer;
|
|
65
|
+
};
|
|
66
|
+
return { create, release };
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=Capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Capture.js","sourceRoot":"","sources":["../src/Capture.ts"],"names":[],"mappings":"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"}
|