@c9up/helix 0.1.3 → 0.1.5

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 (235) hide show
  1. package/dist/cli/coverage/aggregate.d.ts +24 -0
  2. package/dist/cli/coverage/aggregate.d.ts.map +1 -0
  3. package/dist/cli/coverage/aggregate.js +215 -0
  4. package/dist/cli/coverage/aggregate.js.map +1 -0
  5. package/dist/cli/coverage/collect.d.ts +13 -0
  6. package/dist/cli/coverage/collect.d.ts.map +1 -0
  7. package/dist/cli/coverage/collect.js +66 -0
  8. package/dist/cli/coverage/collect.js.map +1 -0
  9. package/dist/cli/coverage/diff/base.d.ts +17 -0
  10. package/dist/cli/coverage/diff/base.d.ts.map +1 -0
  11. package/dist/cli/coverage/diff/base.js +44 -0
  12. package/dist/cli/coverage/diff/base.js.map +1 -0
  13. package/dist/cli/coverage/diff/index.d.ts +25 -0
  14. package/dist/cli/coverage/diff/index.d.ts.map +1 -0
  15. package/dist/cli/coverage/diff/index.js +119 -0
  16. package/dist/cli/coverage/diff/index.js.map +1 -0
  17. package/dist/cli/coverage/diff/overlay.d.ts +19 -0
  18. package/dist/cli/coverage/diff/overlay.d.ts.map +1 -0
  19. package/dist/cli/coverage/diff/overlay.js +58 -0
  20. package/dist/cli/coverage/diff/overlay.js.map +1 -0
  21. package/dist/cli/coverage/diff/parse.d.ts +27 -0
  22. package/dist/cli/coverage/diff/parse.d.ts.map +1 -0
  23. package/dist/cli/coverage/diff/parse.js +105 -0
  24. package/dist/cli/coverage/diff/parse.js.map +1 -0
  25. package/dist/cli/coverage/diff/reporters.d.ts +12 -0
  26. package/dist/cli/coverage/diff/reporters.d.ts.map +1 -0
  27. package/dist/cli/coverage/diff/reporters.js +59 -0
  28. package/dist/cli/coverage/diff/reporters.js.map +1 -0
  29. package/dist/cli/coverage/diff/types.d.ts +46 -0
  30. package/dist/cli/coverage/diff/types.d.ts.map +1 -0
  31. package/dist/cli/coverage/diff/types.js +15 -0
  32. package/dist/cli/coverage/diff/types.js.map +1 -0
  33. package/dist/cli/coverage/filter.d.ts +13 -0
  34. package/dist/cli/coverage/filter.d.ts.map +1 -0
  35. package/dist/cli/coverage/filter.js +60 -0
  36. package/dist/cli/coverage/filter.js.map +1 -0
  37. package/dist/cli/coverage/glob.d.ts +4 -0
  38. package/dist/cli/coverage/glob.d.ts.map +1 -0
  39. package/dist/cli/coverage/glob.js +0 -0
  40. package/dist/cli/coverage/glob.js.map +1 -0
  41. package/dist/cli/coverage/index.d.ts +40 -0
  42. package/dist/cli/coverage/index.d.ts.map +1 -0
  43. package/dist/cli/coverage/index.js +85 -0
  44. package/dist/cli/coverage/index.js.map +1 -0
  45. package/dist/cli/coverage/reporters/json.d.ts +13 -0
  46. package/dist/cli/coverage/reporters/json.d.ts.map +1 -0
  47. package/dist/cli/coverage/reporters/json.js +37 -0
  48. package/dist/cli/coverage/reporters/json.js.map +1 -0
  49. package/dist/cli/coverage/reporters/lcov.d.ts +13 -0
  50. package/dist/cli/coverage/reporters/lcov.d.ts.map +1 -0
  51. package/dist/cli/coverage/reporters/lcov.js +51 -0
  52. package/dist/cli/coverage/reporters/lcov.js.map +1 -0
  53. package/dist/cli/coverage/reporters/text.d.ts +8 -0
  54. package/dist/cli/coverage/reporters/text.d.ts.map +1 -0
  55. package/dist/cli/coverage/reporters/text.js +39 -0
  56. package/dist/cli/coverage/reporters/text.js.map +1 -0
  57. package/dist/cli/coverage/thresholds.d.ts +14 -0
  58. package/dist/cli/coverage/thresholds.d.ts.map +1 -0
  59. package/dist/cli/coverage/thresholds.js +58 -0
  60. package/dist/cli/coverage/thresholds.js.map +1 -0
  61. package/dist/cli/coverage/types.d.ts +118 -0
  62. package/dist/cli/coverage/types.d.ts.map +1 -0
  63. package/dist/cli/coverage/types.js +8 -0
  64. package/dist/cli/coverage/types.js.map +1 -0
  65. package/dist/cli/discover.d.ts +27 -0
  66. package/dist/cli/discover.d.ts.map +1 -0
  67. package/dist/cli/discover.js +142 -0
  68. package/dist/cli/discover.js.map +1 -0
  69. package/dist/cli/native.d.ts +43 -0
  70. package/dist/cli/native.d.ts.map +1 -0
  71. package/dist/cli/native.js +64 -0
  72. package/dist/cli/native.js.map +1 -0
  73. package/dist/cli/pool.d.ts +55 -0
  74. package/dist/cli/pool.d.ts.map +1 -0
  75. package/dist/cli/pool.js +404 -0
  76. package/dist/cli/pool.js.map +1 -0
  77. package/dist/cli/reporter.d.ts +51 -0
  78. package/dist/cli/reporter.d.ts.map +1 -0
  79. package/dist/cli/reporter.js +124 -0
  80. package/dist/cli/reporter.js.map +1 -0
  81. package/dist/cli/run.d.ts +61 -0
  82. package/dist/cli/run.d.ts.map +1 -0
  83. package/dist/cli/run.js +302 -0
  84. package/dist/cli/run.js.map +1 -0
  85. package/dist/cli/summary.d.ts +18 -0
  86. package/dist/cli/summary.d.ts.map +1 -0
  87. package/dist/cli/summary.js +20 -0
  88. package/dist/cli/summary.js.map +1 -0
  89. package/dist/cli/watch/loop.d.ts +26 -0
  90. package/dist/cli/watch/loop.d.ts.map +1 -0
  91. package/dist/cli/watch/loop.js +133 -0
  92. package/dist/cli/watch/loop.js.map +1 -0
  93. package/dist/cli/watch/types.d.ts +22 -0
  94. package/dist/cli/watch/types.d.ts.map +1 -0
  95. package/dist/cli/watch/types.js +6 -0
  96. package/dist/cli/watch/types.js.map +1 -0
  97. package/dist/cli/watch/watcher.d.ts +25 -0
  98. package/dist/cli/watch/watcher.d.ts.map +1 -0
  99. package/dist/cli/watch/watcher.js +122 -0
  100. package/dist/cli/watch/watcher.js.map +1 -0
  101. package/dist/container/index.d.ts +7 -0
  102. package/dist/container/index.d.ts.map +1 -0
  103. package/dist/container/index.js +6 -0
  104. package/dist/container/index.js.map +1 -0
  105. package/{src/container/override.ts → dist/container/override.d.ts} +6 -46
  106. package/dist/container/override.d.ts.map +1 -0
  107. package/dist/container/override.js +67 -0
  108. package/dist/container/override.js.map +1 -0
  109. package/{src/container/spy.ts → dist/container/spy.d.ts} +2 -6
  110. package/dist/container/spy.d.ts.map +1 -0
  111. package/dist/container/spy.js +23 -0
  112. package/dist/container/spy.js.map +1 -0
  113. package/dist/index.d.ts +20 -0
  114. package/dist/index.d.ts.map +1 -0
  115. package/{src/index.ts → dist/index.js} +2 -25
  116. package/dist/index.js.map +1 -0
  117. package/dist/runtime/assertion-error.d.ts +20 -0
  118. package/dist/runtime/assertion-error.d.ts.map +1 -0
  119. package/dist/runtime/assertion-error.js +23 -0
  120. package/dist/runtime/assertion-error.js.map +1 -0
  121. package/dist/runtime/cli-worker.d.ts +25 -0
  122. package/dist/runtime/cli-worker.d.ts.map +1 -0
  123. package/dist/runtime/cli-worker.js +128 -0
  124. package/dist/runtime/cli-worker.js.map +1 -0
  125. package/dist/runtime/equals.d.ts +25 -0
  126. package/dist/runtime/equals.d.ts.map +1 -0
  127. package/dist/runtime/equals.js +343 -0
  128. package/dist/runtime/equals.js.map +1 -0
  129. package/dist/runtime/expect.d.ts +32 -0
  130. package/dist/runtime/expect.d.ts.map +1 -0
  131. package/dist/runtime/expect.js +121 -0
  132. package/dist/runtime/expect.js.map +1 -0
  133. package/{src/runtime/index.ts → dist/runtime/index.d.ts} +5 -27
  134. package/dist/runtime/index.d.ts.map +1 -0
  135. package/dist/runtime/index.js +17 -0
  136. package/dist/runtime/index.js.map +1 -0
  137. package/{src/runtime/lifecycle.ts → dist/runtime/lifecycle.d.ts} +2 -8
  138. package/dist/runtime/lifecycle.d.ts.map +1 -0
  139. package/dist/runtime/lifecycle.js +10 -0
  140. package/dist/runtime/lifecycle.js.map +1 -0
  141. package/dist/runtime/matchers.d.ts +42 -0
  142. package/dist/runtime/matchers.d.ts.map +1 -0
  143. package/dist/runtime/matchers.js +375 -0
  144. package/dist/runtime/matchers.js.map +1 -0
  145. package/dist/runtime/run.d.ts +55 -0
  146. package/dist/runtime/run.d.ts.map +1 -0
  147. package/dist/runtime/run.js +456 -0
  148. package/dist/runtime/run.js.map +1 -0
  149. package/dist/runtime/suite.d.ts +91 -0
  150. package/dist/runtime/suite.d.ts.map +1 -0
  151. package/dist/runtime/suite.js +206 -0
  152. package/dist/runtime/suite.js.map +1 -0
  153. package/dist/runtime/test-context.d.ts +25 -0
  154. package/dist/runtime/test-context.d.ts.map +1 -0
  155. package/dist/runtime/test-context.js +52 -0
  156. package/dist/runtime/test-context.js.map +1 -0
  157. package/dist/runtime/vi/fake-timers.d.ts +48 -0
  158. package/dist/runtime/vi/fake-timers.d.ts.map +1 -0
  159. package/dist/runtime/vi/fake-timers.js +317 -0
  160. package/dist/runtime/vi/fake-timers.js.map +1 -0
  161. package/dist/runtime/vi/index.d.ts +70 -0
  162. package/dist/runtime/vi/index.d.ts.map +1 -0
  163. package/dist/runtime/vi/index.js +209 -0
  164. package/dist/runtime/vi/index.js.map +1 -0
  165. package/dist/runtime/vi/spy.d.ts +54 -0
  166. package/dist/runtime/vi/spy.d.ts.map +1 -0
  167. package/dist/runtime/vi/spy.js +159 -0
  168. package/dist/runtime/vi/spy.js.map +1 -0
  169. package/dist/runtime/vi/spyOn.d.ts +28 -0
  170. package/dist/runtime/vi/spyOn.d.ts.map +1 -0
  171. package/dist/runtime/vi/spyOn.js +121 -0
  172. package/dist/runtime/vi/spyOn.js.map +1 -0
  173. package/dist/runtime/vi/system-time.d.ts +30 -0
  174. package/dist/runtime/vi/system-time.d.ts.map +1 -0
  175. package/dist/runtime/vi/system-time.js +100 -0
  176. package/dist/runtime/vi/system-time.js.map +1 -0
  177. package/dist/runtime/worker.d.ts +26 -0
  178. package/dist/runtime/worker.d.ts.map +1 -0
  179. package/dist/runtime/worker.js +195 -0
  180. package/dist/runtime/worker.js.map +1 -0
  181. package/dist/time/freeze.d.ts +80 -0
  182. package/dist/time/freeze.d.ts.map +1 -0
  183. package/dist/time/freeze.js +184 -0
  184. package/dist/time/freeze.js.map +1 -0
  185. package/{src/time/index.ts → dist/time/index.d.ts} +1 -1
  186. package/dist/time/index.d.ts.map +1 -0
  187. package/dist/time/index.js +15 -0
  188. package/dist/time/index.js.map +1 -0
  189. package/index.darwin-arm64.node +0 -0
  190. package/index.darwin-x64.node +0 -0
  191. package/index.linux-arm64-gnu.node +0 -0
  192. package/index.linux-x64-gnu.node +0 -0
  193. package/index.win32-x64-msvc.node +0 -0
  194. package/package.json +2 -2
  195. package/src/cli/coverage/aggregate.ts +0 -231
  196. package/src/cli/coverage/collect.ts +0 -63
  197. package/src/cli/coverage/diff/base.ts +0 -46
  198. package/src/cli/coverage/diff/index.ts +0 -160
  199. package/src/cli/coverage/diff/overlay.ts +0 -62
  200. package/src/cli/coverage/diff/parse.ts +0 -121
  201. package/src/cli/coverage/diff/reporters.ts +0 -82
  202. package/src/cli/coverage/diff/types.ts +0 -46
  203. package/src/cli/coverage/filter.ts +0 -71
  204. package/src/cli/coverage/glob.ts +0 -0
  205. package/src/cli/coverage/index.ts +0 -126
  206. package/src/cli/coverage/reporters/json.ts +0 -40
  207. package/src/cli/coverage/reporters/lcov.ts +0 -54
  208. package/src/cli/coverage/reporters/text.ts +0 -48
  209. package/src/cli/coverage/thresholds.ts +0 -73
  210. package/src/cli/coverage/types.ts +0 -93
  211. package/src/cli/discover.ts +0 -174
  212. package/src/cli/native.ts +0 -104
  213. package/src/cli/pool.ts +0 -486
  214. package/src/cli/reporter.ts +0 -155
  215. package/src/cli/run.ts +0 -440
  216. package/src/cli/summary.ts +0 -42
  217. package/src/cli/watch/loop.ts +0 -159
  218. package/src/cli/watch/types.ts +0 -22
  219. package/src/cli/watch/watcher.ts +0 -145
  220. package/src/container/index.ts +0 -16
  221. package/src/runtime/assertion-error.ts +0 -38
  222. package/src/runtime/cli-worker.ts +0 -140
  223. package/src/runtime/equals.ts +0 -400
  224. package/src/runtime/expect.ts +0 -173
  225. package/src/runtime/matchers.ts +0 -452
  226. package/src/runtime/run.ts +0 -573
  227. package/src/runtime/suite.ts +0 -310
  228. package/src/runtime/test-context.ts +0 -59
  229. package/src/runtime/vi/fake-timers.ts +0 -410
  230. package/src/runtime/vi/index.ts +0 -254
  231. package/src/runtime/vi/spy.ts +0 -224
  232. package/src/runtime/vi/spyOn.ts +0 -155
  233. package/src/runtime/vi/system-time.ts +0 -121
  234. package/src/runtime/worker.ts +0 -239
  235. package/src/time/freeze.ts +0 -229
@@ -1,310 +0,0 @@
1
- /**
2
- * `describe` / `test` / `it` DSL — builds a suite tree during module load.
3
- *
4
- * Collection phase: `describe(name, fn)` runs `fn` synchronously with an
5
- * active suite on a per-invocation stack. `withCollection(...)` scopes the
6
- * collection to one `runTestFile` call via AsyncLocalStorage, so parallel
7
- * invocations never share state.
8
- */
9
-
10
- import { AsyncLocalStorage } from "node:async_hooks";
11
-
12
- export type TestFn = () => void | Promise<void>;
13
- export type SuiteFn = () => void;
14
-
15
- export type HookType = "beforeAll" | "afterAll" | "beforeEach" | "afterEach";
16
-
17
- export interface Hook {
18
- type: HookType;
19
- fn: TestFn;
20
- }
21
-
22
- export type RunMode = "run" | "skip" | "only" | "todo";
23
-
24
- export interface TestNode {
25
- kind: "test";
26
- name: string;
27
- fn: TestFn | undefined; // undefined for `todo`
28
- mode: RunMode;
29
- parent: SuiteNode;
30
- location?: string;
31
- }
32
-
33
- export interface SuiteNode {
34
- kind: "suite";
35
- name: string;
36
- mode: RunMode;
37
- parent: SuiteNode | undefined;
38
- children: Array<SuiteNode | TestNode>;
39
- hooks: Hook[];
40
- }
41
-
42
- interface CollectionContext {
43
- root: SuiteNode;
44
- stack: SuiteNode[];
45
- }
46
-
47
- function makeSuite(
48
- name: string,
49
- mode: RunMode,
50
- parent: SuiteNode | undefined,
51
- ): SuiteNode {
52
- return {
53
- kind: "suite",
54
- name,
55
- mode,
56
- parent,
57
- children: [],
58
- hooks: [],
59
- };
60
- }
61
-
62
- /**
63
- * Scoped collection context. Each `runTestFile` invocation opens its own
64
- * store so concurrent runs never see each other's registrations.
65
- */
66
- const storage = new AsyncLocalStorage<CollectionContext>();
67
-
68
- /**
69
- * Fallback context used when the DSL is called outside `runTestFile` (e.g.,
70
- * unit tests that drive `describe`/`test` directly). `resetRoot` replaces
71
- * this; `getRoot` returns it.
72
- */
73
- let fallbackRoot: SuiteNode = makeSuite("", "run", undefined);
74
- let fallbackStack: SuiteNode[] = [fallbackRoot];
75
-
76
- function currentContext(): CollectionContext {
77
- const scoped = storage.getStore();
78
- if (scoped) return scoped;
79
- return { root: fallbackRoot, stack: fallbackStack };
80
- }
81
-
82
- export function resetRoot(): SuiteNode {
83
- fallbackRoot = makeSuite("", "run", undefined);
84
- fallbackStack = [fallbackRoot];
85
- return fallbackRoot;
86
- }
87
-
88
- export function getRoot(): SuiteNode {
89
- return currentContext().root;
90
- }
91
-
92
- /**
93
- * Run `body` inside a fresh, isolated collection context. Returns the root
94
- * populated by its DSL calls. Safe under concurrent invocation.
95
- */
96
- export async function withCollection(
97
- body: () => Promise<void> | void,
98
- ): Promise<SuiteNode> {
99
- const root = makeSuite("", "run", undefined);
100
- const ctx: CollectionContext = { root, stack: [root] };
101
- await storage.run(ctx, async () => {
102
- await body();
103
- });
104
- return root;
105
- }
106
-
107
- function current(): SuiteNode {
108
- const { stack } = currentContext();
109
- const top = stack[stack.length - 1];
110
- if (!top) throw new Error("internal: suite stack empty");
111
- return top;
112
- }
113
-
114
- function registerTest(
115
- name: string,
116
- mode: RunMode,
117
- fn: TestFn | undefined,
118
- ): void {
119
- const parent = current();
120
- parent.children.push({
121
- kind: "test",
122
- name,
123
- fn,
124
- mode,
125
- parent,
126
- });
127
- }
128
-
129
- function registerSuite(name: string, mode: RunMode, body: SuiteFn): void {
130
- const ctx = currentContext();
131
- const parent = current();
132
- const suite = makeSuite(name, mode, parent);
133
- parent.children.push(suite);
134
- ctx.stack.push(suite);
135
- let result: unknown;
136
- try {
137
- result = body();
138
- } finally {
139
- ctx.stack.pop();
140
- }
141
- // Async describe bodies would register nested describe/test against the
142
- // wrong parent after the first `await` (because we've already popped).
143
- // Fail loudly rather than silently mis-collect.
144
- if (result && typeof (result as { then?: unknown }).then === "function") {
145
- throw new Error(
146
- `describe(${JSON.stringify(name)}): body returned a Promise. Async describe is not supported — await the setup in a \`beforeAll\` hook instead.`,
147
- );
148
- }
149
- }
150
-
151
- type SuiteApi = {
152
- (name: string, fn: SuiteFn): void;
153
- skip(name: string, fn: SuiteFn): void;
154
- only(name: string, fn: SuiteFn): void;
155
- todo(name: string): void;
156
- };
157
-
158
- type ArrayRow = readonly unknown[];
159
- type ObjectRow = Readonly<Record<string, unknown>>;
160
- type EachRow =
161
- | ArrayRow
162
- | ObjectRow
163
- | null
164
- | undefined
165
- | string
166
- | number
167
- | boolean
168
- | bigint
169
- | symbol;
170
-
171
- type TestApi = {
172
- (name: string, fn: TestFn): void;
173
- skip(name: string, fn?: TestFn): void;
174
- only(name: string, fn: TestFn): void;
175
- todo(name: string): void;
176
- each<Row extends EachRow>(
177
- rows: readonly Row[],
178
- ): (name: string, fn: (row: Row) => void | Promise<void>) => void;
179
- };
180
-
181
- function safeStringify(v: unknown): string {
182
- try {
183
- const s = JSON.stringify(v);
184
- return s === undefined ? String(v) : s;
185
- } catch {
186
- // Circular / BigInt / etc.
187
- return String(v);
188
- }
189
- }
190
-
191
- function isArrayRow(row: EachRow): row is ArrayRow {
192
- return Array.isArray(row);
193
- }
194
-
195
- function isObjectRow(row: EachRow): row is ObjectRow {
196
- return typeof row === "object" && row !== null && !Array.isArray(row);
197
- }
198
-
199
- function interpolateArrayRow(
200
- template: string,
201
- row: ArrayRow,
202
- index: number,
203
- ): string {
204
- // Hand-rolled walker so `%%` escapes to a literal `%` without consuming a
205
- // row value, and format specifiers consume their argument in order.
206
- let i = 0;
207
- let out = "";
208
- for (let j = 0; j < template.length; j += 1) {
209
- const c = template[j];
210
- if (c !== "%" || j === template.length - 1) {
211
- out += c;
212
- continue;
213
- }
214
- const next = template[j + 1];
215
- if (next === "%") {
216
- out += "%";
217
- j += 1;
218
- continue;
219
- }
220
- if (next === "#") {
221
- out += String(index);
222
- j += 1;
223
- continue;
224
- }
225
- if (
226
- next === "s" ||
227
- next === "d" ||
228
- next === "i" ||
229
- next === "f" ||
230
- next === "j" ||
231
- next === "o"
232
- ) {
233
- const v = row[i];
234
- i += 1;
235
- out += typeof v === "object" && v !== null ? safeStringify(v) : String(v);
236
- j += 1;
237
- continue;
238
- }
239
- out += c;
240
- }
241
- return out;
242
- }
243
-
244
- function interpolateObjectRow(
245
- template: string,
246
- row: ObjectRow,
247
- index: number,
248
- ): string {
249
- return template
250
- .replace(/\$#/g, String(index))
251
- .replace(/\$([a-zA-Z_][\w.]*)/g, (_match, path: string) => {
252
- const parts = path.split(".");
253
- let cursor: unknown = row;
254
- for (const p of parts) {
255
- if (cursor && typeof cursor === "object" && p in cursor) {
256
- cursor = Reflect.get(cursor, p);
257
- } else {
258
- return "undefined";
259
- }
260
- }
261
- if (typeof cursor === "object" && cursor !== null)
262
- return safeStringify(cursor);
263
- return String(cursor);
264
- });
265
- }
266
-
267
- function interpolateEach(
268
- template: string,
269
- row: EachRow,
270
- index: number,
271
- ): string {
272
- if (isArrayRow(row)) return interpolateArrayRow(template, row, index);
273
- if (isObjectRow(row)) return interpolateObjectRow(template, row, index);
274
- // Primitive row (number, string, boolean, bigint, symbol, null, undefined).
275
- // Append index so names don't collide.
276
- return `${template} [${index}]`;
277
- }
278
-
279
- const describeFn = ((name: string, fn: SuiteFn) =>
280
- registerSuite(name, "run", fn)) as SuiteApi;
281
- describeFn.skip = (name, fn) => registerSuite(name, "skip", fn);
282
- describeFn.only = (name, fn) => registerSuite(name, "only", fn);
283
- describeFn.todo = (name) => registerSuite(name, "todo", () => {});
284
-
285
- const testFn = ((name: string, fn: TestFn) =>
286
- registerTest(name, "run", fn)) as TestApi;
287
- testFn.skip = (name, fn) => registerTest(name, "skip", fn);
288
- testFn.only = (name, fn) => registerTest(name, "only", fn);
289
- testFn.todo = (name) => registerTest(name, "todo", undefined);
290
- testFn.each = <Row extends EachRow>(rows: readonly Row[]) => {
291
- return (name: string, fn: (row: Row) => void | Promise<void>) => {
292
- rows.forEach((row, index) => {
293
- const resolvedName = interpolateEach(name, row, index);
294
- registerTest(resolvedName, "run", () => fn(row));
295
- });
296
- };
297
- };
298
-
299
- export const describe: SuiteApi = describeFn;
300
- export const test: TestApi = testFn;
301
- export const it: TestApi = testFn;
302
-
303
- export function addHook(type: HookType, fn: TestFn): void {
304
- current().hooks.push({ type, fn });
305
- }
306
-
307
- export const beforeAll = (fn: TestFn): void => addHook("beforeAll", fn);
308
- export const afterAll = (fn: TestFn): void => addHook("afterAll", fn);
309
- export const beforeEach = (fn: TestFn): void => addHook("beforeEach", fn);
310
- export const afterEach = (fn: TestFn): void => addHook("afterEach", fn);
@@ -1,59 +0,0 @@
1
- /**
2
- * Per-test execution frame.
3
- *
4
- * Whereas `withViContext` wraps each test FILE (so spies and fake
5
- * timers can span tests within a file), `withTestContext` wraps each
6
- * INDIVIDUAL test (cycle = beforeEach + body + afterEach). It exists
7
- * so test-scoped resources — most notably container overrides
8
- * registered through `helix.override()` — get torn down between tests
9
- * without needing the user to wire `afterEach(restore)` by hand.
10
- *
11
- * Cleanup semantics mirror `withViContext`'s finally:
12
- * - reverse insertion order
13
- * - one cleanup throwing must not block the others
14
- */
15
-
16
- import { AsyncLocalStorage } from "node:async_hooks";
17
-
18
- export type TestCleanup = () => void | Promise<void>;
19
-
20
- interface TestFrame {
21
- cleanups: TestCleanup[];
22
- }
23
-
24
- const storage = new AsyncLocalStorage<TestFrame>();
25
-
26
- export async function withTestContext<T>(body: () => Promise<T>): Promise<T> {
27
- const frame: TestFrame = { cleanups: [] };
28
- try {
29
- return await storage.run(frame, body);
30
- } finally {
31
- for (let i = frame.cleanups.length - 1; i >= 0; i -= 1) {
32
- try {
33
- await frame.cleanups[i]();
34
- } catch (err) {
35
- // One cleanup failing must not block the others — but log it
36
- // so silent leaks become noisy. `console.error` matches what
37
- // Vitest does for `afterEach` failures observed at runtime.
38
- console.error("[helix] test cleanup failed:", err);
39
- }
40
- }
41
- }
42
- }
43
-
44
- /**
45
- * Register a cleanup function that runs at the end of the current
46
- * test cycle. Returns `true` when registered, `false` when called
47
- * outside a test frame (caller decides — usually a no-op or fallback
48
- * to a wider frame).
49
- */
50
- export function registerTestCleanup(cleanup: TestCleanup): boolean {
51
- const frame = storage.getStore();
52
- if (!frame) return false;
53
- frame.cleanups.push(cleanup);
54
- return true;
55
- }
56
-
57
- export function inTestContext(): boolean {
58
- return storage.getStore() !== undefined;
59
- }