@jterrazz/test 15.1.1 → 15.3.0

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/dist/index.d.ts CHANGED
@@ -1,117 +1,7 @@
1
1
  import { Scalar } from "yaml";
2
- import { DeepMockProxy } from "vitest-mock-extended";
3
- //#region src/specification/matching/match.d.ts
4
- /**
5
- * Code-side dynamic-value matchers (`match.*`) and the capture scope shared
6
- * by every assertion of a single spec execution.
7
- *
8
- * Matchers are used inside `toMatchRows` rows and any structural comparison;
9
- * their file-side twins are the `{{placeholder}}` forms in `_expected/*.http`
10
- * fixtures (body AND headers), `_expected/*.json` files, and text snapshots
11
- * (`_expected/*.txt`). One grammar, one vocabulary (CONVENTIONS D4).
12
- */
13
- /** The frozen token vocabulary (CONVENTIONS D4) plus the code-only kinds. */
14
- type MatcherKind = 'any' | 'base64' | 'date' | 'duration' | 'email' | 'float' | 'hex' | 'includes' | 'int' | 'ip' | 'iso8601' | 'number' | 'path' | 'port' | 'ref' | 'regex' | 'semver' | 'sha' | 'string' | 'time' | 'ulid' | 'url' | 'uuid' | 'workdir';
15
- /** Every kind usable as a `{{token}}` in fixture files (all but ref/regex/includes). */
16
- declare const TOKEN_KINDS: readonly ["any", "base64", "date", "duration", "email", "float", "hex", "int", "ip", "iso8601", "number", "path", "port", "semver", "sha", "string", "time", "ulid", "url", "uuid", "workdir"];
17
- /** A token kind valid inside a fixture `{{...}}` placeholder. */
18
- type TokenKind = (typeof TOKEN_KINDS)[number];
19
- /**
20
- * A dynamic-value matcher. Created via the {@link match} factories — never
21
- * constructed directly by user code.
22
- */
23
- declare class Matcher {
24
- /** For kind 'includes': the substring the actual value must contain. */
25
- readonly includes?: string | undefined;
26
- readonly kind: MatcherKind;
27
- /** For kind 'ref': the capture to assert inequality against. */
28
- readonly notRef?: string | undefined;
29
- /** For kind 'ref': the capture name. */
30
- readonly refName?: string | undefined;
31
- /** For kind 'regex': the pattern the actual value must match. */
32
- readonly regex?: RegExp | undefined;
33
- constructor(kind: MatcherKind, options?: {
34
- includes?: string | undefined;
35
- notRef?: string | undefined;
36
- refName?: string | undefined;
37
- regex?: RegExp | undefined;
38
- });
39
- /** Placeholder-style rendering used in failure diffs and serialization. */
40
- toString(): string;
41
- toJSON(): string;
42
- }
43
- /** A no-argument matcher factory — what every typed entry of `match` is. */
44
- type TypedMatcher = () => Matcher;
45
- /**
46
- * Dynamic-value matchers for structural comparisons — the code-side mirror of
47
- * the `{{token}}` fixture grammar (CONVENTIONS D4).
48
- *
49
- * @example
50
- * await expect(result.table('users', { database: 'db' })).toMatchRows({
51
- * columns: ['id', 'name'],
52
- * rows: [[match.uuid(), 'Alice']],
53
- * });
54
- */
55
- /**
56
- * The matcher roster: one no-argument factory per token kind, plus the three
57
- * code-only forms the `{{token}}` grammar does not carry.
58
- */
59
- type MatchFactories = Record<TokenKind, TypedMatcher> & {
60
- includes: (substring: string) => Matcher;
61
- ref: (name: string, options?: {
62
- not?: string;
63
- }) => Matcher;
64
- regex: (regex: RegExp) => Matcher;
65
- };
66
- declare const match: MatchFactories;
67
- /**
68
- * Named captures recorded by `match.ref()` / `{{type#ref}}` placeholders.
69
- * One scope lives on each spec result — every assertion chained off the same
70
- * result shares it, and a new chain starts fresh.
71
- */
72
- declare class CaptureScope {
73
- private readonly values;
74
- /**
75
- * The exact working directory of the current spec, when the framework
76
- * knows it (cli mode). Drives the `{{workdir}}` token / `match.workdir()`.
77
- */
78
- workdir?: string | undefined;
79
- constructor(workdir?: string);
80
- get(name: string): unknown;
81
- has(name: string): boolean;
82
- set(name: string, value: unknown): void;
83
- }
84
- //#endregion
85
- //#region src/specification/facets/_common/result/json.d.ts
86
- /**
87
- * Read-only accessor for a JSON payload parsed from a text stream (stdout).
88
- *
89
- * Lazily parses the JSON on first use; parse errors are deferred until the
90
- * value is read so that callers can still read the raw stream text without
91
- * triggering a throw.
92
- *
93
- * ANSI escape sequences are stripped by default before `JSON.parse`
94
- * (CONVENTIONS D6). When a `transform` is configured on the spec runner, it
95
- * runs on the stripped text — an escape hatch for application noise not
96
- * covered by the `{{token}}` grammar.
97
- *
98
- * Assertions go through `expect()`: `expect(result.json).toMatch('name.json')`
99
- * (deep-equal against `_expected/<name>`, with `{{placeholder}}` support).
100
- */
101
- declare class JsonAccessor {
102
- /** @internal Ref-capture scope shared by the current spec execution. */
103
- readonly captures: CaptureScope;
104
- /** @internal */
105
- private readonly rawText;
106
- /** @internal Test-file directory — fixture resolution root for matchers. */
107
- readonly testDir: string;
108
- /** @internal */
109
- private readonly transform?;
110
- constructor(rawText: string, testDir: string, transform?: (text: string) => string, captures?: CaptureScope);
111
- /** The parsed JSON value. Throws if the text is not valid JSON. */
112
- get value(): unknown;
113
- }
114
- //#endregion
2
+ import { DeepMockProxy, MockProxy } from "vitest-mock-extended";
3
+ import { ReactNode as ComponentUi } from "react";
4
+ import "vitest/browser";
115
5
  //#region src/specification/contracts/types.d.ts
116
6
  /**
117
7
  * The observed outgoing request, reduced to what contract matchers inspect.
@@ -155,12 +45,51 @@ type ContractRequest = {
155
45
  type ContractResponse = {
156
46
  /** HTTP status code (default: 200). */
157
47
  status?: number;
158
- /** Response body — an object is JSON, a string is text, `null`/`undefined` is empty. */
48
+ /**
49
+ * Response body — an object is JSON, a string is text, `null`/`undefined`
50
+ * is empty, and a {@link StreamBody} (built by `http.stream()` /
51
+ * `http.sse()`) arrives in pieces.
52
+ */
159
53
  body: unknown;
160
54
  /** Response headers. */
161
55
  headers?: Record<string, string> | undefined;
162
56
  /** Delay in ms before responding (for timeout testing). */
163
57
  delay?: number | undefined;
58
+ /**
59
+ * A transport failure instead of a reply: the request never reached a
60
+ * server, so `fetch` rejects. `status`, `body` and `headers` say nothing
61
+ * here — there is no response to carry them.
62
+ *
63
+ * The one thing a status code cannot express. A component's "the server did
64
+ * not answer, check that it is running" branch is reached by a rejected
65
+ * `fetch`, and a 503 stand-in tests the other branch entirely.
66
+ */
67
+ transport?: 'network-error' | undefined;
68
+ };
69
+ /**
70
+ * The marker that tells a STREAMED body from a value that happens to be an
71
+ * object. A body reaches three different engines (msw's server, msw's worker,
72
+ * the `node:http` stub) and each of them serialises "an object" as JSON, so a
73
+ * stream declared as a plain value arrives as `{}`. The tag is what each
74
+ * engine recognises before it reaches for `JSON.stringify`.
75
+ */
76
+ declare const STREAM_BODY = "@jterrazz/test:stream";
77
+ /**
78
+ * A body that arrives in pieces — what `http.stream()` and `http.sse()` build.
79
+ *
80
+ * The chunks are written in order, `delayBetweenChunks` milliseconds apart,
81
+ * and the connection closes after the last one. It is the chunks and their
82
+ * ORDER that a streaming subject is specified against: a client that renders
83
+ * tokens as they land, or one that reconnects on a half-read body.
84
+ */
85
+ type StreamBody = {
86
+ /** The pieces, written in order. */
87
+ chunks: readonly string[];
88
+ /** The `content-type` the stream is served under. */
89
+ contentType: string;
90
+ /** Milliseconds between two chunks. Default 0 — everything at once. */
91
+ delayBetweenChunks: number;
92
+ kind: typeof STREAM_BODY;
164
93
  };
165
94
  /**
166
95
  * A dynamic response: computed from the observed request at the moment the
@@ -260,6 +189,144 @@ declare function defineContract(contract: Contract): Contract;
260
189
  */
261
190
  declare function defineContracts(...items: ContractInput[]): Contracts;
262
191
  //#endregion
192
+ //#region src/integrations/msw/scope.d.ts
193
+ /**
194
+ * One block's worth of declared network. Disposed at the end of the scope that
195
+ * declared it: the handlers are dropped, and an unmatched request is thrown.
196
+ */
197
+ type InterceptScope = AsyncDisposable;
198
+ /**
199
+ * The module-scope network double. Resolves once the engine is listening —
200
+ * which is why it is a promise, and why the canonical form awaits it:
201
+ *
202
+ * ```typescript
203
+ * await using _ = await intercept(http.get(url), http.json({ ok: true }));
204
+ * ```
205
+ *
206
+ * Without that `await` the subject could reach the real network before the
207
+ * first handler is in place, so the shape refuses the racy spelling: a promise
208
+ * is not an `AsyncDisposable`, and the compiler says so.
209
+ */
210
+ type Intercept = ((contracts: ContractInput) => Promise<InterceptScope>) & ((request: ContractRequest, response: ContractResponder | ContractResponse) => Promise<InterceptScope>);
211
+ //#endregion
212
+ //#region src/specification/matching/match.d.ts
213
+ /**
214
+ * Code-side dynamic-value matchers (`match.*`) and the capture scope shared
215
+ * by every assertion of a single spec execution.
216
+ *
217
+ * Matchers are used inside `toMatchRows` rows and any structural comparison;
218
+ * their file-side twins are the `{{placeholder}}` forms in `_expected/*.http`
219
+ * fixtures (body AND headers), `_expected/*.json` files, and text snapshots
220
+ * (`_expected/*.txt`). One grammar, one vocabulary (CONVENTIONS D4).
221
+ */
222
+ /** The frozen token vocabulary (CONVENTIONS D4) plus the code-only kinds. */
223
+ type MatcherKind = 'any' | 'base64' | 'date' | 'duration' | 'email' | 'float' | 'hex' | 'includes' | 'int' | 'ip' | 'iso8601' | 'number' | 'path' | 'port' | 'ref' | 'regex' | 'semver' | 'sha' | 'string' | 'time' | 'ulid' | 'url' | 'uuid' | 'workdir';
224
+ /** Every kind usable as a `{{token}}` in fixture files (all but ref/regex/includes). */
225
+ declare const TOKEN_KINDS: readonly ["any", "base64", "date", "duration", "email", "float", "hex", "int", "ip", "iso8601", "number", "path", "port", "semver", "sha", "string", "time", "ulid", "url", "uuid", "workdir"];
226
+ /** A token kind valid inside a fixture `{{...}}` placeholder. */
227
+ type TokenKind = (typeof TOKEN_KINDS)[number];
228
+ /**
229
+ * A dynamic-value matcher. Created via the {@link match} factories — never
230
+ * constructed directly by user code.
231
+ */
232
+ declare class Matcher {
233
+ /** For kind 'includes': the substring the actual value must contain. */
234
+ readonly includes?: string | undefined;
235
+ readonly kind: MatcherKind;
236
+ /** For kind 'ref': the capture to assert inequality against. */
237
+ readonly notRef?: string | undefined;
238
+ /** For kind 'ref': the capture name. */
239
+ readonly refName?: string | undefined;
240
+ /** For kind 'regex': the pattern the actual value must match. */
241
+ readonly regex?: RegExp | undefined;
242
+ constructor(kind: MatcherKind, options?: {
243
+ includes?: string | undefined;
244
+ notRef?: string | undefined;
245
+ refName?: string | undefined;
246
+ regex?: RegExp | undefined;
247
+ });
248
+ /** Placeholder-style rendering used in failure diffs and serialization. */
249
+ toString(): string;
250
+ toJSON(): string;
251
+ }
252
+ /** A no-argument matcher factory — what every typed entry of `match` is. */
253
+ type TypedMatcher = () => Matcher;
254
+ /**
255
+ * Dynamic-value matchers for structural comparisons — the code-side mirror of
256
+ * the `{{token}}` fixture grammar (CONVENTIONS D4).
257
+ *
258
+ * @example
259
+ * await expect(result.table('users', { database: 'db' })).toMatchRows({
260
+ * columns: ['id', 'name'],
261
+ * rows: [[match.uuid(), 'Alice']],
262
+ * });
263
+ */
264
+ /**
265
+ * The matcher roster: one no-argument factory per token kind, plus the three
266
+ * code-only forms the `{{token}}` grammar does not carry.
267
+ */
268
+ type MatchFactories = Record<TokenKind, TypedMatcher> & {
269
+ includes: (substring: string) => Matcher;
270
+ ref: (name: string, options?: {
271
+ not?: string;
272
+ }) => Matcher;
273
+ regex: (regex: RegExp) => Matcher;
274
+ };
275
+ declare const match: MatchFactories;
276
+ /**
277
+ * Named captures recorded by `match.ref()` / `{{type#ref}}` placeholders.
278
+ * One scope lives on each spec result — every assertion chained off the same
279
+ * result shares it, and a new chain starts fresh.
280
+ */
281
+ declare class CaptureScope {
282
+ private readonly values;
283
+ /**
284
+ * The exact working directory of the current spec, when the framework
285
+ * knows it (cli mode). Drives the `{{workdir}}` token / `match.workdir()`.
286
+ */
287
+ workdir?: string | undefined;
288
+ constructor(workdir?: string);
289
+ get(name: string): unknown;
290
+ has(name: string): boolean;
291
+ set(name: string, value: unknown): void;
292
+ }
293
+ //#endregion
294
+ //#region src/specification/facets/_common/result/json.d.ts
295
+ /**
296
+ * Read-only accessor for a JSON payload parsed from a text stream (stdout).
297
+ *
298
+ * Lazily parses the JSON on first use; parse errors are deferred until the
299
+ * value is read so that callers can still read the raw stream text without
300
+ * triggering a throw.
301
+ *
302
+ * ANSI escape sequences are stripped by default before `JSON.parse`
303
+ * (CONVENTIONS D6). When a `transform` is configured on the spec runner, it
304
+ * runs on the stripped text — an escape hatch for application noise not
305
+ * covered by the `{{token}}` grammar.
306
+ *
307
+ * Assertions go through `expect()`: `expect(result.json).toMatch('name.json')`
308
+ * (deep-equal against `_expected/<name>`, with `{{placeholder}}` support).
309
+ */
310
+ declare class JsonAccessor<Value = unknown> {
311
+ /** @internal Ref-capture scope shared by the current spec execution. */
312
+ readonly captures: CaptureScope;
313
+ /** @internal */
314
+ private readonly rawText;
315
+ /** @internal Test-file directory — fixture resolution root for matchers. */
316
+ readonly testDir: string;
317
+ /** @internal */
318
+ private readonly transform?;
319
+ constructor(rawText: string, testDir: string, transform?: (text: string) => string, captures?: CaptureScope);
320
+ /**
321
+ * The parsed JSON value. Throws if the text is not valid JSON.
322
+ *
323
+ * `Value` is `unknown` unless the subject that produced this accessor
324
+ * knows better — `.call<T>()` does, and hands its T straight through so a
325
+ * one-field reading needs no cast in the test.
326
+ */
327
+ get value(): Value;
328
+ }
329
+ //#endregion
263
330
  //#region src/specification/ports/browser.port.d.ts
264
331
  /**
265
332
  * The landmark roles — the standard set of page regions, and the only
@@ -267,8 +334,15 @@ declare function defineContracts(...items: ContractInput[]): Contracts;
267
334
  * so `within()` never becomes a second selector language.
268
335
  */
269
336
  type LandmarkKind = 'banner' | 'complementary' | 'contentinfo' | 'form' | 'main' | 'navigation' | 'region' | 'search';
270
- /** The interactive//textual element kinds — what a visitor actually acts on. */
271
- type ElementKind = 'button' | 'field' | 'heading' | 'link' | 'testId' | 'text';
337
+ /**
338
+ * The interactive/textual element kinds — what a visitor actually acts on.
339
+ *
340
+ * `dialog`, `status`, `table`, `row`, `listitem` and `option` are ARIA roles
341
+ * like the landmarks, but they are not CONTAINERS of a page: they are things a
342
+ * visitor reads and acts on, and they are the roles the estate's UI specs were
343
+ * already reaching for through `getByRole` or, worse, through `.first()`.
344
+ */
345
+ type ElementKind = 'button' | 'dialog' | 'field' | 'heading' | 'link' | 'listitem' | 'option' | 'row' | 'status' | 'table' | 'testId' | 'text';
272
346
  /**
273
347
  * A user-facing element descriptor — pure data, built by the element
274
348
  * vocabulary (`button()`, `link()`, `field()`, …) and translated into
@@ -285,9 +359,37 @@ type ElementRef = {
285
359
  * "Read Articles".
286
360
  */
287
361
  exact?: boolean;
362
+ /**
363
+ * Assert about the element's FOCUS rather than its presence — built by
364
+ * `focused(element)`. The accessibility tree carries no focus state, so
365
+ * where the keyboard is cannot be goldened; it is asserted by a verb.
366
+ */
367
+ focused?: boolean;
368
+ /**
369
+ * Narrows to "and it is (not) accepting input" — built by `disabled(x)` /
370
+ * `enabled(x)`. Like `focused`, a STATE the vocabulary can already name the
371
+ * element of; unlike it, one the ARIA tree carries too (`[disabled]`), so
372
+ * this modifier is what names the ONE control a test is about, and it
373
+ * reaches the direction a behavioural substitute cannot — clicking a
374
+ * disabled control is a timeout, never an answer.
375
+ */
376
+ disabled?: boolean;
288
377
  kind: ElementKind | LandmarkKind;
289
378
  /** Landmarks may be anonymous (`main()`, `banner()`); everything else is named. */
290
379
  name?: string;
380
+ /**
381
+ * Narrows to "and it is (not) the chosen one" — built by `selected(x)`.
382
+ * An option of a COLLAPSED select is in the tree and in the document, and
383
+ * it has no box on the screen, so this facet of it is read from the node
384
+ * (`:checked`) rather than from what a visitor could point at.
385
+ */
386
+ selected?: boolean;
387
+ /**
388
+ * The value the field must hold — built by `valued(field('Title'), '…')`.
389
+ * A field's value is a PROPERTY of the node: a controlled input's `value`
390
+ * attribute never moves, so nothing but the live value answers for it.
391
+ */
392
+ value?: string;
291
393
  /**
292
394
  * Restrict the search to the elements of another descriptor — built by
293
395
  * `within(scope, target)`. Chains: a scope may itself carry a scope.
@@ -300,6 +402,12 @@ type ElementRef = {
300
402
  * without opening a browser.
301
403
  */
302
404
  type ElementMatch = {
405
+ /**
406
+ * The accessible name, when it differs from the text — an `aria-label` is
407
+ * what a role descriptor MATCHED on, and printing the text alone sends the
408
+ * author to disambiguate a name they cannot see.
409
+ */
410
+ accessibleName?: string | undefined;
303
411
  /** Nearest landmark ancestor (`nav`, `footer`, `main`…), when there is one. */
304
412
  context?: string | undefined;
305
413
  /** The attribute that disambiguates most — `href` for links, `name` for fields. */
@@ -340,7 +448,13 @@ type Visitor = {
340
448
  click: (element: ElementRef) => Promise<void>;
341
449
  /** Fill a form field with a value. */
342
450
  fill: (element: ElementRef, value: string) => Promise<void>;
343
- /** Navigate to a path of the site under test. */
451
+ /**
452
+ * Wait until the element is GONE — hidden, or never in the document. The
453
+ * absence primitive: `see()` cannot answer "the dialog closed", because an
454
+ * element that never appears and one that disappeared read the same to it.
455
+ */
456
+ gone: (element: ElementRef) => Promise<void>;
457
+ /** Navigate to a path of the site under test. */
344
458
  goto: (path: string) => Promise<void>;
345
459
  /** Hover the element. */
346
460
  hover: (element: ElementRef) => Promise<void>;
@@ -365,6 +479,11 @@ type BrowserOpenOptions = {
365
479
  * and the boundary of the `external` policy.
366
480
  */
367
481
  baseUrl: string;
482
+ /**
483
+ * Pin the page's own `Date` at this instant before the first byte is
484
+ * parsed — the calendar the site's scripts read. `.clock()` on the chain.
485
+ */
486
+ clock?: string | undefined;
368
487
  /**
369
488
  * Cross-origin request policy. `'block'` aborts every request leaving
370
489
  * the site under test (analytics, CDNs) — the browser-side analog of
@@ -396,6 +515,8 @@ type BrowserPage = {
396
515
  status: number;
397
516
  /** Rendered `document.body.innerText`. */
398
517
  text: string;
518
+ /** The ARIA snapshot of the rendered `<body>` — the outline a golden pins. */
519
+ tree: string;
399
520
  /** `document.title` after rendering. */
400
521
  title: string;
401
522
  /** Final URL after redirects and scenario navigation. */
@@ -813,24 +934,6 @@ declare class TextAccessor {
813
934
  toString(): string;
814
935
  valueOf(): string;
815
936
  }
816
- /**
817
- * Wrap an arbitrary string into a {@link TextAccessor} anchored on the calling
818
- * test's directory — the same caller-detection the builders use.
819
- *
820
- * The product surface of a test framework is its own error messages, checker
821
- * output, and reports; those deserve the same goldening as any other output.
822
- * `text()` makes an ad-hoc string a first-class snapshot subject:
823
- *
824
- * ```typescript
825
- * const message = await catchMessage(() => expect(result.response).toMatch('wrong-body.http'));
826
- * expect(text(message)).toMatch('wrong-body-error.txt'); // resolves to _expected/
827
- * ```
828
- *
829
- * ANSI is stripped before every comparison (the raw form stays on `.text`),
830
- * the `{{token}}` grammar applies to the fixture, and `.grep()` composition
831
- * works exactly as on any stream accessor.
832
- */
833
- declare function text(value: string): TextAccessor;
834
937
  //#endregion
835
938
  //#region src/specification/facets/cli/result.d.ts
836
939
  /**
@@ -935,6 +1038,62 @@ type LiterateRunFlags = {
935
1038
  frozen?: boolean | undefined;
936
1039
  };
937
1040
  //#endregion
1041
+ //#region src/specification/facets/integration/result.d.ts
1042
+ /** What `.call()` produced: the value it returned, or the error it threw. */
1043
+ type CallOutcome = {
1044
+ error: unknown;
1045
+ threw: boolean;
1046
+ value: unknown;
1047
+ };
1048
+ type CallResultOptions = BaseResultOptions & {
1049
+ outcome: CallOutcome;
1050
+ };
1051
+ /**
1052
+ * What `result.value` is, decided by what the call returned: a string reads as
1053
+ * a stream, anything else as JSON. `.call<T>()` already knows T, so the test
1054
+ * reads one field (`result.value.value.ok`) without narrowing a union first.
1055
+ */
1056
+ type CallValue<Returned> = Returned extends string ? TextAccessor : JsonAccessor<Returned>;
1057
+ /**
1058
+ * The result of an in-process call — the integration facet's whole surface.
1059
+ *
1060
+ * Two readings, never both: `value` is what the call RETURNED, `error` is
1061
+ * what it THREW. A module that refuses is specified the same way a module
1062
+ * that answers is, and neither needs a `try`/`catch` in the test — which is
1063
+ * the shape that used to make a refusal spec three times the size of the
1064
+ * happy one, and the shape that quietly passes when nothing throws at all.
1065
+ *
1066
+ * Both are the package's ordinary accessors, so the golden mechanism reaches
1067
+ * them, and `Returned` is what `.call<T>()` returned — `result.value.value` is
1068
+ * that type, not `unknown`, so a one-field reading needs no golden file: `toMatch('<name>.json'|'<name>.txt')`, the `{{token}}` grammar,
1069
+ * `{ frozen }` and `TEST_UPDATE=1` all work here exactly as on an HTTP
1070
+ * response or a command's stdout.
1071
+ */
1072
+ declare class CallResult<Returned = unknown> extends BaseResult {
1073
+ private readonly outcome;
1074
+ constructor(options: CallResultOptions);
1075
+ /**
1076
+ * What the call THREW, as text — the message of an `Error`, the value
1077
+ * itself when something else was thrown, and empty when it returned.
1078
+ *
1079
+ * Empty rather than absent on purpose: `await expect(result.error).toBeEmpty()`
1080
+ * is how a spec says "and it did not refuse" — awaited, because the
1081
+ * matcher answers a promise on every subject it takes, and a dropped one
1082
+ * passes the test while the failure surfaces as an unhandled rejection
1083
+ * (D2 refuses the bare form).
1084
+ */
1085
+ get error(): TextAccessor;
1086
+ /**
1087
+ * What the call RETURNED. A string reads as a stream (`<name>.txt`),
1088
+ * anything else as JSON (`<name>.json`) — the same two subjects every
1089
+ * other facet's results are built from.
1090
+ *
1091
+ * A call that threw returns the empty value: what it produced is
1092
+ * {@link CallResult.error}.
1093
+ */
1094
+ get value(): CallValue<Returned>;
1095
+ }
1096
+ //#endregion
938
1097
  //#region src/specification/facets/mobile/result.d.ts
939
1098
  /** Result from a `.open()` action — the screen as the device saw it, final state. */
940
1099
  declare class ScreenResult extends BaseResult {
@@ -1027,6 +1186,13 @@ declare class PageResult extends BaseResult {
1027
1186
  get status(): number;
1028
1187
  /** Rendered body text as a text accessor. */
1029
1188
  get content(): TextAccessor;
1189
+ /**
1190
+ * The ARIA snapshot of the rendered `<body>` — the page's outline, as the
1191
+ * accessibility tree draws it, and the one golden a rendered surface pins.
1192
+ * Deterministic where a screenshot is not, and the SAME dialect a component
1193
+ * spec asserts, so a page and the components inside it read alike.
1194
+ */
1195
+ get tree(): TextAccessor;
1030
1196
  /** The document title as a text accessor. */
1031
1197
  get title(): TextAccessor;
1032
1198
  /** Final URL after redirects. */
@@ -1144,11 +1310,23 @@ type SpecificationConfig = {
1144
1310
  * facet factories auto-populate this when `dockerConfig` is present.
1145
1311
  */
1146
1312
  dockerTestRunId?: string | undefined;
1313
+ /**
1314
+ * Environment applied to every run of the declared binary
1315
+ * (`specification.cli({ defaults })`) — under a chain's own `.env()` and
1316
+ * under a document's `env:`, both of which win.
1317
+ */
1318
+ defaultEnv?: CliEnv | undefined;
1147
1319
  /**
1148
1320
  * Named environment SETS a spec document may name by bare word
1149
1321
  * (`env: frozen`). Declared once per app in `specification.cli()`.
1150
1322
  */
1151
1323
  envSets?: Record<string, CliEnv> | undefined;
1324
+ /**
1325
+ * When set, `.clock()` is unavailable on this runner and throws this
1326
+ * reason immediately (compose mode — the calendar it would pin is this
1327
+ * process's, and the app runs in a container).
1328
+ */
1329
+ clockDisabledReason?: string | undefined;
1152
1330
  /**
1153
1331
  * When set, `.intercept()` is unavailable on this runner and throws this
1154
1332
  * reason immediately (compose mode — MSW is in-process, CONVENTIONS I3).
@@ -1190,6 +1368,8 @@ type InterceptMethod<T> = ((contracts: ContractInput) => T) & ((request: Contrac
1190
1368
  * of the declared services record that are databases.
1191
1369
  */
1192
1370
  type ApiSpecification<DatabaseKey extends string = string> = {
1371
+ /** Pin the app's `Date` at `iso` for this chain — the calendar the app reads. */
1372
+ clock: (iso: string) => ApiSpecification<DatabaseKey>;
1193
1373
  /** Set HTTP headers for the request. Multiple calls merge. */
1194
1374
  headers: (headers: Record<string, string>) => ApiSpecification<DatabaseKey>;
1195
1375
  /** Declare outgoing calls — a contract, a list, a composite, or an inline request + response pair. */
@@ -1214,6 +1394,8 @@ type ApiSpecification<DatabaseKey extends string = string> = {
1214
1394
  * Jobs run in-process by definition (CONVENTIONS A5/A8).
1215
1395
  */
1216
1396
  type JobsSpecification<DatabaseKey extends string = string> = {
1397
+ /** Pin the job's `Date` at `iso` for this chain — the calendar the job reads. */
1398
+ clock: (iso: string) => JobsSpecification<DatabaseKey>;
1217
1399
  /** Declare outgoing calls — a contract, a list, a composite, or an inline request + response pair. */
1218
1400
  intercept: InterceptMethod<JobsSpecification<DatabaseKey>>;
1219
1401
  /** Queue a SQL seed file from `_seeds/` to run before the action. */
@@ -1223,6 +1405,31 @@ type JobsSpecification<DatabaseKey extends string = string> = {
1223
1405
  /** Execute the named job registered via the `jobs` option and resolve with the result. */
1224
1406
  trigger: (name: string) => Promise<BaseResult>;
1225
1407
  };
1408
+ /**
1409
+ * The `integration` facet — the in-process chain handed out by
1410
+ * `specification.integration()`.
1411
+ *
1412
+ * The subject is a MODULE, not an entry: no HTTP, no binary, no page. What
1413
+ * makes it a spec rather than a module test is what it stands on — real
1414
+ * services, declared contracts, a golden — so it takes the same setups as
1415
+ * every other facet and ends on the one action a module has: being called.
1416
+ */
1417
+ type IntegrationSpecification<Services extends Record<string, unknown> = Record<string, unknown>, DatabaseKey extends string = string> = {
1418
+ /** Pin the module's `Date` at `iso` for this chain. */
1419
+ clock: (iso: string) => IntegrationSpecification<Services, DatabaseKey>;
1420
+ /** Declare outgoing calls — a contract, a list, a composite, or an inline request + response pair. */
1421
+ intercept: InterceptMethod<IntegrationSpecification<Services, DatabaseKey>>;
1422
+ /** Queue a SQL seed file from `_seeds/` to run before the call. */
1423
+ seed: (file: string, options?: {
1424
+ database?: DatabaseKey;
1425
+ }) => IntegrationSpecification<Services, DatabaseKey>;
1426
+ /**
1427
+ * Call the module and resolve with what it produced. The started services
1428
+ * record is handed in, so the subject is constructed with the real
1429
+ * connection strings rather than with a double.
1430
+ */
1431
+ call: <T>(subject: (services: Services) => Promise<T> | T) => Promise<CallResult<T>>;
1432
+ };
1226
1433
  /**
1227
1434
  * The `cli` facet — command chain entry handed out by `specification.cli()`.
1228
1435
  * Setup methods chain; `.exec()` is the single terminal action (CONVENTIONS
@@ -1267,6 +1474,11 @@ type CliSpecification<DatabaseKey extends string = string> = {
1267
1474
  * performs one raw HTTP exchange and never follows redirects.
1268
1475
  */
1269
1476
  type WebsiteSpecification = {
1477
+ /**
1478
+ * Pin the PAGE's `Date` at `iso` for this chain — what the site's own
1479
+ * scripts read. A `.fetch()` opens no page and refuses the setup.
1480
+ */
1481
+ clock: (iso: string) => WebsiteSpecification;
1270
1482
  /** Set HTTP headers for the exchange (incl. User-Agent overrides). Multiple calls merge. */
1271
1483
  headers: (headers: Record<string, string>) => WebsiteSpecification;
1272
1484
  /**
@@ -1441,7 +1653,16 @@ declare class ContainerAccessor {
1441
1653
  private containerExec;
1442
1654
  }
1443
1655
  //#endregion
1444
- //#region src/vitest/matchers.d.ts
1656
+ //#region src/specification/facets/_common/result/match-options.d.ts
1657
+ /**
1658
+ * The per-call option both `toMatch` implementations honour.
1659
+ *
1660
+ * A golden is read from disk under node and through a server command from
1661
+ * inside a page, and BOTH builds must answer `{ frozen: true }` the same way —
1662
+ * so the option is declared here, where the node matchers and the page's
1663
+ * matchers can each reach it, rather than in the runner's own folder, which a
1664
+ * seam may not import (rule I1).
1665
+ */
1445
1666
  /**
1446
1667
  * Per-call options for the fixture-file `toMatch` subjects. `frozen` opts a
1447
1668
  * single fixture OUT of update-mode rewriting: a frozen fixture is NEVER
@@ -1456,180 +1677,875 @@ type MatchFixtureOptions = {
1456
1677
  frozen?: boolean;
1457
1678
  };
1458
1679
  //#endregion
1459
- //#region src/specification/facets/_common/orchestrator.d.ts
1460
- type OrchestratorOptions = {
1461
- /**
1462
- * Named infrastructure record. Keys become the database vocabulary of the
1463
- * spec (`.seed()` / `.table()` `database` option) and drive the compose
1464
- * binding: a handle with no explicit `composeService` links to the compose
1465
- * service named exactly like its key, else the kebab-case conversion of the
1466
- * key (`analyticsDb` → `analytics-db`) — see {@link resolveComposeBinding}.
1467
- */
1468
- services: Record<string, ServiceHandle>;
1469
- mode: 'e2e' | 'integration';
1470
- /**
1471
- * The project root, already resolved. REQUIRED: the constructors derive it
1472
- * by walking up from the calling specification file (CONVENTIONS A9), and
1473
- * the orchestrator is handed the answer. Defaulting to `process.cwd()` here
1474
- * meant one silent second opinion about what the project is — the runner
1475
- * resolving from the caller, this from wherever the runner happened to be
1476
- * launched, which in a workspace is rarely the same directory.
1477
- */
1478
- root: string;
1479
- /** Compose project name — used for per-worker stack isolation. */
1480
- projectName?: string;
1481
- };
1680
+ //#region src/integrations/vitest-browser/ui.d.ts
1482
1681
  /**
1483
- * Orchestrator for test infrastructure.
1484
- * Integration: starts services via testcontainers.
1485
- * E2E: runs full docker compose up.
1682
+ * A vanilla DOM subject: a function handed the container it must fill. Its
1683
+ * optional return is the teardown, the way a DOM library states one.
1486
1684
  */
1487
- declare class Orchestrator {
1488
- private readonly services;
1489
- private readonly mode;
1490
- private readonly root;
1491
- private readonly projectName;
1492
- private running;
1493
- private composeStack;
1494
- private composeHandles;
1495
- private started;
1496
- constructor(options: OrchestratorOptions);
1497
- /**
1498
- * Bind each declared handle to a compose service (CONVENTIONS A6): a record
1499
- * key resolves to the service named exactly like it, else the kebab-case
1500
- * conversion of the key; an explicit `composeService` wins. Throws on an
1501
- * ambiguous binding (both names present). Runs once compose config is known
1502
- * so the two-step resolution can consult the real service list.
1503
- */
1504
- private resolveBindings;
1505
- /**
1506
- * Start declared services via testcontainers (integration mode).
1507
- * Phase 1: start all containers in parallel (the slow part).
1508
- * Phase 2: wire connections, healthcheck, and init sequentially (fast).
1509
- */
1510
- start(): Promise<void>;
1511
- /**
1512
- * Stop testcontainers (integration mode).
1513
- */
1514
- stop(): Promise<void>;
1515
- /**
1516
- * Start full docker compose stack (e2e mode).
1517
- * Auto-detects infra services and creates handles for them.
1518
- */
1519
- startCompose(): Promise<void>;
1520
- /**
1521
- * Stop docker compose stack (e2e mode).
1522
- */
1523
- stopCompose(): Promise<void>;
1524
- /**
1525
- * Get the default database — the first declared handle that is one.
1526
- */
1527
- getDatabase(): DatabasePort | null;
1528
- /**
1529
- * Get all database services keyed by their record key (declared services)
1530
- * or compose service name (stack-detected services).
1531
- */
1532
- getDatabases(): Map<string, DatabasePort>;
1533
- private allHandles;
1534
- /**
1535
- * Get app URL from compose (e2e mode).
1536
- */
1537
- getAppUrl(): null | string;
1685
+ type DomMount = (container: HTMLElement) => (() => void) | void;
1686
+ /**
1687
+ * The `server.commands` this seam registers, declared in the module every part
1688
+ * of the seam already imports.
1689
+ *
1690
+ * A `declare module` merges only as an interface, and only from a file that is
1691
+ * itself a module and part of the program — a lone `.d.ts` would have to be
1692
+ * pulled in by an empty import, and its single `export {}` is exactly what a
1693
+ * formatter is free to drop, turning the augmentation into an ambient
1694
+ * declaration that SHADOWS the module it meant to extend.
1695
+ */
1696
+ declare module 'vitest/browser' {
1697
+ interface BrowserCommands {
1698
+ ariaTree: () => Promise<string>;
1699
+ goldenRead: (name: string) => Promise<null | string>;
1700
+ goldenWrite: (name: string, content: string) => Promise<string>;
1701
+ }
1538
1702
  }
1539
1703
  //#endregion
1540
- //#region src/specification/facets/_common/services.d.ts
1704
+ //#region src/integrations/vitest-browser/vitest-browser.adapter.d.ts
1705
+ /** What a mounted subject offers the chain, React or vanilla DOM alike. */
1706
+ type MountedSurface = {
1707
+ /** The element the subject was mounted into. */
1708
+ container: HTMLElement;
1709
+ /** Replace the rendered tree — a prop change, as a parent makes one. */
1710
+ rerender: (ui: ComponentUi) => Promise<void>;
1711
+ /** Take it off the screen, as a parent does. */
1712
+ unmount: () => Promise<void>;
1713
+ };
1714
+ /** The verbs a rendered surface shares with a page, plus the two a parent owns. */
1715
+ declare function componentVerbs(surface: MountedSurface): {
1716
+ check: (element: ElementRef) => Promise<void>;
1717
+ click: (element: ElementRef) => Promise<void>;
1718
+ fill: (element: ElementRef, value: string) => Promise<void>;
1719
+ gone: (element: ElementRef) => Promise<void>;
1720
+ hover: (element: ElementRef) => Promise<void>;
1721
+ press: (key: string) => Promise<void>;
1722
+ rerender: (ui: ComponentUi) => Promise<void>;
1723
+ see: (element: ElementRef) => Promise<void>;
1724
+ select: (element: ElementRef, option: string) => Promise<void>;
1725
+ unmount: () => Promise<void>;
1726
+ };
1727
+ //#endregion
1728
+ //#region src/specification/facets/component/rendered-text.d.ts
1541
1729
  /**
1542
- * Infrastructure services declared as a named record. Keys become the typed
1543
- * vocabulary of the whole spec: the server factory receives the same record,
1544
- * and `.seed()` / `.table()` target databases by key.
1545
- */
1546
- type ServiceRecord = Record<string, ServiceHandle>;
1547
- /** Keys of a services record whose handles are databases. */
1548
- type DatabaseKeys<Services extends ServiceRecord> = { [K in keyof Services]: Services[K] extends DatabasePort ? K & string : never; }[keyof Services];
1730
+ * A stream captured INSIDE the page.
1731
+ *
1732
+ * Structurally identical to any other {@link TextAccessor} — the same
1733
+ * `{{token}}` grammar, the same ANSI stripping, the same `.grep()` — and
1734
+ * marked so the matcher augmentation can say the one thing that differs: its
1735
+ * golden lives on the server, so `toMatch` is awaited here where it is
1736
+ * synchronous everywhere else.
1737
+ */
1738
+ declare class RenderedText extends TextAccessor {
1739
+ /** The marker the `toMatch` overload reads. Never asserted on directly. */
1740
+ readonly capturedInPage: true;
1741
+ }
1549
1742
  //#endregion
1550
- //#region src/specification/facets/api/start-api.d.ts
1551
- /** Any object with a request method compatible with Hono's app.request(). */
1552
- type HonoApp = {
1553
- request: (path: string, init?: RequestInit) => Promise<Response> | Response;
1554
- };
1555
- /** Execution mode — exists ONLY on `specification.api()` (CONVENTIONS A5). */
1556
- type SpecificationMode = 'compose' | 'node';
1557
- /** Options for {@link startApi | specification.api}. */
1558
- type ApiSpecificationOptions<Services extends ServiceRecord = ServiceRecord> = {
1559
- /**
1560
- * Execution mode override. Resolution: `options.mode` >
1561
- * `process.env.TEST_MODE` > `'node'`. Never hardcode this in a
1562
- * specification file when `server` is defined — set it per vitest
1563
- * project via `env: { TEST_MODE: 'compose' }` (CONVENTIONS A5).
1564
- */
1565
- mode?: SpecificationMode;
1743
+ //#region src/specification/facets/component/component.result.d.ts
1744
+ /**
1745
+ * What a render resolves to — the component as the page saw it, after the
1746
+ * scenario ran.
1747
+ *
1748
+ * Five accessors and no more: the ARIA outline a golden pins, the two
1749
+ * renderings a probe reads, and the two streams a spec wants silent. Nothing
1750
+ * here reaches back into React — a spec that needs the component's internals
1751
+ * is asserting the implementation, not the surface a user meets.
1752
+ */
1753
+ declare class RenderResult {
1754
+ /** The browser console as a stream — one `[type] text` line per message. */
1755
+ readonly console: RenderedText;
1756
+ /** Rendered text of the whole document body (`innerText`). */
1757
+ readonly content: RenderedText;
1758
+ /** Console messages of type `error` only, plus any uncaught page error. */
1759
+ readonly errors: RenderedText;
1760
+ /** The mounted markup, serialised — the escape hatch for a class or an attribute. */
1761
+ readonly html: RenderedText;
1762
+ /** The ARIA snapshot of the rendered body — the outline a golden pins. */
1763
+ readonly tree: RenderedText;
1764
+ constructor(streams: {
1765
+ console: string;
1766
+ content: string;
1767
+ errors: string;
1768
+ html: string;
1769
+ tree: string;
1770
+ });
1771
+ }
1772
+ //#endregion
1773
+ //#region src/specification/facets/component/component.types.d.ts
1774
+ /**
1775
+ * The component facet's shape, stated where BOTH runtimes can read it.
1776
+ *
1777
+ * The page gets the working chain; node gets a stub under the same name and
1778
+ * the same type, so a component test that ran in the wrong project fails on
1779
+ * the line that rendered rather than on a missing export. The published types
1780
+ * are the node build's, so this file is the one description of the facet.
1781
+ */
1782
+ /** The interaction vocabulary a render scenario is handed — the When. */
1783
+ type ComponentVisitor = ReturnType<typeof componentVerbs>;
1784
+ /** The behaviour of a render; assertions stay in the Then, on the result (W1). */
1785
+ type ComponentScenario = (visitor: ComponentVisitor) => Promise<void>;
1786
+ /**
1787
+ * What `.render()` mounts. A React tree is an element (`<PostTable />`); a
1788
+ * vanilla DOM subject is the FUNCTION that fills a container, which is how a
1789
+ * DOM-only module is called in production too.
1790
+ */
1791
+ type RenderSubject = ComponentUi | DomMount;
1792
+ /**
1793
+ * The chain. Every setup returns a new one, so the handle a spec imports never
1794
+ * carries the previous test's contracts, wrapper or clock.
1795
+ */
1796
+ type ComponentChain = {
1797
+ /** Pin the page's `Date` for this render — the clock the component reads. */
1798
+ clock: (iso: string) => ComponentChain;
1566
1799
  /**
1567
- * Project root override for compose detection and init scripts. When
1568
- * absent, the root is auto-discovered by walking up from the calling
1569
- * specification file to the first directory containing
1570
- * `docker/compose.test.yaml`, else the first containing `package.json`
1571
- * (CONVENTIONS A9).
1800
+ * Declare what the network replies — the same contracts, the same queue
1801
+ * and the same strictness as every other facet (D7), served by msw's
1802
+ * worker instead of its node interceptor.
1572
1803
  */
1573
- root?: string;
1804
+ intercept: {
1805
+ (contracts: ContractInput): ComponentChain;
1806
+ (request: ContractRequest, response: ContractResponder | ContractResponse): ComponentChain;
1807
+ };
1808
+ /** Mount the subject, run the scenario, and capture what the page shows. */
1809
+ render: (subject: RenderSubject, scenario?: ComponentScenario) => Promise<RenderResult>;
1574
1810
  /**
1575
- * The app factory — receives the started services record (fully typed)
1576
- * and returns the Hono app. Required in node mode, ignored in compose
1577
- * mode (the app runs as a compose service there).
1811
+ * The page size THIS render gets — the Given of a component that reads
1812
+ * `matchMedia` or a container query. The project's size is restored when
1813
+ * the test ends, so a narrow render never leaks into the next one.
1578
1814
  */
1579
- server?: (services: Services) => HonoApp;
1815
+ viewport: (size: {
1816
+ height: number;
1817
+ width: number;
1818
+ }) => ComponentChain;
1580
1819
  /**
1581
- * Named infrastructure record. Keys become the `database` vocabulary of
1582
- * `.seed()` / `.table()` and drive the compose binding: a handle with no
1583
- * `composeService` option links to the compose service named exactly like
1584
- * its key, else the kebab-case conversion of the key (CONVENTIONS A6).
1820
+ * Wrap every render of this chain — the test-local Given a router stub or
1821
+ * a `<StrictMode>` is. The project's own `wrap` stays outermost: it is the
1822
+ * app's frame, and one test does not get to sit outside it.
1585
1823
  */
1586
- services?: Services;
1824
+ wrap: (wrapper: (ui: ComponentUi) => ComponentUi) => ComponentChain;
1587
1825
  };
1826
+ //#endregion
1827
+ //#region src/specification/facets/website/elements.d.ts
1588
1828
  /**
1589
- * The record returned by {@link startApi | specification.api}. Destructure
1590
- * with the canonical names (CONVENTIONS A3):
1829
+ * The element vocabulary — user-facing descriptors for visit scenarios.
1830
+ * Reads like English (`click(link('Articles'))`), translates to
1831
+ * accessibility-first locators in the browser integration. CSS/XPath is
1832
+ * deliberately not expressible; `testId()` is the single escape hatch.
1591
1833
  *
1592
- * const { api, cleanup, docker } = await specification.api(…);
1834
+ * A descriptor must designate exactly ONE element (CONVENTIONS W3). Two knobs
1835
+ * narrow it, in this order of preference:
1836
+ *
1837
+ * 1. `within(scope, target)` — search inside a landmark, the way a person
1838
+ * would say "the Articles link *in the nav*";
1839
+ * 2. `{ exact: true }` — match the accessible name whole rather than as a
1840
+ * substring, when two names genuinely overlap.
1593
1841
  */
1594
- type ApiHandle<DatabaseKey extends string = string> = {
1595
- api: ApiSpecification<DatabaseKey>;
1596
- /** Stop all infrastructure started by this specification. */
1597
- cleanup: () => Promise<void>;
1842
+ /** Options accepted by every named descriptor. */
1843
+ type ElementOptions = {
1598
1844
  /**
1599
- * Read a running container by id — returns a {@link ContainerAccessor}
1600
- * usable with `await expect(...).toBeRunning()` and read accessors.
1845
+ * Match the accessible name as a whole string. Default is substring —
1846
+ * `link('Articles')` also matches "Read Articles".
1601
1847
  */
1602
- docker: (containerId: string) => ContainerAccessor;
1603
- /** The orchestrator managing the test infrastructure lifecycle. */
1604
- orchestrator: Orchestrator;
1848
+ exact?: boolean;
1605
1849
  };
1606
- declare function startApi<Services extends ServiceRecord>(options: ApiSpecificationOptions<Services>): Promise<ApiHandle<DatabaseKeys<Services>>>;
1607
- //#endregion
1608
- //#region src/specification/facets/cli/start-cli.d.ts
1609
- /** Options for {@link startCli | specification.cli}. */
1610
- type CliSpecificationOptions<Services extends ServiceRecord = ServiceRecord> = {
1611
- /**
1612
- * Opt-in Docker awareness. When set, every spec generates a unique
1613
- * test-run id, injects it into the child process env under `envVar`,
1614
- * and exposes `.container(name)` accessors on the result that lazily
1615
- * query Docker. Always declare results with `await using` so leaked
1616
- * containers get force-removed at scope exit (CONVENTIONS B5).
1617
- */
1618
- docker?: DockerSpecConfig;
1619
- /**
1620
- * Named environment SETS for `<case>.spec.yaml` documents. An `env:` entry
1621
- * `frozen` applies the whole `frozen` record; `$WORKDIR` expands and `null`
1622
- * unsets, exactly as in `.env()`. Declared once per app so a document
1623
- * states WHICH ground it stands on, not how to build it.
1624
- */
1625
- env?: Record<string, CliEnv>;
1626
- /**
1627
- * Named servers a `<case>.spec.yaml` document may start (`serve: [mcp]`, or
1628
- * `- mcp: { KEY: value }` to add env to that one). Each entry names the
1629
- * shell `command`, the `ready` regex whose capture group holds the port the
1630
- * server announces, the `url(port)` builder, and the `env` variable that
1631
- * URL is bound to in every run's child.
1632
- */
1850
+ /** A user-facing element factory — what every name in this module is. */
1851
+ type ElementFactory = (name: string, options?: ElementOptions) => ElementRef;
1852
+ /** A button (or element with the button role), by accessible name. */
1853
+ declare const button: ElementFactory;
1854
+ /** A form field, by label. */
1855
+ declare const field: ElementFactory;
1856
+ /** A heading, by accessible name. */
1857
+ declare const heading: ElementFactory;
1858
+ /** A link, by accessible name. */
1859
+ declare const link: ElementFactory;
1860
+ /** An element containing the given text. */
1861
+ declare const content: ElementFactory;
1862
+ /** The escape hatch: an element by `data-testid`. Prefer user-facing elements. */
1863
+ declare const testId: (id: string) => ElementRef;
1864
+ /** A landmark factory — the optionally-named containers `within()` accepts. */
1865
+ type LandmarkFactory = (name?: string, options?: ElementOptions) => ElementRef;
1866
+ /** The `banner` landmark — the page header. */
1867
+ declare const banner: LandmarkFactory;
1868
+ /** The `complementary` landmark — an `<aside>`, a sidebar. */
1869
+ declare const complementary: LandmarkFactory;
1870
+ /** The `contentinfo` landmark — the page footer. */
1871
+ declare const contentinfo: LandmarkFactory;
1872
+ /** The `form` landmark — a form carrying an accessible name. */
1873
+ declare const form: LandmarkFactory;
1874
+ /** The `main` landmark — the primary content of the document. */
1875
+ declare const main: LandmarkFactory;
1876
+ /** The `navigation` landmark — a `<nav>`. Name it when a page has several. */
1877
+ declare const navigation: LandmarkFactory;
1878
+ /** The `region` landmark — a `<section>` carrying an accessible name. */
1879
+ declare const region: LandmarkFactory;
1880
+ /** The `search` landmark. */
1881
+ declare const search: LandmarkFactory;
1882
+ /**
1883
+ * Restrict a descriptor to the inside of another — the answer to ambiguity,
1884
+ * and the one the framework prefers over a test id.
1885
+ *
1886
+ * click(within(navigation(), link('Articles')))
1887
+ *
1888
+ * Composes outside-in: the scope may itself be scoped, so a deeply nested
1889
+ * target reads `within(main(), within(region('Series'), link('Part 2')))`.
1890
+ * Any descriptor works as a scope, including `testId()` when a container has
1891
+ * no landmark role to stand on.
1892
+ */
1893
+ declare const within: (scope: ElementRef, target: ElementRef) => ElementRef;
1894
+ /** A modal or non-modal `<dialog>`, by accessible name. A closed one is absent. */
1895
+ declare const dialog: LandmarkFactory;
1896
+ /** A live region announcing a result — `role="status"`, an `<output>`. */
1897
+ declare const status: LandmarkFactory;
1898
+ /** A table, by its caption or accessible name. */
1899
+ declare const table: LandmarkFactory;
1900
+ /** A row of a table or grid, by the text of its cells. */
1901
+ declare const row: LandmarkFactory;
1902
+ /** An item of a list, by its text. Retires the `.first()` of an unnamed `<li>`. */
1903
+ declare const listitem: LandmarkFactory;
1904
+ /**
1905
+ * An option of a select or a listbox, by its label — named inside the field
1906
+ * that holds it: `within(field('Channel'), option('LinkedIn'))`.
1907
+ *
1908
+ * Asserted by PRESENCE, not by visibility: the options of a collapsed
1909
+ * `<select>` are in the document and in the accessibility tree, and none of
1910
+ * them has a box on the screen until it is opened. `see(option('LinkedIn'))`
1911
+ * therefore asks "is it offered", and `see(selected(option('LinkedIn')))`
1912
+ * asks which one the field is on.
1913
+ */
1914
+ declare const option: ElementFactory;
1915
+ /**
1916
+ * Where the keyboard is: `see(focused(button('Open')))` asserts the element has
1917
+ * focus, `gone(focused(x))` that it does not.
1918
+ *
1919
+ * A modifier rather than a descriptor of its own, because focus is a STATE of
1920
+ * an element the vocabulary can already name. It is a verb's business and never
1921
+ * a golden's: the accessibility tree carries no focus, so a tree snapshot of a
1922
+ * dialog that took the keyboard and one that did not are byte-identical.
1923
+ */
1924
+ declare const focused: (element: ElementRef) => ElementRef;
1925
+ /**
1926
+ * Whether the element accepts input: `see(disabled(button('Delete')))` asserts
1927
+ * it refuses, `see(enabled(button('Delete')))` that it takes it.
1928
+ *
1929
+ * Modifiers rather than descriptors, for the same reason as `focused`: being
1930
+ * disabled is a state of an element the vocabulary already names. Unlike focus,
1931
+ * the ARIA tree carries it, so a golden pins a whole outline's enablement and
1932
+ * these name the ONE control a test is about. They also buy the direction a
1933
+ * behavioural substitute cannot reach — clicking a disabled control is a
1934
+ * timeout, never an assertion.
1935
+ */
1936
+ declare const disabled: (element: ElementRef) => ElementRef;
1937
+ /** The other direction of {@link disabled} — the element takes input. */
1938
+ declare const enabled: (element: ElementRef) => ElementRef;
1939
+ /**
1940
+ * Which option the field is on: `see(selected(option('LinkedIn')))`, and
1941
+ * `gone(selected(option('X')))` for the one it left.
1942
+ *
1943
+ * A modifier for the same reason as {@link disabled}: being chosen is a state
1944
+ * of an element the vocabulary already names. No matcher answers for it — a
1945
+ * `<option>` is not a checkbox — so both adapters read the `:checked` the CSS
1946
+ * spec gives a selected option.
1947
+ */
1948
+ declare const selected: (element: ElementRef) => ElementRef;
1949
+ /**
1950
+ * What the field holds: `see(valued(field('Title'), 'Launch teaser'))`, and
1951
+ * `gone(valued(field('Title'), '…'))` for a value it no longer holds.
1952
+ *
1953
+ * A modifier for the same reason as {@link disabled}: what a field holds is a
1954
+ * state of an element the vocabulary already names, and this is how the ONE
1955
+ * field a test is about is waited for — a golden pins a whole outline instead.
1956
+ * Read from the node's live value, never from the `value` ATTRIBUTE, which a
1957
+ * controlled input never moves.
1958
+ */
1959
+ declare const valued: (element: ElementRef, value: string) => ElementRef;
1960
+ //#endregion
1961
+ //#region src/specification/contracts/filters.d.ts
1962
+ /**
1963
+ * A text filter on a provider request builder (`openai.chat({ user })`,
1964
+ * `anthropic.messages({ system })`, …).
1965
+ *
1966
+ * A **string is EXACT**. That is deliberate: a substring filter silently
1967
+ * cross-matches — two prompts sharing a preamble both satisfy the first
1968
+ * contract, and the spec goes green on the wrong reply. Looser matching is
1969
+ * explicit, and says which looseness it means:
1970
+ *
1971
+ * - a `RegExp` — pattern matching;
1972
+ * - `match.includes('…')` — containment, the code-only matcher (it never joins
1973
+ * the `{{token}}` file vocabulary, CONVENTIONS D4);
1974
+ * - any other `match.*` matcher, evaluated by the same structural engine the
1975
+ * assertions use.
1976
+ */
1977
+ type TextFilter = Matcher | RegExp | string;
1978
+ //#endregion
1979
+ //#region src/integrations/anthropic/anthropic.d.ts
1980
+ type AnthropicMessagesFilter = {
1981
+ model?: TextFilter;
1982
+ system?: TextFilter;
1983
+ user?: TextFilter;
1984
+ tools?: string[];
1985
+ };
1986
+ /**
1987
+ * Anthropic API intercept helpers.
1988
+ */
1989
+ declare const anthropic: {
1990
+ /**
1991
+ * Request: match Messages API calls, optionally routed through a
1992
+ * custom gateway URL. When used with a JSON fixture file, the data is
1993
+ * returned as-is (no wrapping) because Anthropic fixtures are typically
1994
+ * already in the Messages API response shape.
1995
+ *
1996
+ * @example
1997
+ * anthropic.messages()
1998
+ * anthropic.messages({ system: /classify/ })
1999
+ * anthropic.messages({ user: buildPrompt() }) // string = EXACT equality
2000
+ * anthropic.messages({ user: /classify/ }, GATEWAY)
2001
+ */
2002
+ messages(filter?: AnthropicMessagesFilter, url?: string): ContractRequest;
2003
+ /** Response: wrap data in Anthropic messages format. */
2004
+ reply(data: unknown): ContractResponse;
2005
+ /** Response: return an Anthropic error. */
2006
+ error(status: number, message?: string): ContractResponse;
2007
+ /** Response: simulate a timeout. */
2008
+ timeout(): ContractResponse;
2009
+ };
2010
+ //#endregion
2011
+ //#region src/specification/contracts/http.d.ts
2012
+ /**
2013
+ * Request filters for the generic HTTP provider. Every field is a subset
2014
+ * constraint — a request matches when all provided fields match.
2015
+ */
2016
+ type HttpContractFilter = {
2017
+ /**
2018
+ * Body constraint. An object is a deep SUBSET match (toMatchObject-style)
2019
+ * whose leaf values may be `match.*` matchers; a string is a containment
2020
+ * test and a RegExp a `test()` over the raw text body.
2021
+ */
2022
+ body?: object | RegExp | string;
2023
+ /** Header subset. Names are case-insensitive; string = exact value, RegExp = `test()`. */
2024
+ headers?: Record<string, RegExp | string>;
2025
+ /** Query-param subset. string = exact value, RegExp = `test()`. */
2026
+ query?: Record<string, RegExp | string>;
2027
+ };
2028
+ /** Init options for a streamed reply. */
2029
+ type HttpStreamInit = {
2030
+ /** The `content-type` the stream is served under. Default `application/octet-stream`. */
2031
+ contentType?: string;
2032
+ /** Milliseconds between two chunks. Default 0 — every chunk at once. */
2033
+ delay?: number;
2034
+ /** Response headers, merged over the builder's own. */
2035
+ headers?: Record<string, string>;
2036
+ /** HTTP status code. Default 200. */
2037
+ status?: number;
2038
+ };
2039
+ /** One server-sent event, as `http.sse()` frames it. */
2040
+ type SseEvent = {
2041
+ /** The `data:` payload. An object is serialised as JSON; a string is sent as-is. */
2042
+ data: unknown;
2043
+ /** The `event:` name. Omitted for an unnamed (default `message`) event. */
2044
+ event?: string;
2045
+ /** The `id:` the client echoes as `Last-Event-ID` when it reconnects. */
2046
+ id?: string;
2047
+ /** The `retry:` hint, in milliseconds. */
2048
+ retry?: number;
2049
+ };
2050
+ /** Init options shared by the response builders. */
2051
+ type HttpResponseInit = {
2052
+ /** Delay in ms before responding (for timeout testing). */
2053
+ delay?: number;
2054
+ /** Response headers, merged over the builder's own. */
2055
+ headers?: Record<string, string>;
2056
+ /** HTTP status code. */
2057
+ status?: number;
2058
+ };
2059
+ /**
2060
+ * Generic HTTP contract helpers for any URL. The url is absolute (string or
2061
+ * RegExp), or a PATH FORM starting with `/` — `http.get('/articles/{{uuid}}')`
2062
+ * matches that path on ANY origin, which is what an app calling its own
2063
+ * backend needs. An optional {@link HttpContractFilter} narrows matching by
2064
+ * body, headers, or query — a request that hits the URL/method but fails the
2065
+ * filter counts as unmatched (strict contracts, CONVENTIONS D7).
2066
+ *
2067
+ * @example
2068
+ * defineContract({ request: http.get('/articles/{{uuid}}'), response: http.json(article) })
2069
+ * defineContract({ request: http.post(URL, { body: { user: 'alice' } }), response: http.empty() })
2070
+ */
2071
+ declare const http: {
2072
+ any(url: RegExp | string, filter?: HttpContractFilter): ContractRequest;
2073
+ delete(url: RegExp | string, filter?: HttpContractFilter): ContractRequest;
2074
+ get(url: RegExp | string, filter?: HttpContractFilter): ContractRequest;
2075
+ patch(url: RegExp | string, filter?: HttpContractFilter): ContractRequest;
2076
+ post(url: RegExp | string, filter?: HttpContractFilter): ContractRequest;
2077
+ put(url: RegExp | string, filter?: HttpContractFilter): ContractRequest;
2078
+ /** Response: a body-less reply (204 by default). */
2079
+ empty(status?: number): ContractResponse;
2080
+ /** Response: an error status. Without a body, `{ error: 'HTTP <status>' }`. */
2081
+ error(status: number, body?: unknown): ContractResponse;
2082
+ /** Response: a JSON body (200 by default). */
2083
+ json(body: unknown, init?: HttpResponseInit): ContractResponse;
2084
+ /**
2085
+ * Response: no response at all — the request fails in transport, the way a
2086
+ * server that is not running fails it. `fetch` rejects; no status is served.
2087
+ */
2088
+ unreachable(): ContractResponse;
2089
+ /**
2090
+ * Response: a body that arrives in PIECES, written in order.
2091
+ *
2092
+ * A subject that reads a response as it lands — a token-by-token render, a
2093
+ * progress bar, a reconnect on a half-read body — is specified by the
2094
+ * chunks and their order, which a single serialised body cannot state.
2095
+ * Honoured by all three engines: msw's server, msw's worker, and the
2096
+ * `node:http` stub the website and mobile facets serve from.
2097
+ *
2098
+ * @example
2099
+ * http.stream(['Hel', 'lo, ', 'world'], { contentType: 'text/plain', delay: 10 })
2100
+ */
2101
+ stream(chunks: readonly string[], init?: HttpStreamInit): ContractResponse;
2102
+ /**
2103
+ * Response: a server-sent event stream — one chunk per event, framed the
2104
+ * way an `EventSource` reads them, served as `text/event-stream`.
2105
+ *
2106
+ * @example
2107
+ * http.sse([{ data: { token: 'Hel' } }, { data: { token: 'lo' } }, { event: 'done', data: '' }])
2108
+ */
2109
+ sse(events: readonly SseEvent[], init?: Omit<HttpStreamInit, "contentType">): ContractResponse;
2110
+ /** Response: a text body, served as `text/plain` (200 by default). */
2111
+ text(body: string, init?: HttpResponseInit): ContractResponse;
2112
+ };
2113
+ //#endregion
2114
+ //#region src/integrations/openai/openai.d.ts
2115
+ type OpenAIChatFilter = {
2116
+ model?: TextFilter;
2117
+ system?: TextFilter;
2118
+ user?: TextFilter;
2119
+ tools?: string[];
2120
+ temperature?: number;
2121
+ };
2122
+ type OpenAIResponsesFilter = {
2123
+ model?: TextFilter;
2124
+ system?: TextFilter;
2125
+ user?: TextFilter;
2126
+ tools?: string[];
2127
+ };
2128
+ /**
2129
+ * OpenAI API intercept helpers.
2130
+ */
2131
+ declare const openai: {
2132
+ /**
2133
+ * Request: match Chat Completions API calls. STRING filters mean EXACT
2134
+ * equality (pass the app's own prompt builder); loosen deliberately with a
2135
+ * RegExp or `match.includes(...)`.
2136
+ *
2137
+ * @example
2138
+ * openai.chat() // any chat call
2139
+ * openai.chat({ model: 'gpt-4o' }) // exact model
2140
+ * openai.chat({ system: buildPrompt() }) // exact system prompt
2141
+ * openai.chat({ system: /classify/ }) // pattern
2142
+ */
2143
+ chat(filter?: OpenAIChatFilter): ContractRequest;
2144
+ /**
2145
+ * Request: match Responses API calls (AI SDK v5+) with auto-wrapping.
2146
+ * String filters mean EXACT equality (see {@link openai.chat}).
2147
+ * When used with a JSON file, the data is automatically wrapped in the
2148
+ * Responses API envelope.
2149
+ *
2150
+ * @param filter - Optional body filters.
2151
+ * @param url - Custom gateway URL (default: api.openai.com).
2152
+ *
2153
+ * @example
2154
+ * openai.responses({ user: /Report Ingestion/ }, GATEWAY)
2155
+ */
2156
+ responses(filter?: OpenAIResponsesFilter, url?: string): ContractRequest;
2157
+ /**
2158
+ * Response: wrap data in Chat Completions format.
2159
+ *
2160
+ * @example
2161
+ * openai.reply({ categories: ['TECH'] })
2162
+ */
2163
+ reply(data: unknown): ContractResponse;
2164
+ /** Response: return an OpenAI error. */
2165
+ error(status: number, message?: string): ContractResponse;
2166
+ /** Response: return malformed content. */
2167
+ malformed(content: string): ContractResponse;
2168
+ /** Response: simulate a timeout. */
2169
+ timeout(): ContractResponse;
2170
+ };
2171
+ //#endregion
2172
+ //#region src/vitest/mock-of.d.ts
2173
+ /** How much of the port the double answers for. */
2174
+ type MockOfOptions = {
2175
+ /**
2176
+ * Deep (the default): reading a member that was never stubbed hands back
2177
+ * another double, however far down the port nests. `false` gives the flat
2178
+ * proxy — every member of `T` and nothing beneath them, which is what a
2179
+ * port with a nested namespace wants when the test only ever touches the
2180
+ * first level.
2181
+ */
2182
+ deep?: boolean;
2183
+ };
2184
+ /**
2185
+ * A typed double for an injected port — the fourth rung of the doubles ladder
2186
+ * (docs/12-conventions.md), and the only one a module test may build itself.
2187
+ *
2188
+ * The type argument is the port: `T` is constrained to `object` and has no
2189
+ * default, so a double is always asked for something. A call with no argument
2190
+ * answers for `object`, which satisfies no port and fails where it is used.
2191
+ *
2192
+ * @example
2193
+ * const gateway = mockOf<PaymentGateway>(); // deep
2194
+ * const clock = mockOf<ClockPort>({ deep: false }); // flat
2195
+ */
2196
+ declare function mockOf<T extends object>(options: {
2197
+ deep: false;
2198
+ }): MockProxy<T>;
2199
+ declare function mockOf<T extends object>(options?: MockOfOptions): DeepMockProxy<T>;
2200
+ /** The factory's own shape — kept as a name so a consumer can annotate with it. */
2201
+ type MockPort = typeof mockOf;
2202
+ //#endregion
2203
+ //#region src/vitest/mock-of-date.d.ts
2204
+ /** Interface for freezing and resetting the global Date in tests. */
2205
+ type MockDatePort = {
2206
+ /** Restore the real Date object. */
2207
+ reset: () => void;
2208
+ /** Freeze `Date.now()` and `new Date()` to the given value. */
2209
+ set: (date: Date | number | string) => void;
2210
+ };
2211
+ /**
2212
+ * Freeze or reset the global Date for deterministic time-dependent tests.
2213
+ * Wraps the `mockdate` package.
2214
+ */
2215
+ declare const mockOfDate: MockDatePort;
2216
+ //#endregion
2217
+ //#region src/vitest/clock.d.ts
2218
+ /**
2219
+ * The one time primitive.
2220
+ *
2221
+ * Time is the determinism the framework owns (CONVENTIONS D16): a test that
2222
+ * samples `Date.now()` and asserts on what comes back is a test that fails on
2223
+ * the next leap second, and a test that reaches for `vi.useFakeTimers()` owns a
2224
+ * teardown it will one day forget. `clock` is both answers in one name — the
2225
+ * instant is stated, and the scope restores itself.
2226
+ *
2227
+ * ```typescript
2228
+ * using _ = clock.at('2026-03-04T09:30:00Z'); // Date is pinned until the scope ends
2229
+ * ```
2230
+ *
2231
+ * `at()` takes the CALENDAR and leaves the scheduler alone: a UI framework's
2232
+ * own loop, a `setTimeout` inside the subject and every promise still resolve
2233
+ * on their own. `run()` takes the scheduler too, for a subject whose behaviour
2234
+ * IS the passage of time — a debounce, a retry backoff, a poll.
2235
+ */
2236
+ /** A pinned clock — released when the `using` scope that declared it ends. */
2237
+ type PinnedClock = Disposable;
2238
+ declare const clock: {
2239
+ /**
2240
+ * Move the pinned clock forward by `ms` — and, under {@link clock.run},
2241
+ * fire every callback that came due, awaiting what each of them started.
2242
+ *
2243
+ * Only a pinned clock moves: called with no clock taken, it says so rather
2244
+ * than silently doing nothing to the real one.
2245
+ */
2246
+ advance(ms: number): Promise<void>;
2247
+ /**
2248
+ * Pin `Date` at `iso` for the current scope. `Date` ONLY: the scheduler
2249
+ * stays real, so a subject that awaits, renders or polls keeps running.
2250
+ *
2251
+ * @example
2252
+ * using _ = clock.at('2026-03-04T09:30:00Z');
2253
+ * expect(stampedAt()).toBe('2026-03-04T09:30:00.000Z');
2254
+ */
2255
+ at(iso: string): PinnedClock;
2256
+ /**
2257
+ * Take the scheduler as well as the calendar: `setTimeout`, `setInterval`
2258
+ * and their friends queue instead of firing, and {@link clock.advance} is
2259
+ * what makes them due. For a subject whose behaviour IS elapsed time — a
2260
+ * debounce, a retry backoff, a poll — where waiting for real would be the
2261
+ * arbitrary sleep J2 forbids.
2262
+ *
2263
+ * @example
2264
+ * using _ = clock.run('2026-03-04T09:30:00Z');
2265
+ * const pending = retrying(failsTwice);
2266
+ * await clock.advance(5_000);
2267
+ * await expect(pending).resolves.toBe('ok');
2268
+ */
2269
+ run(iso?: string): PinnedClock;
2270
+ };
2271
+ //#endregion
2272
+ //#region src/specification/assertions/required.d.ts
2273
+ /**
2274
+ * The value, or a failure that says what was missing and why it mattered.
2275
+ *
2276
+ * A test reaching into a captured structure — a row, a header, the third
2277
+ * element of a list — meets `T | undefined` and has to do something about it.
2278
+ * The two things it usually does are both wrong: `!` erases the question, and
2279
+ * an `if (!x) throw new Error('missing')` re-states the same three lines in
2280
+ * every repository (the estate had two hand-written copies of exactly this).
2281
+ * `required` is that gesture with the reason attached, so the failure reads as
2282
+ * a sentence rather than as a `TypeError` two frames further down.
2283
+ *
2284
+ * @example
2285
+ * const id = required(result.response.body.id, 'the creation reply carries the new id');
2286
+ */
2287
+ declare function required<T>(value: null | T | undefined, why: string): T;
2288
+ //#endregion
2289
+ //#region src/specification/assertions/wait-until.d.ts
2290
+ /** How long to wait, and how often to look. */
2291
+ type WaitUntilOptions = {
2292
+ /** Milliseconds between two readings. Default 50. */
2293
+ interval?: number;
2294
+ /** How long the condition has to become true. Default 5 000 ms. */
2295
+ timeout?: number;
2296
+ /** What the condition is, named in the failure. Default: the predicate's source. */
2297
+ why?: string;
2298
+ };
2299
+ /**
2300
+ * Wait until a condition holds — the sanctioned answer to "the thing I am
2301
+ * specifying is not ready yet".
2302
+ *
2303
+ * A spec that sleeps for a guessed duration is a spec that is slow on a fast
2304
+ * machine and flaky on a slow one, which is why J2 refuses `setTimeout` under
2305
+ * `specs/`. Every facet that drives something already waits on a CONDITION —
2306
+ * a served page, a banner on stdout, an element the visitor can see — and this
2307
+ * is that primitive where no facet owns the waiting: a background write to
2308
+ * land, a queue to drain, a file to appear.
2309
+ *
2310
+ * The failure names the condition and how long it was given, so a timeout is a
2311
+ * sentence rather than "expected true, got false".
2312
+ *
2313
+ * The budget is measured on `performance.now()`, not on `Date` — `clock.at()`
2314
+ * freezes the calendar, and a deadline read off a frozen calendar never
2315
+ * arrives: the poll would run until vitest killed the test with a sentence
2316
+ * about the file rather than about the condition.
2317
+ *
2318
+ * Not for a subject under `clock.run()`: there the scheduler is the test's, and
2319
+ * `clock.advance(ms)` is what makes time pass.
2320
+ *
2321
+ * @example
2322
+ * await waitUntil(() => outbox.length === 1, { why: 'the job wrote its one message' });
2323
+ */
2324
+ declare function waitUntil(predicate: () => boolean | Promise<boolean>, options?: WaitUntilOptions): Promise<void>;
2325
+ //#endregion
2326
+ //#region src/surface.d.ts
2327
+ declare module 'vitest' {
2328
+ interface Assertion<T = any> {
2329
+ /**
2330
+ * Assert the subject is empty — zero rows for a table (async), an
2331
+ * empty stream for a text accessor (console, errors, stdout).
2332
+ */
2333
+ toBeEmpty: T extends TableAccessor ? () => Promise<void> : T extends {
2334
+ readonly comparableText: string;
2335
+ } ? () => Promise<void> : never;
2336
+ /** Assert the container is running. Async — docker-backed subject. */
2337
+ toBeRunning: T extends ContainerAccessor ? () => Promise<void> : never;
2338
+ /**
2339
+ * On `@jterrazz/test` accessors: assert the subject matches a fixture
2340
+ * file under `_expected/<name>` (flat — a slash creates a subfolder;
2341
+ * `.http` format for `result.response`). Async for filesystem/directory
2342
+ * subjects (tree compare on disk), and for a subject captured INSIDE a
2343
+ * page (`result.tree`, `result.html`, … — the file crosses the browser
2344
+ * seam through a server command).
2345
+ *
2346
+ * Pass `{ frozen: true }` to opt a single fixture OUT of update-mode
2347
+ * rewriting: a frozen fixture is never overwritten under `TEST_UPDATE=1`
2348
+ * (or vitest `-u`), and a frozen mismatch/missing fixture still throws.
2349
+ * Use it for a deliberately-wrong fixture whose diff/error rendering is
2350
+ * the behaviour under test.
2351
+ */
2352
+ toMatch: T extends DirectoryAccessor | FilesystemAccessor ? (name: RegExp | string, options?: MatchFixtureOptions) => Promise<void> : T extends {
2353
+ readonly capturedInPage: true;
2354
+ } ? (name: RegExp | string, options?: MatchFixtureOptions) => Promise<void> : T extends JsonAccessor | ResponseAccessor | TextAccessor ? (name: RegExp | string, options?: MatchFixtureOptions) => void : (expected: RegExp | string, options?: MatchFixtureOptions) => void;
2355
+ /**
2356
+ * Assert the table contains exactly the given rows for the given
2357
+ * columns. Cells accept `match.*` dynamic-value matchers. Async —
2358
+ * queries the database.
2359
+ */
2360
+ toMatchRows: T extends TableAccessor ? (expected: {
2361
+ columns: string[];
2362
+ rows: readonly (readonly unknown[])[];
2363
+ }) => Promise<void> : never;
2364
+ }
2365
+ }
2366
+ //#endregion
2367
+ //#region src/specification/facets/_common/orchestrator.d.ts
2368
+ type OrchestratorOptions = {
2369
+ /**
2370
+ * Named infrastructure record. Keys become the database vocabulary of the
2371
+ * spec (`.seed()` / `.table()` `database` option) and drive the compose
2372
+ * binding: a handle with no explicit `composeService` links to the compose
2373
+ * service named exactly like its key, else the kebab-case conversion of the
2374
+ * key (`analyticsDb` → `analytics-db`) — see {@link resolveComposeBinding}.
2375
+ */
2376
+ services: Record<string, ServiceHandle>;
2377
+ mode: 'e2e' | 'integration';
2378
+ /**
2379
+ * The project root, already resolved. REQUIRED: the constructors derive it
2380
+ * by walking up from the calling specification file (CONVENTIONS A9), and
2381
+ * the orchestrator is handed the answer. Defaulting to `process.cwd()` here
2382
+ * meant one silent second opinion about what the project is — the runner
2383
+ * resolving from the caller, this from wherever the runner happened to be
2384
+ * launched, which in a workspace is rarely the same directory.
2385
+ */
2386
+ root: string;
2387
+ /** Compose project name — used for per-worker stack isolation. */
2388
+ projectName?: string;
2389
+ };
2390
+ /**
2391
+ * Orchestrator for test infrastructure.
2392
+ * Integration: starts services via testcontainers.
2393
+ * E2E: runs full docker compose up.
2394
+ */
2395
+ declare class Orchestrator {
2396
+ private readonly services;
2397
+ private readonly mode;
2398
+ private readonly root;
2399
+ private readonly projectName;
2400
+ private running;
2401
+ private composeStack;
2402
+ private composeHandles;
2403
+ private started;
2404
+ constructor(options: OrchestratorOptions);
2405
+ /**
2406
+ * Bind each declared handle to a compose service (CONVENTIONS A6): a record
2407
+ * key resolves to the service named exactly like it, else the kebab-case
2408
+ * conversion of the key; an explicit `composeService` wins. Throws on an
2409
+ * ambiguous binding (both names present). Runs once compose config is known
2410
+ * so the two-step resolution can consult the real service list.
2411
+ */
2412
+ private resolveBindings;
2413
+ /**
2414
+ * Start declared services via testcontainers (integration mode).
2415
+ * Phase 1: start all containers in parallel (the slow part).
2416
+ * Phase 2: wire connections, healthcheck, and init sequentially (fast).
2417
+ */
2418
+ start(): Promise<void>;
2419
+ /**
2420
+ * Stop testcontainers (integration mode).
2421
+ */
2422
+ stop(): Promise<void>;
2423
+ /**
2424
+ * Start full docker compose stack (e2e mode).
2425
+ * Auto-detects infra services and creates handles for them.
2426
+ */
2427
+ startCompose(): Promise<void>;
2428
+ /**
2429
+ * Stop docker compose stack (e2e mode).
2430
+ */
2431
+ stopCompose(): Promise<void>;
2432
+ /**
2433
+ * Get the default database — the first declared handle that is one.
2434
+ */
2435
+ getDatabase(): DatabasePort | null;
2436
+ /**
2437
+ * Get all database services keyed by their record key (declared services)
2438
+ * or compose service name (stack-detected services).
2439
+ */
2440
+ getDatabases(): Map<string, DatabasePort>;
2441
+ private allHandles;
2442
+ /**
2443
+ * Get app URL from compose (e2e mode).
2444
+ */
2445
+ getAppUrl(): null | string;
2446
+ }
2447
+ //#endregion
2448
+ //#region src/specification/facets/_common/services.d.ts
2449
+ /**
2450
+ * Infrastructure services declared as a named record. Keys become the typed
2451
+ * vocabulary of the whole spec: the server factory receives the same record,
2452
+ * and `.seed()` / `.table()` target databases by key.
2453
+ */
2454
+ type ServiceRecord = Record<string, ServiceHandle>;
2455
+ /** Keys of a services record whose handles are databases. */
2456
+ type DatabaseKeys<Services extends ServiceRecord> = { [K in keyof Services]: Services[K] extends DatabasePort ? K & string : never; }[keyof Services];
2457
+ //#endregion
2458
+ //#region src/specification/facets/api/start-api.d.ts
2459
+ /** Any object with a request method compatible with Hono's app.request(). */
2460
+ type HonoApp = {
2461
+ request: (path: string, init?: RequestInit) => Promise<Response> | Response;
2462
+ };
2463
+ /** Execution mode — exists ONLY on `specification.api()` (CONVENTIONS A5). */
2464
+ type SpecificationMode = 'compose' | 'node';
2465
+ /** Options for {@link startApi | specification.api}. */
2466
+ type ApiSpecificationOptions<Services extends ServiceRecord = ServiceRecord> = {
2467
+ /**
2468
+ * Execution mode override. Resolution: `options.mode` >
2469
+ * `process.env.TEST_MODE` > `'node'`. Never hardcode this in a
2470
+ * specification file when `server` is defined — set it per vitest
2471
+ * project via `env: { TEST_MODE: 'compose' }` (CONVENTIONS A5).
2472
+ */
2473
+ mode?: SpecificationMode;
2474
+ /**
2475
+ * Project root override for compose detection and init scripts. When
2476
+ * absent, the root is auto-discovered by walking up from the calling
2477
+ * specification file to the first directory containing
2478
+ * `docker/compose.test.yaml`, else the first containing `package.json`
2479
+ * (CONVENTIONS A9).
2480
+ */
2481
+ root?: string;
2482
+ /**
2483
+ * The app factory — receives the started services record (fully typed)
2484
+ * and returns the Hono app. Required in node mode, ignored in compose
2485
+ * mode (the app runs as a compose service there).
2486
+ */
2487
+ server?: (services: Services) => HonoApp;
2488
+ /**
2489
+ * Named infrastructure record. Keys become the `database` vocabulary of
2490
+ * `.seed()` / `.table()` and drive the compose binding: a handle with no
2491
+ * `composeService` option links to the compose service named exactly like
2492
+ * its key, else the kebab-case conversion of the key (CONVENTIONS A6).
2493
+ */
2494
+ services?: Services;
2495
+ };
2496
+ /**
2497
+ * The record returned by {@link startApi | specification.api}. Destructure
2498
+ * with the canonical names (CONVENTIONS A3):
2499
+ *
2500
+ * const { api, cleanup, docker } = await specification.api(…);
2501
+ */
2502
+ type ApiHandle<DatabaseKey extends string = string> = {
2503
+ api: ApiSpecification<DatabaseKey>;
2504
+ /** Stop all infrastructure started by this specification. */
2505
+ cleanup: () => Promise<void>;
2506
+ /**
2507
+ * Read a running container by id — returns a {@link ContainerAccessor}
2508
+ * usable with `await expect(...).toBeRunning()` and read accessors.
2509
+ */
2510
+ docker: (containerId: string) => ContainerAccessor;
2511
+ /** The orchestrator managing the test infrastructure lifecycle. */
2512
+ orchestrator: Orchestrator;
2513
+ };
2514
+ declare function startApi<Services extends ServiceRecord>(options: ApiSpecificationOptions<Services>): Promise<ApiHandle<DatabaseKeys<Services>>>;
2515
+ //#endregion
2516
+ //#region src/specification/facets/cli/start-cli.d.ts
2517
+ /** Options for {@link startCli | specification.cli}. */
2518
+ type CliSpecificationOptions<Services extends ServiceRecord = ServiceRecord> = {
2519
+ /**
2520
+ * Opt-in Docker awareness. When set, every spec generates a unique
2521
+ * test-run id, injects it into the child process env under `envVar`,
2522
+ * and exposes `.container(name)` accessors on the result that lazily
2523
+ * query Docker. Always declare results with `await using` so leaked
2524
+ * containers get force-removed at scope exit (CONVENTIONS B5).
2525
+ */
2526
+ docker?: DockerSpecConfig;
2527
+ /**
2528
+ * Environment applied to EVERY run of this binary — the variables the
2529
+ * product needs to be deterministic at all (`TZ`, `NO_COLOR`, `LANG`,
2530
+ * a config home under the spec's own workdir). Stated once per app
2531
+ * instead of repeated on every chain and in every document; a chained
2532
+ * `.env()` and a document's `env:` both win over it.
2533
+ */
2534
+ defaults?: CliEnv;
2535
+ /**
2536
+ * Named environment SETS for `<case>.spec.yaml` documents. An `env:` entry
2537
+ * `frozen` applies the whole `frozen` record; `$WORKDIR` expands and `null`
2538
+ * unsets, exactly as in `.env()`. Declared once per app so a document
2539
+ * states WHICH ground it stands on, not how to build it.
2540
+ */
2541
+ env?: Record<string, CliEnv>;
2542
+ /**
2543
+ * Named servers a `<case>.spec.yaml` document may start (`serve: [mcp]`, or
2544
+ * `- mcp: { KEY: value }` to add env to that one). Each entry names the
2545
+ * shell `command`, the `ready` regex whose capture group holds the port the
2546
+ * server announces, the `url(port)` builder, and the `env` variable that
2547
+ * URL is bound to in every run's child.
2548
+ */
1633
2549
  serve?: Record<string, LiterateServeRegistration>;
1634
2550
  /**
1635
2551
  * Project-root override (CONVENTIONS A9) — the single meaning of `root`:
@@ -1673,6 +2589,42 @@ type CliHandle<DatabaseKey extends string = string> = {
1673
2589
  };
1674
2590
  declare function startCli<Services extends ServiceRecord>(bin: string, options?: CliSpecificationOptions<Services>): Promise<CliHandle<DatabaseKeys<Services>>>;
1675
2591
  //#endregion
2592
+ //#region src/specification/facets/integration/start-integration.d.ts
2593
+ /** Options for {@link startIntegration | specification.integration}. */
2594
+ type IntegrationSpecificationOptions<Services extends ServiceRecord = ServiceRecord> = {
2595
+ /** Project-root override — see the `root` option of `specification.api()`. */
2596
+ root?: string;
2597
+ /**
2598
+ * Named infrastructure the module is specified AGAINST — a real database,
2599
+ * a real cache, a `process()` it talks to. Omit it for the other half of
2600
+ * the facet: a pure module whose oracle is a golden.
2601
+ */
2602
+ services?: Services;
2603
+ };
2604
+ /**
2605
+ * The record returned by {@link startIntegration | specification.integration}.
2606
+ * Destructure with the canonical names (CONVENTIONS A3):
2607
+ *
2608
+ * const { integration, cleanup } = await specification.integration(…);
2609
+ */
2610
+ type IntegrationHandle<Services extends ServiceRecord = ServiceRecord, DatabaseKey extends string = string> = {
2611
+ /** Stop all infrastructure started by this specification. */
2612
+ cleanup: () => Promise<void>;
2613
+ integration: IntegrationSpecification<Services, DatabaseKey>;
2614
+ };
2615
+ /**
2616
+ * Specify a module the way the assembled product is specified: against real
2617
+ * services and declared contracts, with the golden mechanism on what it
2618
+ * produces.
2619
+ *
2620
+ * The fork is the SUBJECT. A module alone is a module test, beside its code,
2621
+ * with no runner at all. A module that needs a real database, or whose oracle
2622
+ * is a golden file, is this — and it used to be neither: a `specs/` folder
2623
+ * with plain vitest, a hand-built sqlite template, a `beforeAll` that started
2624
+ * a container, and a `toMatchSnapshot` where the package has a golden engine.
2625
+ */
2626
+ declare function startIntegration<Services extends ServiceRecord>(options?: IntegrationSpecificationOptions<Services>): Promise<IntegrationHandle<Services, DatabaseKeys<Services>>>;
2627
+ //#endregion
1676
2628
  //#region src/specification/facets/jobs/start-jobs.d.ts
1677
2629
  /** Options for {@link startJobs | specification.jobs}. */
1678
2630
  type JobsSpecificationOptions<Services extends ServiceRecord = ServiceRecord> = {
@@ -1719,7 +2671,7 @@ type MobileBackendOptions = {
1719
2671
  port?: number;
1720
2672
  };
1721
2673
  /** Options for {@link startMobile | specification.mobile}. */
1722
- type MobileSpecificationOptions = {
2674
+ type MobileSpecificationOptions<Services extends ServiceRecord = ServiceRecord> = {
1723
2675
  /** The app under test — terminated and relaunched by every `.open()`. */
1724
2676
  app: {
1725
2677
  /** Bundle id of the installed app (`com.example.app`). */
@@ -1752,6 +2704,14 @@ type MobileSpecificationOptions = {
1752
2704
  * driving a DEV build states the wait its bundler's cold boot needs
1753
2705
  * (`{ action: 45_000 }`) instead of sleeping inside its scenarios.
1754
2706
  */
2707
+ /**
2708
+ * Named services started with the runner and stopped with it — a
2709
+ * `process()` for the bundler the app loads from, a database a dev build
2710
+ * reads. Metro stops being a `beforeAll` the repository maintains: it is
2711
+ * `process({ command: 'expo start', ready: /Metro waiting on .*:(\\d+)/ })`
2712
+ * like every other external process the framework owns.
2713
+ */
2714
+ services?: Services;
1755
2715
  timeouts?: DeviceTimeouts;
1756
2716
  };
1757
2717
  /**
@@ -1773,13 +2733,35 @@ type MobileHandle = {
1773
2733
  /** The resolved simulator UDID the specs run against. */
1774
2734
  udid: string;
1775
2735
  };
1776
- declare function startMobile(options: MobileSpecificationOptions): Promise<MobileHandle>;
2736
+ declare function startMobile<Services extends ServiceRecord>(options: MobileSpecificationOptions<Services>): Promise<MobileHandle>;
1777
2737
  //#endregion
1778
2738
  //#region src/specification/facets/website/serve.adapter.d.ts
1779
- /** Options for a local server started by the framework. */
1780
- type ServeOptions = {
1781
- /** Shell command that starts the site. Receives the chosen port as `PORT`. */
2739
+ /**
2740
+ * The ONE shape an external process takes — the site under test, a backend a
2741
+ * page talks to, a bundler a simulator loads from. Built by `process()`
2742
+ * (chapter 11) and accepted wherever a facet starts something outside this
2743
+ * process: `website({ server })`, `services: { api: process(…) }`, and the
2744
+ * literate `serve:` registry.
2745
+ */
2746
+ type ProcessOptions = {
2747
+ /**
2748
+ * A one-shot command run ONCE per specification, before the process is
2749
+ * spawned, which must exit 0 — a build, a migration, a fixture load. Its
2750
+ * failure is the specification's, and it says so.
2751
+ */
2752
+ before?: string;
2753
+ /** Shell command that starts the process. Receives the chosen port as `PORT`. */
1782
2754
  command: string;
2755
+ /** Working directory, relative to the project root. Default: the root itself. */
2756
+ cwd?: string;
2757
+ /**
2758
+ * Environment for the child, on top of the runner's own. A function
2759
+ * receives the services already started beside this one, so a process can
2760
+ * be handed a sibling's connection string.
2761
+ */
2762
+ env?: ((services: Record<string, {
2763
+ connectionString: string;
2764
+ }>) => Record<string, string>) | Record<string, string>;
1783
2765
  /** Fixed port. Default: an OS-assigned free port, injected as `PORT`. */
1784
2766
  port?: number;
1785
2767
  /**
@@ -1797,8 +2779,96 @@ type ServeOptions = {
1797
2779
  /** Readiness budget in milliseconds. Default 30 000. */
1798
2780
  timeout?: number;
1799
2781
  };
2782
+ /**
2783
+ * What `ProcessOptions` was called in 15.2, when the only process the
2784
+ * framework owned was a website's server.
2785
+ *
2786
+ * @deprecated Renamed to {@link ProcessOptions} in 15.3 — the shape is the
2787
+ * one external process every facet starts, not a website's alone. The alias
2788
+ * is removed in 16.0.
2789
+ */
2790
+ type ServeOptions = ProcessOptions;
2791
+ //#endregion
2792
+ //#region src/specification/facets/_common/process.d.ts
2793
+ /**
2794
+ * An external process, declared like any other service.
2795
+ *
2796
+ * Before this there were three shapes for the same thing: `website({ server })`
2797
+ * took a `ServeOptions`, a literate document took a `serve:` entry, and a
2798
+ * project that needed a second process — an API behind the site, Metro behind
2799
+ * the simulator — started one by hand in a `beforeAll` and killed it in an
2800
+ * `afterAll` it sometimes forgot. `process()` is the one shape, and the
2801
+ * framework owns the lifetime.
2802
+ *
2803
+ * It sits in a `services` record beside `postgres()`, `redis()` and
2804
+ * `sqlite()`, so it starts after them and can be handed their connection
2805
+ * strings through `env`, and it is stopped with the specification.
2806
+ */
2807
+ declare class ProcessHandle implements ServiceHandle {
2808
+ /** Embedded: nothing to pull, nothing to run in a container. */
2809
+ readonly defaultImage = "";
2810
+ readonly defaultPort = 0;
2811
+ readonly environment: Record<string, string>;
2812
+ readonly type = "process";
2813
+ composeName: null | string;
2814
+ connectionString: string;
2815
+ started: boolean;
2816
+ private adapter;
2817
+ private readonly options;
2818
+ constructor(options: ProcessOptions);
2819
+ buildConnectionString(host: string, port: number): string;
2820
+ createDatabaseAdapter(): DatabasePort | null;
2821
+ healthcheck(): Promise<void>;
2822
+ /**
2823
+ * A process is not a container, so the orchestrator never starts it: the
2824
+ * facet does, once its siblings are up and their connection strings are
2825
+ * readable ({@link startProcessServices}).
2826
+ */
2827
+ initialize(): Promise<void>;
2828
+ /**
2829
+ * Isolation is the RUN's, not the worker's — and a run here is one
2830
+ * EVALUATION of the specification module. Under vitest's default
2831
+ * isolation that is once per test file, so two files that import the same
2832
+ * specification get a child each, with the id the facet minted for it.
2833
+ * Nothing is acquired or reset between tests: the id is what tells two
2834
+ * runs apart, never a label a spec samples.
2835
+ */
2836
+ isolation(): IsolationStrategy;
2837
+ reset(): Promise<void>;
2838
+ /**
2839
+ * Spawn it and wait until it answers. `services` is every handle declared
2840
+ * beside this one, already started — what an `env` function reads.
2841
+ *
2842
+ * @internal
2843
+ */
2844
+ spawnWith(root: string, services: Record<string, {
2845
+ connectionString: string;
2846
+ }>, runId: string): Promise<void>;
2847
+ /** Terminate the process group. Idempotent. */
2848
+ shutdown(): Promise<void>;
2849
+ /** What it was declared as — what a facet reads to start it in a slot of its own. */
2850
+ get spec(): ProcessOptions;
2851
+ /** The base URL it came up on — known only once it is started. */
2852
+ get url(): string;
2853
+ }
2854
+ /**
2855
+ * Declare an external process the framework owns for the life of the
2856
+ * specification.
2857
+ *
2858
+ * @example
2859
+ * const { website, cleanup } = await specification.website({
2860
+ * services: { api: process({ command: 'bin/server web', ready: '/health' }) },
2861
+ * server: ({ api }) => process({
2862
+ * command: 'next dev',
2863
+ * env: { NEXT_PUBLIC_API_URL: api.connectionString },
2864
+ * }),
2865
+ * });
2866
+ */
2867
+ declare function processService(options: ProcessOptions): ProcessHandle;
1800
2868
  //#endregion
1801
2869
  //#region src/specification/facets/website/start-website.d.ts
2870
+ /** What `server` may be handed as, and what it resolves to. */
2871
+ type ServerSpec<Services extends ServiceRecord> = ((services: Services) => ProcessHandle | ProcessOptions) | ProcessHandle | ProcessOptions;
1802
2872
  /**
1803
2873
  * The declared stub backend behind the site under test — started before the
1804
2874
  * server command, torn down with the runner. Its URL is injected into the
@@ -1819,7 +2889,7 @@ type WebsiteBackendOptions = {
1819
2889
  * mode for the same reason: a deployed site cannot be pointed at a local
1820
2890
  * stub.
1821
2891
  */
1822
- type WebsiteSpecificationOptions = {
2892
+ type WebsiteSpecificationOptions<Services extends ServiceRecord = ServiceRecord> = {
1823
2893
  /**
1824
2894
  * Cross-origin request policy for visits. Default: `'block'` with a
1825
2895
  * local `server` (deterministic — analytics and CDNs never leave the
@@ -1831,6 +2901,14 @@ type WebsiteSpecificationOptions = {
1831
2901
  * `server` command. Auto-discovered from the calling file when absent.
1832
2902
  */
1833
2903
  root?: string;
2904
+ /**
2905
+ * Named services started with the runner, before the site is: a database
2906
+ * the site reads, a `process()` backend it calls. They are started in
2907
+ * declaration order and stopped with the specification, and `server` may
2908
+ * be a function of them — which is how a site is handed the URL of the
2909
+ * API it was started beside.
2910
+ */
2911
+ services?: Services;
1834
2912
  } & ({
1835
2913
  /**
1836
2914
  * Declared stub backend: started BEFORE the server command, its
@@ -1839,10 +2917,11 @@ type WebsiteSpecificationOptions = {
1839
2917
  */
1840
2918
  backend?: WebsiteBackendOptions;
1841
2919
  /**
1842
- * Start the site locally: a shell command receiving a free port
1843
- * as `PORT`, polled on `ready` (default `/`) until it answers.
2920
+ * Start the site locally: a `process()` — a shell command receiving
2921
+ * a free port as `PORT`, polled on `ready` (default `/`) until it
2922
+ * answers — or a function of the started services returning one.
1844
2923
  */
1845
- server: ServeOptions;
2924
+ server: ServerSpec<Services>;
1846
2925
  url?: never;
1847
2926
  } | {
1848
2927
  backend?: never;
@@ -1863,11 +2942,11 @@ type WebsiteHandle = {
1863
2942
  url: string;
1864
2943
  website: WebsiteSpecification;
1865
2944
  };
1866
- declare function startWebsite(options: WebsiteSpecificationOptions): Promise<WebsiteHandle>;
2945
+ declare function startWebsite<Services extends ServiceRecord>(options: WebsiteSpecificationOptions<Services>): Promise<WebsiteHandle>;
1867
2946
  //#endregion
1868
2947
  //#region src/specification/facets/_common/specification.d.ts
1869
2948
  /**
1870
- * The five specification constructors (CONVENTIONS A2) — created in a
2949
+ * The six specification constructors (CONVENTIONS A2) — created in a
1871
2950
  * `*.specification.ts` file under `specs/`, destructured with canonical
1872
2951
  * names, and cleaned up via `afterAll(cleanup)` (A1/A3/A4).
1873
2952
  *
@@ -1890,16 +2969,21 @@ declare function startWebsite(options: WebsiteSpecificationOptions): Promise<Web
1890
2969
  * export const { cli, cleanup } = await specification.cli('my-cli');
1891
2970
  * afterAll(cleanup);
1892
2971
  */
1893
- /** The five constructors, and only five — the framework's whole entry surface. */
2972
+ /** The six constructors, and only six — the framework's whole entry surface. */
1894
2973
  type Specification = {
1895
2974
  api: typeof startApi;
1896
2975
  cli: typeof startCli;
2976
+ integration: typeof startIntegration;
1897
2977
  jobs: typeof startJobs;
1898
2978
  mobile: typeof startMobile;
1899
2979
  website: typeof startWebsite;
1900
2980
  };
1901
2981
  declare const specification: Specification;
1902
2982
  //#endregion
2983
+ //#region src/specification/facets/component/component.node.d.ts
2984
+ /** Present, typed, and refusing — every setup and the terminal action alike. */
2985
+ declare const component: ComponentChain;
2986
+ //#endregion
1903
2987
  //#region src/specification/literate/spec-document.d.ts
1904
2988
  /**
1905
2989
  * The facets a document may describe. `cli` is the only one implemented; the
@@ -1988,93 +3072,51 @@ declare function inspectContainer(id: string): unknown;
1988
3072
  /** Force-remove the given container IDs in a single call. Errors are swallowed. */
1989
3073
  declare function removeContainers(ids: string[]): void;
1990
3074
  //#endregion
1991
- //#region src/specification/ports/container.port.d.ts
1992
- /**
1993
- * Abstract container interface.
1994
- * Represents a running service (database, cache, etc.)
1995
- */
1996
- type ContainerPort = {
1997
- /** Start the container and wait until ready. */
1998
- start: () => Promise<void>;
1999
- /** Stop and remove the container. */
2000
- stop: () => Promise<void>;
2001
- /** Get the mapped host port for a container port. */
2002
- getMappedPort: (containerPort: number) => number;
2003
- /** Get the host to connect to. */
2004
- getHost: () => string;
2005
- /** Get a full connection string for this service. */
2006
- getConnectionString: () => string;
2007
- /** Get container logs (stdout + stderr). */
2008
- getLogs: () => Promise<string>;
2009
- };
2010
- //#endregion
2011
- //#region src/specification/facets/website/elements.d.ts
2012
- /**
2013
- * The element vocabulary — user-facing descriptors for visit scenarios.
2014
- * Reads like English (`click(link('Articles'))`), translates to
2015
- * accessibility-first locators in the browser integration. CSS/XPath is
2016
- * deliberately not expressible; `testId()` is the single escape hatch.
2017
- *
2018
- * A descriptor must designate exactly ONE element (CONVENTIONS W3). Two knobs
2019
- * narrow it, in this order of preference:
2020
- *
2021
- * 1. `within(scope, target)` — search inside a landmark, the way a person
2022
- * would say "the Articles link *in the nav*";
2023
- * 2. `{ exact: true }` — match the accessible name whole rather than as a
2024
- * substring, when two names genuinely overlap.
2025
- */
2026
- /** Options accepted by every named descriptor. */
2027
- type ElementOptions = {
2028
- /**
2029
- * Match the accessible name as a whole string. Default is substring —
2030
- * `link('Articles')` also matches "Read Articles".
2031
- */
2032
- exact?: boolean;
2033
- };
2034
- /** A user-facing element factory — what every name in this module is. */
2035
- type ElementFactory = (name: string, options?: ElementOptions) => ElementRef;
2036
- /** A button (or element with the button role), by accessible name. */
2037
- declare const button: ElementFactory;
2038
- /** A form field, by label. */
2039
- declare const field: ElementFactory;
2040
- /** A heading, by accessible name. */
2041
- declare const heading: ElementFactory;
2042
- /** A link, by accessible name. */
2043
- declare const link: ElementFactory;
2044
- /** An element containing the given text. */
2045
- declare const content: ElementFactory;
2046
- /** The escape hatch: an element by `data-testid`. Prefer user-facing elements. */
2047
- declare const testId: (id: string) => ElementRef;
2048
- /** A landmark factory — the optionally-named containers `within()` accepts. */
2049
- type LandmarkFactory = (name?: string, options?: ElementOptions) => ElementRef;
2050
- /** The `banner` landmark — the page header. */
2051
- declare const banner: LandmarkFactory;
2052
- /** The `complementary` landmark — an `<aside>`, a sidebar. */
2053
- declare const complementary: LandmarkFactory;
2054
- /** The `contentinfo` landmark — the page footer. */
2055
- declare const contentinfo: LandmarkFactory;
2056
- /** The `form` landmark — a form carrying an accessible name. */
2057
- declare const form: LandmarkFactory;
2058
- /** The `main` landmark — the primary content of the document. */
2059
- declare const main: LandmarkFactory;
2060
- /** The `navigation` landmark — a `<nav>`. Name it when a page has several. */
2061
- declare const navigation: LandmarkFactory;
2062
- /** The `region` landmark — a `<section>` carrying an accessible name. */
2063
- declare const region: LandmarkFactory;
2064
- /** The `search` landmark. */
2065
- declare const search: LandmarkFactory;
2066
- /**
2067
- * Restrict a descriptor to the inside of another — the answer to ambiguity,
2068
- * and the one the framework prefers over a test id.
3075
+ //#region src/specification/facets/_common/result/text-subject.d.ts
3076
+ /**
3077
+ * Wrap an arbitrary string into a {@link TextAccessor} anchored on the calling
3078
+ * test's directory — the same caller-detection the builders use.
2069
3079
  *
2070
- * click(within(navigation(), link('Articles')))
3080
+ * The product surface of a test framework is its own error messages, checker
3081
+ * output, and reports; those deserve the same goldening as any other output.
3082
+ * `text()` makes an ad-hoc string a first-class snapshot subject:
2071
3083
  *
2072
- * Composes outside-in: the scope may itself be scoped, so a deeply nested
2073
- * target reads `within(main(), within(region('Series'), link('Part 2')))`.
2074
- * Any descriptor works as a scope, including `testId()` when a container has
2075
- * no landmark role to stand on.
3084
+ * ```typescript
3085
+ * const message = await catchMessage(() => expect(result.response).toMatch('wrong-body.http'));
3086
+ * expect(text(message)).toMatch('wrong-body-error.txt'); // resolves to _expected/
3087
+ * ```
3088
+ *
3089
+ * ANSI is stripped before every comparison (the raw form stays on `.text`),
3090
+ * the `{{token}}` grammar applies to the fixture, and `.grep()` composition
3091
+ * works exactly as on any stream accessor.
3092
+ *
3093
+ * The ANCHOR is why this sits apart from the accessor it builds: reading the
3094
+ * caller's frame means reading a stack and a real path, which is node's alone.
3095
+ * {@link TextAccessor} itself is a pure projection over a captured string, so
3096
+ * it loads in a page — and the browser entry builds its own `text()`, where
3097
+ * the golden commands resolve `_expected/` from the test's path server-side.
2076
3098
  */
2077
- declare const within: (scope: ElementRef, target: ElementRef) => ElementRef;
3099
+ declare function text(value: string): TextAccessor;
3100
+ //#endregion
3101
+ //#region src/specification/ports/container.port.d.ts
3102
+ /**
3103
+ * Abstract container interface.
3104
+ * Represents a running service (database, cache, etc.)
3105
+ */
3106
+ type ContainerPort = {
3107
+ /** Start the container and wait until ready. */
3108
+ start: () => Promise<void>;
3109
+ /** Stop and remove the container. */
3110
+ stop: () => Promise<void>;
3111
+ /** Get the mapped host port for a container port. */
3112
+ getMappedPort: (containerPort: number) => number;
3113
+ /** Get the host to connect to. */
3114
+ getHost: () => string;
3115
+ /** Get a full connection string for this service. */
3116
+ getConnectionString: () => string;
3117
+ /** Get container logs (stdout + stderr). */
3118
+ getLogs: () => Promise<string>;
3119
+ };
2078
3120
  //#endregion
2079
3121
  //#region src/integrations/postgres/postgres.d.ts
2080
3122
  type PostgresOptions = {
@@ -2240,228 +3282,11 @@ declare class SqliteHandle implements DatabasePort, ServiceHandle {
2240
3282
  */
2241
3283
  declare function sqlite(options?: SqliteOptions): SqliteHandle;
2242
3284
  //#endregion
2243
- //#region src/specification/contracts/filters.d.ts
2244
- /**
2245
- * A text filter on a provider request builder (`openai.chat({ user })`,
2246
- * `anthropic.messages({ system })`, …).
2247
- *
2248
- * A **string is EXACT**. That is deliberate: a substring filter silently
2249
- * cross-matches — two prompts sharing a preamble both satisfy the first
2250
- * contract, and the spec goes green on the wrong reply. Looser matching is
2251
- * explicit, and says which looseness it means:
2252
- *
2253
- * - a `RegExp` — pattern matching;
2254
- * - `match.includes('…')` — containment, the code-only matcher (it never joins
2255
- * the `{{token}}` file vocabulary, CONVENTIONS D4);
2256
- * - any other `match.*` matcher, evaluated by the same structural engine the
2257
- * assertions use.
2258
- */
2259
- type TextFilter = Matcher | RegExp | string;
2260
- //#endregion
2261
- //#region src/integrations/anthropic/anthropic.d.ts
2262
- type AnthropicMessagesFilter = {
2263
- model?: TextFilter;
2264
- system?: TextFilter;
2265
- user?: TextFilter;
2266
- tools?: string[];
2267
- };
2268
- /**
2269
- * Anthropic API intercept helpers.
2270
- */
2271
- declare const anthropic: {
2272
- /**
2273
- * Request: match Messages API calls, optionally routed through a
2274
- * custom gateway URL. When used with a JSON fixture file, the data is
2275
- * returned as-is (no wrapping) because Anthropic fixtures are typically
2276
- * already in the Messages API response shape.
2277
- *
2278
- * @example
2279
- * anthropic.messages()
2280
- * anthropic.messages({ system: /classify/ })
2281
- * anthropic.messages({ user: buildPrompt() }) // string = EXACT equality
2282
- * anthropic.messages({ user: /classify/ }, GATEWAY)
2283
- */
2284
- messages(filter?: AnthropicMessagesFilter, url?: string): ContractRequest;
2285
- /** Response: wrap data in Anthropic messages format. */
2286
- reply(data: unknown): ContractResponse;
2287
- /** Response: return an Anthropic error. */
2288
- error(status: number, message?: string): ContractResponse;
2289
- /** Response: simulate a timeout. */
2290
- timeout(): ContractResponse;
2291
- };
2292
- //#endregion
2293
- //#region src/specification/contracts/http.d.ts
2294
- /**
2295
- * Request filters for the generic HTTP provider. Every field is a subset
2296
- * constraint — a request matches when all provided fields match.
2297
- */
2298
- type HttpContractFilter = {
2299
- /**
2300
- * Body constraint. An object is a deep SUBSET match (toMatchObject-style)
2301
- * whose leaf values may be `match.*` matchers; a string is a containment
2302
- * test and a RegExp a `test()` over the raw text body.
2303
- */
2304
- body?: object | RegExp | string;
2305
- /** Header subset. Names are case-insensitive; string = exact value, RegExp = `test()`. */
2306
- headers?: Record<string, RegExp | string>;
2307
- /** Query-param subset. string = exact value, RegExp = `test()`. */
2308
- query?: Record<string, RegExp | string>;
2309
- };
2310
- /** Init options shared by the response builders. */
2311
- type HttpResponseInit = {
2312
- /** Delay in ms before responding (for timeout testing). */
2313
- delay?: number;
2314
- /** Response headers, merged over the builder's own. */
2315
- headers?: Record<string, string>;
2316
- /** HTTP status code. */
2317
- status?: number;
2318
- };
2319
- /**
2320
- * Generic HTTP contract helpers for any URL. The url is absolute (string or
2321
- * RegExp), or a PATH FORM starting with `/` — `http.get('/articles/{{uuid}}')`
2322
- * matches that path on ANY origin, which is what an app calling its own
2323
- * backend needs. An optional {@link HttpContractFilter} narrows matching by
2324
- * body, headers, or query — a request that hits the URL/method but fails the
2325
- * filter counts as unmatched (strict contracts, CONVENTIONS D7).
2326
- *
2327
- * @example
2328
- * defineContract({ request: http.get('/articles/{{uuid}}'), response: http.json(article) })
2329
- * defineContract({ request: http.post(URL, { body: { user: 'alice' } }), response: http.empty() })
2330
- */
2331
- declare const http: {
2332
- any(url: RegExp | string, filter?: HttpContractFilter): ContractRequest;
2333
- delete(url: RegExp | string, filter?: HttpContractFilter): ContractRequest;
2334
- get(url: RegExp | string, filter?: HttpContractFilter): ContractRequest;
2335
- patch(url: RegExp | string, filter?: HttpContractFilter): ContractRequest;
2336
- post(url: RegExp | string, filter?: HttpContractFilter): ContractRequest;
2337
- put(url: RegExp | string, filter?: HttpContractFilter): ContractRequest;
2338
- /** Response: a body-less reply (204 by default). */
2339
- empty(status?: number): ContractResponse;
2340
- /** Response: an error status. Without a body, `{ error: 'HTTP <status>' }`. */
2341
- error(status: number, body?: unknown): ContractResponse;
2342
- /** Response: a JSON body (200 by default). */
2343
- json(body: unknown, init?: HttpResponseInit): ContractResponse;
2344
- /** Response: a text body, served as `text/plain` (200 by default). */
2345
- text(body: string, init?: HttpResponseInit): ContractResponse;
2346
- };
2347
- //#endregion
2348
- //#region src/integrations/openai/openai.d.ts
2349
- type OpenAIChatFilter = {
2350
- model?: TextFilter;
2351
- system?: TextFilter;
2352
- user?: TextFilter;
2353
- tools?: string[];
2354
- temperature?: number;
2355
- };
2356
- type OpenAIResponsesFilter = {
2357
- model?: TextFilter;
2358
- system?: TextFilter;
2359
- user?: TextFilter;
2360
- tools?: string[];
2361
- };
2362
- /**
2363
- * OpenAI API intercept helpers.
2364
- */
2365
- declare const openai: {
2366
- /**
2367
- * Request: match Chat Completions API calls. STRING filters mean EXACT
2368
- * equality (pass the app's own prompt builder); loosen deliberately with a
2369
- * RegExp or `match.includes(...)`.
2370
- *
2371
- * @example
2372
- * openai.chat() // any chat call
2373
- * openai.chat({ model: 'gpt-4o' }) // exact model
2374
- * openai.chat({ system: buildPrompt() }) // exact system prompt
2375
- * openai.chat({ system: /classify/ }) // pattern
2376
- */
2377
- chat(filter?: OpenAIChatFilter): ContractRequest;
2378
- /**
2379
- * Request: match Responses API calls (AI SDK v5+) with auto-wrapping.
2380
- * String filters mean EXACT equality (see {@link openai.chat}).
2381
- * When used with a JSON file, the data is automatically wrapped in the
2382
- * Responses API envelope.
2383
- *
2384
- * @param filter - Optional body filters.
2385
- * @param url - Custom gateway URL (default: api.openai.com).
2386
- *
2387
- * @example
2388
- * openai.responses({ user: /Report Ingestion/ }, GATEWAY)
2389
- */
2390
- responses(filter?: OpenAIResponsesFilter, url?: string): ContractRequest;
2391
- /**
2392
- * Response: wrap data in Chat Completions format.
2393
- *
2394
- * @example
2395
- * openai.reply({ categories: ['TECH'] })
2396
- */
2397
- reply(data: unknown): ContractResponse;
2398
- /** Response: return an OpenAI error. */
2399
- error(status: number, message?: string): ContractResponse;
2400
- /** Response: return malformed content. */
2401
- malformed(content: string): ContractResponse;
2402
- /** Response: simulate a timeout. */
2403
- timeout(): ContractResponse;
2404
- };
2405
- //#endregion
2406
- //#region src/vitest/mock-of.d.ts
2407
- /** Factory signature that creates a deep mock proxy for any interface. */
2408
- type MockPort = <T>() => DeepMockProxy<T>;
2409
- /**
2410
- * Create a deep mock proxy for a given type.
2411
- * Wraps `vitest-mock-extended`'s `mockDeep` for convenient port mocking.
2412
- */
2413
- declare const mockOf: MockPort;
2414
- //#endregion
2415
- //#region src/vitest/mock-of-date.d.ts
2416
- /** Interface for freezing and resetting the global Date in tests. */
2417
- type MockDatePort = {
2418
- /** Restore the real Date object. */
2419
- reset: () => void;
2420
- /** Freeze `Date.now()` and `new Date()` to the given value. */
2421
- set: (date: Date | number | string) => void;
2422
- };
3285
+ //#region src/index.d.ts
2423
3286
  /**
2424
- * Freeze or reset the global Date for deterministic time-dependent tests.
2425
- * Wraps the `mockdate` package.
3287
+ * The module-scope network double, on msw's node server — what a test with no
3288
+ * chain to hang contracts on reaches for (chapter 10).
2426
3289
  */
2427
- declare const mockOfDate: MockDatePort;
2428
- //#endregion
2429
- //#region src/index.d.ts
2430
- declare module 'vitest' {
2431
- interface Assertion<T = any> {
2432
- /**
2433
- * Assert the subject is empty — zero rows for a table (async), an
2434
- * empty stream for a text accessor (console, errors, stdout).
2435
- */
2436
- toBeEmpty: T extends TableAccessor ? () => Promise<void> : T extends {
2437
- readonly comparableText: string;
2438
- } ? () => Promise<void> : never;
2439
- /** Assert the container is running. Async — docker-backed subject. */
2440
- toBeRunning: T extends ContainerAccessor ? () => Promise<void> : never;
2441
- /**
2442
- * On `@jterrazz/test` accessors: assert the subject matches a fixture
2443
- * file under `_expected/<name>` (flat — a slash creates a subfolder;
2444
- * `.http` format for `result.response`). Async for filesystem/directory
2445
- * subjects (tree compare on disk). Other subjects keep vitest-native
2446
- * `toMatch` semantics (string substring / regexp).
2447
- *
2448
- * Pass `{ frozen: true }` to opt a single fixture OUT of update-mode
2449
- * rewriting: a frozen fixture is never overwritten under `TEST_UPDATE=1`
2450
- * (or vitest `-u`), and a frozen mismatch/missing fixture still throws.
2451
- * Use it for a deliberately-wrong fixture whose diff/error rendering is
2452
- * the behaviour under test.
2453
- */
2454
- toMatch: T extends DirectoryAccessor | FilesystemAccessor ? (name: RegExp | string, options?: MatchFixtureOptions) => Promise<void> : T extends JsonAccessor | ResponseAccessor | TextAccessor ? (name: RegExp | string, options?: MatchFixtureOptions) => void : (expected: RegExp | string, options?: MatchFixtureOptions) => void;
2455
- /**
2456
- * Assert the table contains exactly the given rows for the given
2457
- * columns. Cells accept `match.*` dynamic-value matchers. Async —
2458
- * queries the database.
2459
- */
2460
- toMatchRows: T extends TableAccessor ? (expected: {
2461
- columns: string[];
2462
- rows: readonly (readonly unknown[])[];
2463
- }) => Promise<void> : never;
2464
- }
2465
- }
3290
+ declare const intercept: Intercept;
2466
3291
  //#endregion
2467
- export { type ApiHandle, type ApiSpecification, type ApiSpecificationOptions, BaseResult, type BrowserConsoleMessage, type BrowserLinkElement, type BrowserMetaElement, type BrowserOpenOptions, type BrowserPage, type BrowserPort, type CaptureScope, type CliEnv, type CliHandle, type CliInput, type CliOutput, type CliPort, CliResult, type CliSpecification, type CliSpecificationOptions, ContainerAccessor, type ContainerPort, type Contract, type ContractInput, type ContractRequest, type ContractResponder, type ContractResponse, type ContractResponseValue, type Contracts, type DatabaseKeys, type DatabasePort, type DeviceOpenOptions, type DevicePort, type DeviceScreen, type DeviceTimeouts, DirectoryAccessor, type DockerSpecConfig, type ElementKind, type ElementMatch, type ElementOptions, type ElementRef, type ExecOptions, FetchResult, type FileAccessor, FilesystemAccessor, type HonoApp, type HttpContractFilter, type HttpResponseInit, HttpResult, type IsolationStrategy, type JobHandle, type JobsHandle, type JobsSpecification, type JobsSpecificationOptions, JsonAccessor, type LandmarkKind, type LiterateRunFlags, type LiterateServeRegistration, type MatchFixtureOptions, type MatchableRequest, Matcher, type MatcherKind, type MobileBackendOptions, type MobileElementKind, type MobileElementMatch, type MobileElementRef, type MobileHandle, type MobileScenario, type MobileSpecification, type MobileSpecificationOptions, type MobileVisitor, type MockDatePort, type MockPort, Orchestrator, PageResult, type PostgresOptions, type RedisOptions, ResponseAccessor, type ScreenNode, ScreenResult, type ServeOptions, type ServerPort, type ServerResponse, type ServiceHandle, type ServiceRecord, type SpecDocument, type SpecEnvToken, type SpecFileAssertion, type SpecFixture, type SpecKind, type SpecRun, type SpecServeEntry, type SpecStream, type SpecificationConfig, type SpecificationMode, type SqliteOptions, TableAccessor, TextAccessor, type TextFilter, type VisitScenario, type Visitor, type WebsiteBackendOptions, type WebsiteHandle, type WebsiteSpecification, type WebsiteSpecificationOptions, anthropic, banner, button, complementary, content, contentinfo, defineContract, defineContracts, field, findContainersByLabel, form, heading, http, inspectContainer, link, main, match, mockOf, mockOfDate, navigation, openai, postgres, redis, region, removeContainers, search, specification, sqlite, testId, text, within };
3292
+ export { type ApiHandle, type ApiSpecification, type ApiSpecificationOptions, BaseResult, type BrowserConsoleMessage, type BrowserLinkElement, type BrowserMetaElement, type BrowserOpenOptions, type BrowserPage, type BrowserPort, CallResult, type CaptureScope, type CliEnv, type CliHandle, type CliInput, type CliOutput, type CliPort, CliResult, type CliSpecification, type CliSpecificationOptions, type ComponentChain, type ComponentScenario, type ComponentUi, type ComponentVisitor, ContainerAccessor, type ContainerPort, type Contract, type ContractInput, type ContractRequest, type ContractResponder, type ContractResponse, type ContractResponseValue, type Contracts, type DatabaseKeys, type DatabasePort, type DeviceOpenOptions, type DevicePort, type DeviceScreen, type DeviceTimeouts, DirectoryAccessor, type DockerSpecConfig, type DomMount, type ElementKind, type ElementMatch, type ElementOptions, type ElementRef, type ExecOptions, FetchResult, type FileAccessor, FilesystemAccessor, type HonoApp, type HttpContractFilter, type HttpResponseInit, HttpResult, type HttpStreamInit, type IntegrationHandle, type IntegrationSpecification, type IntegrationSpecificationOptions, type Intercept, type InterceptScope, type IsolationStrategy, type JobHandle, type JobsHandle, type JobsSpecification, type JobsSpecificationOptions, JsonAccessor, type LandmarkKind, type LiterateRunFlags, type LiterateServeRegistration, type MatchFixtureOptions, type MatchableRequest, Matcher, type MatcherKind, type MobileBackendOptions, type MobileElementKind, type MobileElementMatch, type MobileElementRef, type MobileHandle, type MobileScenario, type MobileSpecification, type MobileSpecificationOptions, type MobileVisitor, type MockDatePort, type MockOfOptions, type MockPort, Orchestrator, PageResult, type PinnedClock, type PostgresOptions, ProcessHandle, type ProcessOptions, type RedisOptions, type RenderResult, type RenderSubject, type RenderedText, ResponseAccessor, type ScreenNode, ScreenResult, type ServeOptions, type ServerPort, type ServerResponse, type ServerSpec, type ServiceHandle, type ServiceRecord, type SpecDocument, type SpecEnvToken, type SpecFileAssertion, type SpecFixture, type SpecKind, type SpecRun, type SpecServeEntry, type SpecStream, type SpecificationConfig, type SpecificationMode, type SqliteOptions, type SseEvent, type StreamBody, TableAccessor, TextAccessor, type TextFilter, type VisitScenario, type Visitor, type WaitUntilOptions, type WebsiteBackendOptions, type WebsiteHandle, type WebsiteSpecification, type WebsiteSpecificationOptions, anthropic, banner, button, clock, complementary, component, content, contentinfo, defineContract, defineContracts, dialog, disabled, enabled, field, findContainersByLabel, focused, form, heading, http, inspectContainer, intercept, link, listitem, main, match, mockOf, mockOfDate, navigation, openai, option, postgres, processService as process, redis, region, removeContainers, required, row, search, selected, specification, sqlite, status, table, testId, text, valued, waitUntil, within };