@c9up/helix 0.1.8 → 0.1.9

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 (106) hide show
  1. package/README.md +274 -5
  2. package/bin/helix.js +312 -13
  3. package/dist/cli/failed-cache.d.ts +27 -0
  4. package/dist/cli/failed-cache.d.ts.map +1 -0
  5. package/dist/cli/failed-cache.js +64 -0
  6. package/dist/cli/failed-cache.js.map +1 -0
  7. package/dist/cli/glob.d.ts +36 -0
  8. package/dist/cli/glob.d.ts.map +1 -0
  9. package/dist/cli/glob.js +185 -0
  10. package/dist/cli/glob.js.map +1 -0
  11. package/dist/cli/native.d.ts +4 -0
  12. package/dist/cli/native.d.ts.map +1 -1
  13. package/dist/cli/native.js.map +1 -1
  14. package/dist/cli/pool.d.ts +11 -0
  15. package/dist/cli/pool.d.ts.map +1 -1
  16. package/dist/cli/pool.js +12 -0
  17. package/dist/cli/pool.js.map +1 -1
  18. package/dist/cli/reporter.d.ts +11 -0
  19. package/dist/cli/reporter.d.ts.map +1 -1
  20. package/dist/cli/reporter.js +53 -0
  21. package/dist/cli/reporter.js.map +1 -1
  22. package/dist/cli/run.d.ts +41 -0
  23. package/dist/cli/run.d.ts.map +1 -1
  24. package/dist/cli/run.js +181 -21
  25. package/dist/cli/run.js.map +1 -1
  26. package/dist/cli/runner.d.ts +19 -0
  27. package/dist/cli/runner.d.ts.map +1 -0
  28. package/dist/cli/runner.js +15 -0
  29. package/dist/cli/runner.js.map +1 -0
  30. package/dist/cli/suites.d.ts +102 -0
  31. package/dist/cli/suites.d.ts.map +1 -0
  32. package/dist/cli/suites.js +226 -0
  33. package/dist/cli/suites.js.map +1 -0
  34. package/dist/index.d.ts +10 -9
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +9 -8
  37. package/dist/index.js.map +1 -1
  38. package/dist/japa/core.d.ts +106 -0
  39. package/dist/japa/core.d.ts.map +1 -0
  40. package/dist/japa/core.js +128 -0
  41. package/dist/japa/core.js.map +1 -0
  42. package/dist/runtime/assert.d.ts +174 -0
  43. package/dist/runtime/assert.d.ts.map +1 -0
  44. package/dist/runtime/assert.js +591 -0
  45. package/dist/runtime/assert.js.map +1 -0
  46. package/dist/runtime/bootstrap.d.ts +47 -0
  47. package/dist/runtime/bootstrap.d.ts.map +1 -0
  48. package/dist/runtime/bootstrap.js +166 -0
  49. package/dist/runtime/bootstrap.js.map +1 -0
  50. package/dist/runtime/cli-args.d.ts +77 -0
  51. package/dist/runtime/cli-args.d.ts.map +1 -0
  52. package/dist/runtime/cli-args.js +85 -0
  53. package/dist/runtime/cli-args.js.map +1 -0
  54. package/dist/runtime/configure.d.ts +214 -0
  55. package/dist/runtime/configure.d.ts.map +1 -0
  56. package/dist/runtime/configure.js +164 -0
  57. package/dist/runtime/configure.js.map +1 -0
  58. package/dist/runtime/context.d.ts +84 -0
  59. package/dist/runtime/context.d.ts.map +1 -0
  60. package/dist/runtime/context.js +146 -0
  61. package/dist/runtime/context.js.map +1 -0
  62. package/dist/runtime/emitter.d.ts +141 -0
  63. package/dist/runtime/emitter.d.ts.map +1 -0
  64. package/dist/runtime/emitter.js +79 -0
  65. package/dist/runtime/emitter.js.map +1 -0
  66. package/dist/runtime/global-hooks.d.ts +31 -0
  67. package/dist/runtime/global-hooks.d.ts.map +1 -0
  68. package/dist/runtime/global-hooks.js +126 -0
  69. package/dist/runtime/global-hooks.js.map +1 -0
  70. package/dist/runtime/index.d.ts +14 -3
  71. package/dist/runtime/index.d.ts.map +1 -1
  72. package/dist/runtime/index.js +7 -2
  73. package/dist/runtime/index.js.map +1 -1
  74. package/dist/runtime/run.d.ts +49 -2
  75. package/dist/runtime/run.d.ts.map +1 -1
  76. package/dist/runtime/run.js +618 -94
  77. package/dist/runtime/run.js.map +1 -1
  78. package/dist/runtime/runner.d.ts +97 -0
  79. package/dist/runtime/runner.d.ts.map +1 -0
  80. package/dist/runtime/runner.js +160 -0
  81. package/dist/runtime/runner.js.map +1 -0
  82. package/dist/runtime/suite-config.d.ts +23 -0
  83. package/dist/runtime/suite-config.d.ts.map +1 -0
  84. package/dist/runtime/suite-config.js +52 -0
  85. package/dist/runtime/suite-config.js.map +1 -0
  86. package/dist/runtime/suite-taps.d.ts +122 -0
  87. package/dist/runtime/suite-taps.d.ts.map +1 -0
  88. package/dist/runtime/suite-taps.js +218 -0
  89. package/dist/runtime/suite-taps.js.map +1 -0
  90. package/dist/runtime/suite.d.ts +277 -8
  91. package/dist/runtime/suite.d.ts.map +1 -1
  92. package/dist/runtime/suite.js +255 -4
  93. package/dist/runtime/suite.js.map +1 -1
  94. package/dist/runtime/test-context.d.ts +50 -3
  95. package/dist/runtime/test-context.d.ts.map +1 -1
  96. package/dist/runtime/test-context.js +83 -5
  97. package/dist/runtime/test-context.js.map +1 -1
  98. package/dist/runtime/worker.d.ts.map +1 -1
  99. package/dist/runtime/worker.js +85 -28
  100. package/dist/runtime/worker.js.map +1 -1
  101. package/index.darwin-arm64.node +0 -0
  102. package/index.darwin-x64.node +0 -0
  103. package/index.linux-arm64-gnu.node +0 -0
  104. package/index.linux-x64-gnu.node +0 -0
  105. package/index.win32-x64-msvc.node +0 -0
  106. package/package.json +8 -1
@@ -0,0 +1,164 @@
1
+ /**
2
+ * `configure({ plugins })` — the Japa/AdonisJS bootstrap entry.
3
+ *
4
+ * Following Japa precisely: the runtime core is plugin-agnostic, and every
5
+ * capability (HTTP `client`, `db`, fakes, …) ships as a PLUGIN that extends the
6
+ * injected test context. A plugin is a function handed a {@link PluginApi};
7
+ * it registers context properties via `api.context.macro` / `.getter` (the
8
+ * `TestContext.macro`/`getter` of Japa) and pairs that with a `declare module`
9
+ * augmentation for the types.
10
+ *
11
+ * // tests/bootstrap.ts
12
+ * import { configure } from "@c9up/helix";
13
+ * import { apiClient } from "@c9up/ream/testing";
14
+ * await configure({ plugins: [apiClient({ baseUrl })] });
15
+ *
16
+ * This keeps `@c9up/helix` (the core) free of any ecosystem dependency: the
17
+ * plugins live in each package's `/testing` subpath and depend on helix, never
18
+ * the other way round — the Japa "runner + plugins" topology.
19
+ */
20
+ import { cliArgs } from "./cli-args.js";
21
+ import { TestContextRegistry } from "./context.js";
22
+ import { emitter } from "./emitter.js";
23
+ import { Runner } from "./runner.js";
24
+ import { makeSuiteHandle, setCurrentSuite, } from "./suite-taps.js";
25
+ /** Build a {@link Refiner} writing into `filters`. */
26
+ function makeRefiner(filters) {
27
+ return {
28
+ add(layer, values) {
29
+ filters[layer] = [...(filters[layer] ?? []), ...values];
30
+ },
31
+ matchAllTags(toggle = true) {
32
+ filters.matchAll = toggle;
33
+ },
34
+ };
35
+ }
36
+ /** Teardowns to run after the run — from `configure({ teardown })` + `api.cleanup`. */
37
+ const runnerTeardowns = [];
38
+ /** Undos returned by `setup` hooks — drained BEFORE the teardowns. */
39
+ const runnerCleanups = [];
40
+ const configuredDefaults = {};
41
+ /** The defaults set by {@link configure}, if any. */
42
+ export function getConfiguredDefaults() {
43
+ return configuredDefaults;
44
+ }
45
+ /** Tracks the run by listening to {@link emitter} — handed to plugins. */
46
+ const runner = new Runner(emitter);
47
+ /** The options the last {@link configure} call resolved to (Japa `config`). */
48
+ let resolvedConfig = {};
49
+ const api = {
50
+ // A getter so a plugin reads the config of the `configure()` call it is
51
+ // running under, not an empty object captured at module load. Japa lets a
52
+ // plugin EDIT it (that is how a plugin raises the default timeout), so the
53
+ // object is handed over mutable and read back after every plugin has run.
54
+ get config() {
55
+ return resolvedConfig;
56
+ },
57
+ // The same object every access, for the same reason: a plugin that writes
58
+ // `api.cliArgs.tags = [...]` must actually steer the run.
59
+ get cliArgs() {
60
+ return cliArgs();
61
+ },
62
+ runner,
63
+ emitter,
64
+ context: {
65
+ macro: (name, value) => TestContextRegistry.macro(name, value),
66
+ getter: (name, fn) => TestContextRegistry.getter(name, fn),
67
+ },
68
+ cleanup: (fn) => {
69
+ runnerTeardowns.push(fn);
70
+ },
71
+ };
72
+ /**
73
+ * Install plugins + runner hooks. Call once from a bootstrap file
74
+ * (Japa/AdonisJS `bin/test.ts` / `tests/bootstrap.ts`).
75
+ *
76
+ * Order follows Japa: PLUGINS first, then the run's `setup` hooks, then the
77
+ * `teardown` hooks are parked for after the run (see {@link
78
+ * drainRunnerTeardowns}). That ordering is what makes a plugin's edits count —
79
+ * it can raise `config.timeout`, push a `setup` hook, or reach for
80
+ * `runner.onSuite`, and the run picks all of it up because nothing has been
81
+ * read yet.
82
+ */
83
+ export async function configure(options) {
84
+ resolvedConfig = options;
85
+ // Hook arrays a plugin can append to (through `runner.onSuite`) — they must
86
+ // exist before the plugins run, and they are the very arrays drained below.
87
+ resolvedConfig.setup ??= [];
88
+ resolvedConfig.teardown ??= [];
89
+ const setup = resolvedConfig.setup;
90
+ const teardown = resolvedConfig.teardown;
91
+ const handle = makeSuiteHandle(options.suite ?? "default", setup, teardown);
92
+ setCurrentSuite(handle);
93
+ // The rest of Japa's `BaseConfig`, filled with what this run actually is, so
94
+ // a plugin reading `api.config` is told the truth rather than `undefined`.
95
+ const flags = cliArgs();
96
+ resolvedConfig.cwd ??= process.cwd();
97
+ resolvedConfig.reporters ??= { activated: flags.reporters ?? [] };
98
+ resolvedConfig.forceExit ??= flags.forceExit === true;
99
+ resolvedConfig.filters ??= {};
100
+ resolvedConfig.filters.files ??= flags.files;
101
+ resolvedConfig.filters.suites ??=
102
+ flags.suite === undefined ? undefined : [flags.suite];
103
+ resolvedConfig.refiner ??= makeRefiner(resolvedConfig.filters);
104
+ for (const plugin of resolvedConfig.plugins ?? []) {
105
+ await plugin(api);
106
+ }
107
+ // Japa order: plugins, THEN `runner.onSuite(config.configureSuite)`, then the
108
+ // setup hooks. Applying it here rather than earlier is what lets a plugin
109
+ // read it — or put its own in place — and still have it take effect.
110
+ await resolvedConfig.configureSuite?.(handle);
111
+ // Read the defaults back AFTER the plugins, so a plugin that edited the
112
+ // config steers the run rather than writing into a value already consumed.
113
+ if (resolvedConfig.timeout !== undefined)
114
+ configuredDefaults.timeout = resolvedConfig.timeout;
115
+ if (resolvedConfig.retries !== undefined)
116
+ configuredDefaults.retries = resolvedConfig.retries;
117
+ if (resolvedConfig.suite !== undefined)
118
+ configuredDefaults.suite = resolvedConfig.suite;
119
+ if (resolvedConfig.filters !== undefined)
120
+ configuredDefaults.filters = resolvedConfig.filters;
121
+ if (resolvedConfig.importer !== undefined)
122
+ configuredDefaults.importer = resolvedConfig.importer;
123
+ // Japa skips the global setup hooks under `--list-pinned`: nothing runs, so
124
+ // nothing should be opened.
125
+ const listing = cliArgs().listPinned === true;
126
+ for (const fn of listing ? [] : setup) {
127
+ // A `setup` hook may resolve to its own undo (the AdonisJS idiom); park it
128
+ // with the teardowns so it runs in reverse order with everything else.
129
+ const undo = await fn(runner);
130
+ if (typeof undo === "function")
131
+ runnerCleanups.push(undo);
132
+ }
133
+ for (const fn of teardown)
134
+ runnerTeardowns.push(fn);
135
+ }
136
+ /**
137
+ * Run every registered runner teardown (reverse order), then clear them — called
138
+ * by the runtime after a file's tests finish. Failures are logged, not thrown,
139
+ * so one bad teardown can't hide the test results.
140
+ */
141
+ export async function drainRunnerTeardowns() {
142
+ // Cleanups returned by `setup` unwind first — they are the innermost thing
143
+ // that was opened. `null` for the error: the drain only happens once the run
144
+ // itself has finished, so there is no setup failure left to report.
145
+ for (let i = runnerCleanups.length - 1; i >= 0; i -= 1) {
146
+ try {
147
+ await runnerCleanups[i](null, runner);
148
+ }
149
+ catch (err) {
150
+ console.error("[helix] runner cleanup failed:", err);
151
+ }
152
+ }
153
+ runnerCleanups.length = 0;
154
+ for (let i = runnerTeardowns.length - 1; i >= 0; i -= 1) {
155
+ try {
156
+ await runnerTeardowns[i](runner);
157
+ }
158
+ catch (err) {
159
+ console.error("[helix] runner teardown failed:", err);
160
+ }
161
+ }
162
+ runnerTeardowns.length = 0;
163
+ }
164
+ //# sourceMappingURL=configure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configure.js","sourceRoot":"","sources":["../../src/runtime/configure.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Injected test context — Japa's defining mechanism.
3
+ *
4
+ * Every test body (and, later, group hooks) receives a `TestContext` as its
5
+ * FIRST argument: `test("x", ({ assert, client, db, cleanup }) => …)`. The
6
+ * context is EXTENSIBLE via declaration merging: capability plugins (HTTP
7
+ * client, DB, fakes) both register a runtime property through
8
+ * {@link TestContextRegistry} AND augment the `TestContext` interface:
9
+ *
10
+ * declare module "@c9up/helix" {
11
+ * interface TestContext { client: ApiClient }
12
+ * }
13
+ *
14
+ * This is what lets `@c9up/helix/http`, `@c9up/helix/db`, … graft `client`,
15
+ * `db`, … onto the context — fully typed — without the core depending on those
16
+ * packages.
17
+ *
18
+ * Backwards compatible: passing the context as the first arg is a no-op for
19
+ * existing zero-argument bodies (`test("x", () => …)`), which ignore it.
20
+ */
21
+ import { type Assert } from "./assert.js";
22
+ import type { TestInstance } from "./suite.js";
23
+ import { type TestCleanup } from "./test-context.js";
24
+ /**
25
+ * The per-test context. `cleanup` is always present; capability plugins add
26
+ * `assert`, `client`, `db`, … by augmenting this interface (declaration
27
+ * merging) alongside a matching {@link TestContextRegistry} registration.
28
+ */
29
+ /**
30
+ * A CLASS (not an interface) so plugins can add REQUIRED properties via
31
+ * declaration merging — `declare module "@c9up/helix" { interface TestContext {
32
+ * client: ApiClient } }` — without breaking the core's construction (an external
33
+ * augmentation is not subject to helix's `strictPropertyInitialization`). This
34
+ * is exactly how Japa's `TestContext` works.
35
+ */
36
+ export declare class TestContext {
37
+ /**
38
+ * Add a shared property to every test context — Japa's
39
+ * `TestContext.macro('sleep', fn)`, callable on the class itself so a Japa
40
+ * plugin's registration code ports over unchanged.
41
+ */
42
+ static macro(name: string, value: unknown): void;
43
+ /** Add a lazily-computed, per-context property (Japa `TestContext.getter`). */
44
+ static getter(name: string, fn: Getter): void;
45
+ /** Chai-flavored assertions (`@japa/assert` parity), alongside `expect`. */
46
+ readonly assert: Assert;
47
+ /** The running test's own instance — name, options, dataset (Japa `ctx.test`). */
48
+ readonly test: TestInstance;
49
+ constructor(test: TestInstance);
50
+ /**
51
+ * Register a teardown that runs at the end of THIS test, regardless of
52
+ * outcome (Japa `ctx.cleanup`). Reverse-insertion order, isolated failures.
53
+ */
54
+ cleanup(fn: TestCleanup): void;
55
+ }
56
+ export type Getter = (this: TestContext, ctx: TestContext) => unknown;
57
+ /**
58
+ * Registry through which plugins extend the test context at runtime. Mirrors
59
+ * Japa's `TestContext.macro(name, value)` / `TestContext.getter(name, fn)`.
60
+ * Pair each call with a `declare module` augmentation for the types.
61
+ */
62
+ export declare const TestContextRegistry: {
63
+ /** Add a shared property present on every test context. */
64
+ macro(name: string, value: unknown): void;
65
+ /**
66
+ * Add a lazily-computed, per-context property. The getter runs the first
67
+ * time the property is read on a given context (inside that test's frame),
68
+ * and the result is cached for that context.
69
+ */
70
+ getter(name: string, fn: Getter): void;
71
+ /** Remove a macro/getter (plugin teardown, tests). No arg clears all. */
72
+ clear(name?: string): void;
73
+ /** Whether any extension is registered under `name`. */
74
+ has(name: string): boolean;
75
+ };
76
+ /**
77
+ * Build a fresh `TestContext` for one test attempt. MUST be called inside the
78
+ * per-test frame (`withTestContext`) so `ctx.cleanup` reaches the right frame.
79
+ * Applies registered macros (own value), then getters (lazy, cached per
80
+ * context). Dynamic props are attached via `defineProperty` so no `cleanup`
81
+ * override and no cast are needed.
82
+ */
83
+ export declare function buildTestContext(test: TestInstance): TestContext;
84
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/runtime/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,aAAa,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAE1E;;;;GAIG;AACH;;;;;;GAMG;AACH,qBAAa,WAAW;IACvB;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAIhD,+EAA+E;IAC/E,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAI7C,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,kFAAkF;IAClF,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;gBAEhB,IAAI,EAAE,YAAY;IAK9B;;;OAGG;IACH,OAAO,CAAC,EAAE,EAAE,WAAW,GAAG,IAAI;CAK9B;AAID,MAAM,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC;AAKtE;;;;GAIG;AACH,eAAO,MAAM,mBAAmB;IAC/B,2DAA2D;gBAC/C,MAAM,SAAS,OAAO,GAAG,IAAI;IAGzC;;;;OAIG;iBACU,MAAM,MAAM,MAAM,GAAG,IAAI;IAGtC,yEAAyE;iBAC5D,MAAM,GAAG,IAAI;IAS1B,wDAAwD;cAC9C,MAAM,GAAG,OAAO;CAG1B,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,YAAY,GAAG,WAAW,CAqChE"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Injected test context — Japa's defining mechanism.
3
+ *
4
+ * Every test body (and, later, group hooks) receives a `TestContext` as its
5
+ * FIRST argument: `test("x", ({ assert, client, db, cleanup }) => …)`. The
6
+ * context is EXTENSIBLE via declaration merging: capability plugins (HTTP
7
+ * client, DB, fakes) both register a runtime property through
8
+ * {@link TestContextRegistry} AND augment the `TestContext` interface:
9
+ *
10
+ * declare module "@c9up/helix" {
11
+ * interface TestContext { client: ApiClient }
12
+ * }
13
+ *
14
+ * This is what lets `@c9up/helix/http`, `@c9up/helix/db`, … graft `client`,
15
+ * `db`, … onto the context — fully typed — without the core depending on those
16
+ * packages.
17
+ *
18
+ * Backwards compatible: passing the context as the first arg is a no-op for
19
+ * existing zero-argument bodies (`test("x", () => …)`), which ignore it.
20
+ */
21
+ import { createAssert } from "./assert.js";
22
+ import { registerTestCleanup } from "./test-context.js";
23
+ /**
24
+ * The per-test context. `cleanup` is always present; capability plugins add
25
+ * `assert`, `client`, `db`, … by augmenting this interface (declaration
26
+ * merging) alongside a matching {@link TestContextRegistry} registration.
27
+ */
28
+ /**
29
+ * A CLASS (not an interface) so plugins can add REQUIRED properties via
30
+ * declaration merging — `declare module "@c9up/helix" { interface TestContext {
31
+ * client: ApiClient } }` — without breaking the core's construction (an external
32
+ * augmentation is not subject to helix's `strictPropertyInitialization`). This
33
+ * is exactly how Japa's `TestContext` works.
34
+ */
35
+ export class TestContext {
36
+ /**
37
+ * Add a shared property to every test context — Japa's
38
+ * `TestContext.macro('sleep', fn)`, callable on the class itself so a Japa
39
+ * plugin's registration code ports over unchanged.
40
+ */
41
+ static macro(name, value) {
42
+ TestContextRegistry.macro(name, value);
43
+ }
44
+ /** Add a lazily-computed, per-context property (Japa `TestContext.getter`). */
45
+ static getter(name, fn) {
46
+ TestContextRegistry.getter(name, fn);
47
+ }
48
+ /** Chai-flavored assertions (`@japa/assert` parity), alongside `expect`. */
49
+ assert;
50
+ /** The running test's own instance — name, options, dataset (Japa `ctx.test`). */
51
+ test;
52
+ constructor(test) {
53
+ this.assert = createAssert();
54
+ this.test = test;
55
+ }
56
+ /**
57
+ * Register a teardown that runs at the end of THIS test, regardless of
58
+ * outcome (Japa `ctx.cleanup`). Reverse-insertion order, isolated failures.
59
+ */
60
+ cleanup(fn) {
61
+ // Falls through to the active per-test frame; a false return means we were
62
+ // called outside a frame (defensive — the runner always wraps).
63
+ registerTestCleanup(fn);
64
+ }
65
+ }
66
+ const macros = new Map();
67
+ const getters = new Map();
68
+ /**
69
+ * Registry through which plugins extend the test context at runtime. Mirrors
70
+ * Japa's `TestContext.macro(name, value)` / `TestContext.getter(name, fn)`.
71
+ * Pair each call with a `declare module` augmentation for the types.
72
+ */
73
+ export const TestContextRegistry = {
74
+ /** Add a shared property present on every test context. */
75
+ macro(name, value) {
76
+ macros.set(name, value);
77
+ },
78
+ /**
79
+ * Add a lazily-computed, per-context property. The getter runs the first
80
+ * time the property is read on a given context (inside that test's frame),
81
+ * and the result is cached for that context.
82
+ */
83
+ getter(name, fn) {
84
+ getters.set(name, fn);
85
+ },
86
+ /** Remove a macro/getter (plugin teardown, tests). No arg clears all. */
87
+ clear(name) {
88
+ if (name === undefined) {
89
+ macros.clear();
90
+ getters.clear();
91
+ }
92
+ else {
93
+ macros.delete(name);
94
+ getters.delete(name);
95
+ }
96
+ },
97
+ /** Whether any extension is registered under `name`. */
98
+ has(name) {
99
+ return macros.has(name) || getters.has(name);
100
+ },
101
+ };
102
+ /**
103
+ * Build a fresh `TestContext` for one test attempt. MUST be called inside the
104
+ * per-test frame (`withTestContext`) so `ctx.cleanup` reaches the right frame.
105
+ * Applies registered macros (own value), then getters (lazy, cached per
106
+ * context). Dynamic props are attached via `defineProperty` so no `cleanup`
107
+ * override and no cast are needed.
108
+ */
109
+ export function buildTestContext(test) {
110
+ const ctx = new TestContext(test);
111
+ // `cleanup` and `test` are structural — the runtime hands them to the body
112
+ // and nothing may take their place. `assert` is NOT: helix ships one, and a
113
+ // project installing `@japa/assert` is asking for that one instead. Refusing
114
+ // the override left the plugin registered but never reached, which is how
115
+ // `plugins: [assert()]` could look wired and do nothing.
116
+ const reserved = new Set(["cleanup", "test"]);
117
+ for (const [name, value] of macros) {
118
+ if (reserved.has(name))
119
+ continue;
120
+ Object.defineProperty(ctx, name, {
121
+ value,
122
+ enumerable: true,
123
+ configurable: true,
124
+ writable: true,
125
+ });
126
+ }
127
+ for (const [name, fn] of getters) {
128
+ if (reserved.has(name))
129
+ continue;
130
+ let computed = false;
131
+ let cached;
132
+ Object.defineProperty(ctx, name, {
133
+ enumerable: true,
134
+ configurable: true,
135
+ get() {
136
+ if (!computed) {
137
+ cached = fn.call(ctx, ctx);
138
+ computed = true;
139
+ }
140
+ return cached;
141
+ },
142
+ });
143
+ }
144
+ return ctx;
145
+ }
146
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/runtime/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Runner events — the Japa `Emitter` surface.
3
+ *
4
+ * Japa's plugin/reporter topology is built on an event emitter: a plugin
5
+ * receives `{ config, cliArgs, runner, emitter }` and subscribes to
6
+ * `runner:start`, `suite:start`, `group:start`, `test:start`, … to observe the
7
+ * run. Helix emits the SAME event names with the SAME node shapes
8
+ * (`TestStartNode`, `TestEndNode`, `GroupStartNode`, …) so a Japa reporter or
9
+ * plugin can be ported without rewriting its listeners.
10
+ *
11
+ * One named deviation from `@japa/core`: `suite:start` / `suite:end` carry the
12
+ * test FILE name. Helix runs one process per file, so the file is what a
13
+ * worker-side listener can see of a suite.
14
+ *
15
+ * `errors[].error` is the thrown `Error` itself, as in Japa — the emitter runs
16
+ * in the worker, where the original is still around. Only an error rebuilt from
17
+ * an IPC frame (which can carry data only) degrades to the {@link
18
+ * SerializedError} shape, which keeps the same `name`/`message`/`stack` fields.
19
+ */
20
+ import type { SerializedError } from "./run.js";
21
+ /** The lifecycle phase an error was raised in (Japa parity). */
22
+ export type ErrorPhase = "setup" | "test" | "setup:cleanup" | "teardown" | "teardown:cleanup" | "test:cleanup";
23
+ /**
24
+ * One captured failure, tagged with the phase it happened in. `error` is the
25
+ * thrown `Error`; it degrades to {@link SerializedError} — same `name`,
26
+ * `message` and `stack` — only for a result rebuilt from an IPC frame.
27
+ */
28
+ export interface EmittedError {
29
+ phase: ErrorPhase;
30
+ error: Error | SerializedError;
31
+ }
32
+ /** A test title, before and after dataset interpolation (Japa parity). */
33
+ export interface EmittedTitle {
34
+ original: string;
35
+ expanded: string;
36
+ }
37
+ /** The dataset row a test instance was expanded from. */
38
+ export interface EmittedDataset {
39
+ size: number;
40
+ index: number;
41
+ row: unknown;
42
+ }
43
+ /**
44
+ * Shared shape of `test:start` / `test:end` — Japa's `TestOptions`, field for
45
+ * field. Only `title`, `tags`, `timeout`, `meta` and `isPinned` always carry a
46
+ * value; the rest appear when the corresponding modifier was used, so a
47
+ * reporter that probes for a key sees what Japa would show it.
48
+ */
49
+ interface TestNodeBase {
50
+ title: EmittedTitle;
51
+ tags: string[];
52
+ timeout: number;
53
+ waitsForDone?: boolean;
54
+ /** The test body, as Japa hands it over. Absent on a `todo`. */
55
+ executor?: (...args: never[]) => unknown;
56
+ retries?: number;
57
+ retryAttempt?: number;
58
+ isTodo?: boolean;
59
+ isSkipped?: boolean;
60
+ isFailing?: boolean;
61
+ skipReason?: string;
62
+ failReason?: string;
63
+ isPinned: boolean;
64
+ meta: Record<string, unknown>;
65
+ dataset?: EmittedDataset;
66
+ }
67
+ /** Payload of `test:start`. */
68
+ export type TestStartNode = TestNodeBase;
69
+ /** Payload of `test:end`. */
70
+ export type TestEndNode = TestNodeBase & {
71
+ duration: number;
72
+ hasError: boolean;
73
+ errors: EmittedError[];
74
+ };
75
+ /** Payload of `group:start`. */
76
+ export interface GroupStartNode {
77
+ title: string;
78
+ meta: Record<string, unknown>;
79
+ }
80
+ /** Payload of `group:end`. */
81
+ export type GroupEndNode = GroupStartNode & {
82
+ hasError: boolean;
83
+ errors: EmittedError[];
84
+ };
85
+ /** Payload of `suite:start` — helix's suite is the test file. */
86
+ export interface SuiteStartNode {
87
+ name: string;
88
+ }
89
+ /** Payload of `suite:end`. */
90
+ export type SuiteEndNode = SuiteStartNode & {
91
+ hasError: boolean;
92
+ errors: EmittedError[];
93
+ };
94
+ /**
95
+ * Payload of `runner:start`. Japa types this as `{}`; helix spells the same
96
+ * "no fields" shape as an empty record so no lint suppression is needed.
97
+ */
98
+ export type RunnerStartNode = Record<string, never>;
99
+ /** Payload of `runner:end`. */
100
+ export interface RunnerEndNode {
101
+ hasError: boolean;
102
+ }
103
+ /** Every event the runtime emits, with its payload (Japa `RunnerEvents`). */
104
+ export interface RunnerEvents {
105
+ "test:start": TestStartNode;
106
+ "test:end": TestEndNode;
107
+ "group:start": GroupStartNode;
108
+ "group:end": GroupEndNode;
109
+ "suite:start": SuiteStartNode;
110
+ "suite:end": SuiteEndNode;
111
+ "runner:start": RunnerStartNode;
112
+ "runner:end": RunnerEndNode;
113
+ }
114
+ /** A listener for one event. */
115
+ export type EventHandler<E extends keyof RunnerEvents> = (payload: RunnerEvents[E]) => void;
116
+ /**
117
+ * A typed event emitter over {@link RunnerEvents}. Deliberately minimal — `on`
118
+ * / `once` / `off` / `emit`, the surface a Japa reporter or plugin uses. A
119
+ * throwing listener is reported on stderr and never fails the run.
120
+ */
121
+ export declare class Emitter {
122
+ #private;
123
+ /** Subscribe to an event. Returns `this` for chaining. */
124
+ on<E extends keyof RunnerEvents>(event: E, handler: EventHandler<E>): this;
125
+ /** Subscribe to the next occurrence of an event only. */
126
+ once<E extends keyof RunnerEvents>(event: E, handler: EventHandler<E>): this;
127
+ /** Remove a previously registered listener. */
128
+ off<E extends keyof RunnerEvents>(event: E, handler: EventHandler<E>): this;
129
+ /** Drop every listener (used between runs in the same process). */
130
+ clear(): void;
131
+ /** Broadcast an event. Listener failures are isolated. */
132
+ emit<E extends keyof RunnerEvents>(event: E, payload: RunnerEvents[E]): void;
133
+ }
134
+ /**
135
+ * The process-wide emitter. Helix runs one file per process, so a module-level
136
+ * instance is the run's emitter — the same object plugins receive at
137
+ * `configure()` time and the runtime emits on.
138
+ */
139
+ export declare const emitter: Emitter;
140
+ export {};
141
+ //# sourceMappingURL=emitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emitter.d.ts","sourceRoot":"","sources":["../../src/runtime/emitter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Runner events — the Japa `Emitter` surface.
3
+ *
4
+ * Japa's plugin/reporter topology is built on an event emitter: a plugin
5
+ * receives `{ config, cliArgs, runner, emitter }` and subscribes to
6
+ * `runner:start`, `suite:start`, `group:start`, `test:start`, … to observe the
7
+ * run. Helix emits the SAME event names with the SAME node shapes
8
+ * (`TestStartNode`, `TestEndNode`, `GroupStartNode`, …) so a Japa reporter or
9
+ * plugin can be ported without rewriting its listeners.
10
+ *
11
+ * One named deviation from `@japa/core`: `suite:start` / `suite:end` carry the
12
+ * test FILE name. Helix runs one process per file, so the file is what a
13
+ * worker-side listener can see of a suite.
14
+ *
15
+ * `errors[].error` is the thrown `Error` itself, as in Japa — the emitter runs
16
+ * in the worker, where the original is still around. Only an error rebuilt from
17
+ * an IPC frame (which can carry data only) degrades to the {@link
18
+ * SerializedError} shape, which keeps the same `name`/`message`/`stack` fields.
19
+ */
20
+ /**
21
+ * A typed event emitter over {@link RunnerEvents}. Deliberately minimal — `on`
22
+ * / `once` / `off` / `emit`, the surface a Japa reporter or plugin uses. A
23
+ * throwing listener is reported on stderr and never fails the run.
24
+ */
25
+ export class Emitter {
26
+ #listeners = new Map();
27
+ /** Subscribe to an event. Returns `this` for chaining. */
28
+ on(event, handler) {
29
+ const set = this.#listeners.get(event) ?? new Set();
30
+ set.add({ fn: handler });
31
+ this.#listeners.set(event, set);
32
+ return this;
33
+ }
34
+ /** Subscribe to the next occurrence of an event only. */
35
+ once(event, handler) {
36
+ const wrapped = (payload) => {
37
+ this.off(event, wrapped);
38
+ handler(payload);
39
+ };
40
+ return this.on(event, wrapped);
41
+ }
42
+ /** Remove a previously registered listener. */
43
+ off(event, handler) {
44
+ const set = this.#listeners.get(event);
45
+ if (set === undefined)
46
+ return this;
47
+ for (const entry of set) {
48
+ if (entry.fn === handler)
49
+ set.delete(entry);
50
+ }
51
+ return this;
52
+ }
53
+ /** Drop every listener (used between runs in the same process). */
54
+ clear() {
55
+ this.#listeners.clear();
56
+ }
57
+ /** Broadcast an event. Listener failures are isolated. */
58
+ emit(event, payload) {
59
+ const set = this.#listeners.get(event);
60
+ if (set === undefined)
61
+ return;
62
+ // Snapshot: a `once` listener removes itself while we iterate.
63
+ for (const entry of [...set]) {
64
+ try {
65
+ entry.fn(payload);
66
+ }
67
+ catch (err) {
68
+ console.error(`[helix] "${event}" listener failed:`, err);
69
+ }
70
+ }
71
+ }
72
+ }
73
+ /**
74
+ * The process-wide emitter. Helix runs one file per process, so a module-level
75
+ * instance is the run's emitter — the same object plugins receive at
76
+ * `configure()` time and the runtime emits on.
77
+ */
78
+ export const emitter = new Emitter();
79
+ //# sourceMappingURL=emitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"emitter.js","sourceRoot":"","sources":["../../src/runtime/emitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAmIH;;;;GAIG;AACH,MAAM,OAAO,OAAO;IACV,UAAU,GAAG,IAAI,GAAG,EAA2C,CAAC;IAEzE,0DAA0D;IAC1D,EAAE,CAA+B,KAAQ,EAAE,OAAwB;QAClE,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,GAAG,EAAkB,CAAC;QACpE,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QACzB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC;IACb,CAAC;IAED,yDAAyD;IACzD,IAAI,CAA+B,KAAQ,EAAE,OAAwB;QACpE,MAAM,OAAO,GAAoB,CAAC,OAAO,EAAE,EAAE;YAC5C,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YACzB,OAAO,CAAC,OAAO,CAAC,CAAC;QAClB,CAAC,CAAC;QACF,OAAO,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC;IAED,+CAA+C;IAC/C,GAAG,CAA+B,KAAQ,EAAE,OAAwB;QACnE,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QACnC,KAAK,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;YACzB,IAAI,KAAK,CAAC,EAAE,KAAK,OAAO;gBAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC;IAED,mEAAmE;IACnE,KAAK;QACJ,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;IAED,0DAA0D;IAC1D,IAAI,CAA+B,KAAQ,EAAE,OAAwB;QACpE,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO;QAC9B,+DAA+D;QAC/D,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC;gBACJ,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;YACnB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,OAAO,CAAC,KAAK,CAAC,YAAY,KAAK,oBAAoB,EAAE,GAAG,CAAC,CAAC;YAC3D,CAAC;QACF,CAAC;IACF,CAAC;CACD;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC"}