@c9up/helix 0.1.7 → 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.
- package/README.md +282 -11
- package/bin/helix.js +329 -13
- package/dist/cli/failed-cache.d.ts +27 -0
- package/dist/cli/failed-cache.d.ts.map +1 -0
- package/dist/cli/failed-cache.js +64 -0
- package/dist/cli/failed-cache.js.map +1 -0
- package/dist/cli/glob.d.ts +36 -0
- package/dist/cli/glob.d.ts.map +1 -0
- package/dist/cli/glob.js +185 -0
- package/dist/cli/glob.js.map +1 -0
- package/dist/cli/native.d.ts +4 -0
- package/dist/cli/native.d.ts.map +1 -1
- package/dist/cli/native.js.map +1 -1
- package/dist/cli/pool.d.ts +11 -0
- package/dist/cli/pool.d.ts.map +1 -1
- package/dist/cli/pool.js +12 -0
- package/dist/cli/pool.js.map +1 -1
- package/dist/cli/reporter.d.ts +11 -0
- package/dist/cli/reporter.d.ts.map +1 -1
- package/dist/cli/reporter.js +53 -0
- package/dist/cli/reporter.js.map +1 -1
- package/dist/cli/run.d.ts +41 -0
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +181 -21
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/runner.d.ts +19 -0
- package/dist/cli/runner.d.ts.map +1 -0
- package/dist/cli/runner.js +15 -0
- package/dist/cli/runner.js.map +1 -0
- package/dist/cli/suites.d.ts +102 -0
- package/dist/cli/suites.d.ts.map +1 -0
- package/dist/cli/suites.js +226 -0
- package/dist/cli/suites.js.map +1 -0
- package/dist/index.d.ts +10 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -8
- package/dist/index.js.map +1 -1
- package/dist/japa/core.d.ts +106 -0
- package/dist/japa/core.d.ts.map +1 -0
- package/dist/japa/core.js +128 -0
- package/dist/japa/core.js.map +1 -0
- package/dist/runtime/assert.d.ts +174 -0
- package/dist/runtime/assert.d.ts.map +1 -0
- package/dist/runtime/assert.js +591 -0
- package/dist/runtime/assert.js.map +1 -0
- package/dist/runtime/asymmetric.d.ts +34 -0
- package/dist/runtime/asymmetric.d.ts.map +1 -0
- package/dist/runtime/asymmetric.js +78 -0
- package/dist/runtime/asymmetric.js.map +1 -0
- package/dist/runtime/bootstrap.d.ts +47 -0
- package/dist/runtime/bootstrap.d.ts.map +1 -0
- package/dist/runtime/bootstrap.js +166 -0
- package/dist/runtime/bootstrap.js.map +1 -0
- package/dist/runtime/cli-args.d.ts +77 -0
- package/dist/runtime/cli-args.d.ts.map +1 -0
- package/dist/runtime/cli-args.js +85 -0
- package/dist/runtime/cli-args.js.map +1 -0
- package/dist/runtime/configure.d.ts +214 -0
- package/dist/runtime/configure.d.ts.map +1 -0
- package/dist/runtime/configure.js +164 -0
- package/dist/runtime/configure.js.map +1 -0
- package/dist/runtime/context.d.ts +84 -0
- package/dist/runtime/context.d.ts.map +1 -0
- package/dist/runtime/context.js +146 -0
- package/dist/runtime/context.js.map +1 -0
- package/dist/runtime/emitter.d.ts +141 -0
- package/dist/runtime/emitter.d.ts.map +1 -0
- package/dist/runtime/emitter.js +79 -0
- package/dist/runtime/emitter.js.map +1 -0
- package/dist/runtime/equals.d.ts.map +1 -1
- package/dist/runtime/equals.js +21 -0
- package/dist/runtime/equals.js.map +1 -1
- package/dist/runtime/expect.d.ts +22 -1
- package/dist/runtime/expect.d.ts.map +1 -1
- package/dist/runtime/expect.js +15 -1
- package/dist/runtime/expect.js.map +1 -1
- package/dist/runtime/global-hooks.d.ts +31 -0
- package/dist/runtime/global-hooks.d.ts.map +1 -0
- package/dist/runtime/global-hooks.js +126 -0
- package/dist/runtime/global-hooks.js.map +1 -0
- package/dist/runtime/index.d.ts +16 -3
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +7 -1
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/matchers.d.ts +5 -0
- package/dist/runtime/matchers.d.ts.map +1 -1
- package/dist/runtime/matchers.js +117 -0
- package/dist/runtime/matchers.js.map +1 -1
- package/dist/runtime/run.d.ts +63 -1
- package/dist/runtime/run.d.ts.map +1 -1
- package/dist/runtime/run.js +696 -79
- package/dist/runtime/run.js.map +1 -1
- package/dist/runtime/runner.d.ts +97 -0
- package/dist/runtime/runner.d.ts.map +1 -0
- package/dist/runtime/runner.js +160 -0
- package/dist/runtime/runner.js.map +1 -0
- package/dist/runtime/suite-config.d.ts +23 -0
- package/dist/runtime/suite-config.d.ts.map +1 -0
- package/dist/runtime/suite-config.js +52 -0
- package/dist/runtime/suite-config.js.map +1 -0
- package/dist/runtime/suite-taps.d.ts +122 -0
- package/dist/runtime/suite-taps.d.ts.map +1 -0
- package/dist/runtime/suite-taps.js +218 -0
- package/dist/runtime/suite-taps.js.map +1 -0
- package/dist/runtime/suite.d.ts +316 -10
- package/dist/runtime/suite.d.ts.map +1 -1
- package/dist/runtime/suite.js +307 -8
- package/dist/runtime/suite.js.map +1 -1
- package/dist/runtime/test-context.d.ts +88 -1
- package/dist/runtime/test-context.d.ts.map +1 -1
- package/dist/runtime/test-context.js +170 -2
- package/dist/runtime/test-context.js.map +1 -1
- package/dist/runtime/vi/fake-timers.d.ts.map +1 -1
- package/dist/runtime/vi/fake-timers.js +3 -4
- package/dist/runtime/vi/fake-timers.js.map +1 -1
- package/dist/runtime/worker.d.ts.map +1 -1
- package/dist/runtime/worker.js +87 -5
- package/dist/runtime/worker.js.map +1 -1
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +10 -1
|
@@ -0,0 +1,214 @@
|
|
|
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 { type CLIArgs } from "./cli-args.js";
|
|
21
|
+
import { type TestContext } from "./context.js";
|
|
22
|
+
import { type Emitter } from "./emitter.js";
|
|
23
|
+
import { Runner } from "./runner.js";
|
|
24
|
+
import { type SuiteHandle, type SuiteHook, type SuiteHookCleanup } from "./suite-taps.js";
|
|
25
|
+
/**
|
|
26
|
+
* What a plugin uses to extend the test context. Mirrors Japa's
|
|
27
|
+
* `TestContext.macro(name, value)` / `TestContext.getter(name, fn)`.
|
|
28
|
+
*/
|
|
29
|
+
export interface PluginContext {
|
|
30
|
+
/** Add a shared property present on every test context. */
|
|
31
|
+
macro(name: string, value: unknown): void;
|
|
32
|
+
/** Add a lazily-computed, per-context property (cached per context). */
|
|
33
|
+
getter(name: string, fn: (ctx: TestContext) => unknown): void;
|
|
34
|
+
}
|
|
35
|
+
/** A runner-level hook — Japa's shape, defined once in `suite-taps.ts`. */
|
|
36
|
+
export type RunnerHook = SuiteHook;
|
|
37
|
+
export type RunnerHookCleanup = SuiteHookCleanup;
|
|
38
|
+
/**
|
|
39
|
+
* The API handed to each plugin at {@link configure} time.
|
|
40
|
+
*
|
|
41
|
+
* Japa hands its plugins `{ config, cliArgs, runner, emitter }`; helix passes
|
|
42
|
+
* the same four, so a Japa plugin's body ports over unchanged, plus two helix
|
|
43
|
+
* additions — `context` (Japa reaches the same registry through the imported
|
|
44
|
+
* `TestContext` class) and `cleanup` (Japa uses `config.teardown`).
|
|
45
|
+
*/
|
|
46
|
+
export interface PluginApi {
|
|
47
|
+
/**
|
|
48
|
+
* The options this run was configured with (Japa `config`). Mutable: Japa
|
|
49
|
+
* plugins edit it, and helix reads it back once every plugin has run.
|
|
50
|
+
*/
|
|
51
|
+
config: ConfigureOptions;
|
|
52
|
+
/** The flags the CLI forwarded to this worker (Japa `cliArgs`). */
|
|
53
|
+
cliArgs: CLIArgs;
|
|
54
|
+
/** Run-level counters, readable once the run ends (Japa `runner`). */
|
|
55
|
+
runner: Runner;
|
|
56
|
+
/** Lifecycle events — `test:start`, `group:end`, … (Japa `emitter`). */
|
|
57
|
+
emitter: Emitter;
|
|
58
|
+
/** Extend the injected test context. */
|
|
59
|
+
context: PluginContext;
|
|
60
|
+
/**
|
|
61
|
+
* Register a teardown that runs ONCE after all tests in the run finish
|
|
62
|
+
* (reverse registration order) — the place to close a booted server, a DB
|
|
63
|
+
* pool, etc. (Japa runner-teardown parity). Without this, a plugin that boots
|
|
64
|
+
* a resource at `configure()` has no clean shutdown point.
|
|
65
|
+
*/
|
|
66
|
+
cleanup(fn: RunnerHook): void;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A helix plugin — the Japa plugin shape adapted to helix. Runs once at
|
|
70
|
+
* bootstrap; may be async (e.g. to boot a server before registering `client`).
|
|
71
|
+
*/
|
|
72
|
+
export type Plugin = (api: PluginApi) => void | Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Filters applied to the tests a file declares (Japa `config.filters`).
|
|
75
|
+
*
|
|
76
|
+
* `files` and `suites` are reported, not honoured: they select which FILES run,
|
|
77
|
+
* and helix settles that list in the CLI process before any worker — and
|
|
78
|
+
* therefore any bootstrap — exists. Setting them here cannot un-spawn a worker
|
|
79
|
+
* that is already running, so they carry what the CLI decided and the CLI-side
|
|
80
|
+
* flags (`--files`, a suite positional) remain the way to decide it.
|
|
81
|
+
*/
|
|
82
|
+
export interface ConfigureFilters {
|
|
83
|
+
/**
|
|
84
|
+
* Path fragments the CLI matched files against (Japa `filters.files`).
|
|
85
|
+
* Read-only here: helix settles the file list before a worker exists, so
|
|
86
|
+
* this reports what was selected rather than selecting.
|
|
87
|
+
*/
|
|
88
|
+
files?: string[];
|
|
89
|
+
/** Suite names the run was limited to (Japa `filters.suites`). Read-only. */
|
|
90
|
+
suites?: string[];
|
|
91
|
+
/** Only tests carrying one of these tags (`~@tag`/`!@tag` excludes). */
|
|
92
|
+
tags?: string[];
|
|
93
|
+
/** Only groups with these exact titles. */
|
|
94
|
+
groups?: string[];
|
|
95
|
+
/** Only tests with these exact titles. */
|
|
96
|
+
tests?: string[];
|
|
97
|
+
/** Require EVERY tag in `tags` instead of any (Japa `--match-all`). */
|
|
98
|
+
matchAll?: boolean;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Japa's `Refiner`, as much of it as means anything here: a handle that ADDS
|
|
102
|
+
* filters. It writes straight into {@link ConfigureOptions.filters}, so a
|
|
103
|
+
* plugin calling `refiner.add("tags", [...])` steers the run exactly as setting
|
|
104
|
+
* the filter would — the object is a different door to the same room, not a
|
|
105
|
+
* second mechanism.
|
|
106
|
+
*/
|
|
107
|
+
export interface Refiner {
|
|
108
|
+
/** Add filter values for a layer (Japa `refiner.add`). */
|
|
109
|
+
add(layer: "tests" | "groups" | "tags", values: string[]): void;
|
|
110
|
+
/** Require every tag instead of any (Japa `refiner.matchAllTags`). */
|
|
111
|
+
matchAllTags(toggle?: boolean): void;
|
|
112
|
+
}
|
|
113
|
+
/** Runtime configuration passed to {@link configure}. */
|
|
114
|
+
export interface ConfigureOptions {
|
|
115
|
+
/** Plugins to install — each extends the test context (Japa parity). */
|
|
116
|
+
plugins?: Plugin[];
|
|
117
|
+
/**
|
|
118
|
+
* The directory the run was launched from (Japa `cwd`). Filled in by the
|
|
119
|
+
* runtime, so a plugin resolving a path against the project reads the same
|
|
120
|
+
* root the CLI discovered from.
|
|
121
|
+
*/
|
|
122
|
+
cwd?: string;
|
|
123
|
+
/**
|
|
124
|
+
* Configure the suite before it runs (Japa `configureSuite`). Applied AFTER
|
|
125
|
+
* the plugins, which is both Japa's order and what lets a plugin read it or
|
|
126
|
+
* put its own in place.
|
|
127
|
+
*
|
|
128
|
+
* May return a promise — Japa's is synchronous, but helix's per-suite
|
|
129
|
+
* `configure` has to re-import the config module, and hooks it registers must
|
|
130
|
+
* exist before the setup hooks are drained.
|
|
131
|
+
*/
|
|
132
|
+
configureSuite?: (suite: SuiteHandle) => void | Promise<void>;
|
|
133
|
+
/**
|
|
134
|
+
* The reporters this run activated (Japa `reporters.activated`). Read-only
|
|
135
|
+
* truth: reporters live in the CLI process, so naming one here would not
|
|
136
|
+
* make it run.
|
|
137
|
+
*/
|
|
138
|
+
reporters?: {
|
|
139
|
+
activated: string[];
|
|
140
|
+
};
|
|
141
|
+
/** `process.exit()` once the run ends (Japa `forceExit`). */
|
|
142
|
+
forceExit?: boolean;
|
|
143
|
+
/** Directories discovery skipped (Japa `exclude`). */
|
|
144
|
+
exclude?: string[];
|
|
145
|
+
/**
|
|
146
|
+
* The filter object (Japa `refiner`). Writes through to
|
|
147
|
+
* {@link ConfigureOptions.filters}, so `refiner.add("tags", [...])` from a
|
|
148
|
+
* plugin steers the run exactly as setting the filter would.
|
|
149
|
+
*/
|
|
150
|
+
refiner?: Refiner;
|
|
151
|
+
/**
|
|
152
|
+
* Filters to apply to this file's tests (Japa `config.filters`). The CLI
|
|
153
|
+
* flags win: a filter typed at the prompt overrides the configured one.
|
|
154
|
+
*/
|
|
155
|
+
filters?: ConfigureFilters;
|
|
156
|
+
/**
|
|
157
|
+
* How a test file is imported (Japa `config.importer`). Defaults to
|
|
158
|
+
* `import(file.href)`. Receives the URL helix would have imported —
|
|
159
|
+
* cache-busting query included, so repeated runs still re-evaluate.
|
|
160
|
+
*/
|
|
161
|
+
importer?: (file: URL) => void | Promise<void>;
|
|
162
|
+
/** Run once before the tests (Japa runner `setup`). */
|
|
163
|
+
setup?: RunnerHook[];
|
|
164
|
+
/** Run once after the tests, reverse order (Japa runner `teardown`). */
|
|
165
|
+
teardown?: RunnerHook[];
|
|
166
|
+
/**
|
|
167
|
+
* Default per-test timeout in ms for this file's tests (Japa `configure({
|
|
168
|
+
* timeout })`). `0` disables. Overridden by `--timeout` and by a per-test
|
|
169
|
+
* `test.timeout(ms)` / `{ timeout }`.
|
|
170
|
+
*/
|
|
171
|
+
timeout?: number;
|
|
172
|
+
/**
|
|
173
|
+
* Default extra attempts on failure for this file's tests (Japa `configure({
|
|
174
|
+
* retries })`). Overridden by `--retries` and by a per-test `test.retry(n)`.
|
|
175
|
+
*/
|
|
176
|
+
retries?: number;
|
|
177
|
+
/**
|
|
178
|
+
* The name of the suite these tests belong to — surfaced as
|
|
179
|
+
* `ctx.test.options.meta.suite.name` and on the `suite:*` events. Defaults to
|
|
180
|
+
* `"default"`, the name Japa gives its implicit suite. Overridden by
|
|
181
|
+
* `--suite`.
|
|
182
|
+
*/
|
|
183
|
+
suite?: string;
|
|
184
|
+
}
|
|
185
|
+
/** Run-level defaults from `configure({ timeout, retries, suite, filters })`. */
|
|
186
|
+
interface ConfiguredDefaults {
|
|
187
|
+
timeout?: number;
|
|
188
|
+
retries?: number;
|
|
189
|
+
suite?: string;
|
|
190
|
+
filters?: ConfigureFilters;
|
|
191
|
+
importer?: (file: URL) => void | Promise<void>;
|
|
192
|
+
}
|
|
193
|
+
/** The defaults set by {@link configure}, if any. */
|
|
194
|
+
export declare function getConfiguredDefaults(): Readonly<ConfiguredDefaults>;
|
|
195
|
+
/**
|
|
196
|
+
* Install plugins + runner hooks. Call once from a bootstrap file
|
|
197
|
+
* (Japa/AdonisJS `bin/test.ts` / `tests/bootstrap.ts`).
|
|
198
|
+
*
|
|
199
|
+
* Order follows Japa: PLUGINS first, then the run's `setup` hooks, then the
|
|
200
|
+
* `teardown` hooks are parked for after the run (see {@link
|
|
201
|
+
* drainRunnerTeardowns}). That ordering is what makes a plugin's edits count —
|
|
202
|
+
* it can raise `config.timeout`, push a `setup` hook, or reach for
|
|
203
|
+
* `runner.onSuite`, and the run picks all of it up because nothing has been
|
|
204
|
+
* read yet.
|
|
205
|
+
*/
|
|
206
|
+
export declare function configure(options: ConfigureOptions): Promise<void>;
|
|
207
|
+
/**
|
|
208
|
+
* Run every registered runner teardown (reverse order), then clear them — called
|
|
209
|
+
* by the runtime after a file's tests finish. Failures are logged, not thrown,
|
|
210
|
+
* so one bad teardown can't hide the test results.
|
|
211
|
+
*/
|
|
212
|
+
export declare function drainRunnerTeardowns(): Promise<void>;
|
|
213
|
+
export {};
|
|
214
|
+
//# sourceMappingURL=configure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configure.d.ts","sourceRoot":"","sources":["../../src/runtime/configure.ts"],"names":[],"mappings":"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"}
|
|
@@ -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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"}
|