@jterrazz/test 5.3.1 → 6.0.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,58 +1,16 @@
1
- import { DeepMockProxy } from "vitest-mock-extended";
1
+ import { a as ServiceHandle, i as postgres, n as redis, o as IsolationStrategy, r as PostgresOptions, s as DatabasePort, t as RedisOptions } from "./redis.adapter.js";
2
+ import { i as mockOfDate, n as mockOf, r as MockDatePort, t as MockPort } from "./mock-of.js";
2
3
 
3
- //#region src/ports/database.port.d.ts
4
- /**
5
- * Abstract database interface for specification runners.
6
- * Implement this to plug in your database stack.
7
- */
8
- interface DatabasePort {
9
- /** Execute raw SQL (for seeding test data). */
10
- seed(sql: string): Promise<void>;
11
- /** Query a table and return rows as arrays of values. */
12
- query(table: string, columns: string[]): Promise<unknown[][]>;
13
- /** Reset database to clean state between tests. */
14
- reset(): Promise<void>;
15
- }
16
- //#endregion
17
- //#region src/ports/service.port.d.ts
18
- /**
19
- * A service handle — returned by factory functions like postgres(), redis().
20
- * Mutable: connectionString is populated after the orchestrator starts containers.
21
- */
22
- interface ServiceHandle {
23
- /** Service type identifier. */
24
- readonly type: string;
25
- /** Compose service name (if linked). */
26
- readonly composeName: null | string;
27
- /** Default container port for this service type. */
28
- readonly defaultPort: number;
29
- /** Default Docker image for this service type. */
30
- readonly defaultImage: string;
31
- /** Environment variables to pass to the container. */
32
- readonly environment: Record<string, string>;
33
- /** Connection string — populated after start. */
34
- connectionString: string;
35
- /** Whether this service has been started. */
36
- started: boolean;
37
- /** Build the connection string from host and port. */
38
- buildConnectionString(host: string, port: number): string;
39
- /** Create a DatabasePort adapter (if this is a database). Returns null otherwise. */
40
- createDatabaseAdapter(): DatabasePort | null;
41
- /** Verify the service is ready and accepting connections. Throws with context if not. */
42
- healthcheck(): Promise<void>;
43
- /** Run initialization scripts (e.g., init.sql). Throws with SQL error context if it fails. */
44
- initialize(composeDir: string): Promise<void>;
45
- /** Reset state between tests (truncate tables, flush cache, etc.) */
46
- reset(): Promise<void>;
47
- }
48
- //#endregion
49
4
  //#region src/ports/command.port.d.ts
50
5
  /**
51
- * Result of executing a CLI command.
6
+ * Result of executing a CLI command, including exit code and captured output streams.
52
7
  */
53
8
  interface CommandResult {
9
+ /** Process exit code (0 = success). */
54
10
  exitCode: number;
11
+ /** Captured standard output. */
55
12
  stdout: string;
13
+ /** Captured standard error. */
56
14
  stderr: string;
57
15
  }
58
16
  /**
@@ -82,19 +40,22 @@ interface CommandPort {
82
40
  //#endregion
83
41
  //#region src/ports/server.port.d.ts
84
42
  /**
85
- * HTTP response returned by a server port.
43
+ * HTTP response returned by a server port, with parsed JSON body.
86
44
  */
87
45
  interface ServerResponse {
46
+ /** HTTP status code. */
88
47
  status: number;
48
+ /** Parsed JSON response body, or null if parsing failed. */
89
49
  body: unknown;
50
+ /** Response headers as a flat key-value map. */
90
51
  headers: Record<string, string>;
91
52
  }
92
53
  /**
93
54
  * Abstract server interface for specification runners.
94
- * Integration mode uses in-process app, E2E mode uses real HTTP.
55
+ * Integration mode uses an in-process Hono app; E2E mode uses real HTTP via fetch.
95
56
  */
96
57
  interface ServerPort {
97
- /** Send an HTTP request and return the response. */
58
+ /** Send an HTTP request and return the parsed response. */
98
59
  request(method: string, path: string, body?: unknown): Promise<ServerResponse>;
99
60
  }
100
61
  //#endregion
@@ -108,6 +69,10 @@ interface DirectorySnapshotOptions {
108
69
  */
109
70
  update?: boolean;
110
71
  }
72
+ /**
73
+ * Handle to a directory produced by a specification run.
74
+ * Supports snapshot-based assertions via {@link toMatchFixture} and file listing via {@link files}.
75
+ */
111
76
  declare class DirectoryAccessor {
112
77
  private absPath;
113
78
  private testDir;
@@ -128,30 +93,54 @@ declare class DirectoryAccessor {
128
93
  }
129
94
  //#endregion
130
95
  //#region src/builder/response-accessor.d.ts
96
+ /** Accessor for an HTTP response body with file-based assertion support. */
131
97
  declare class ResponseAccessor {
132
98
  readonly body: unknown;
133
99
  private testDir;
134
100
  constructor(body: unknown, testDir: string);
101
+ /**
102
+ * Assert that the response body matches the JSON in `responses/{file}`.
103
+ *
104
+ * @example
105
+ * result.response.toMatchFile("expected-items.json");
106
+ */
135
107
  toMatchFile(file: string): void;
136
108
  }
137
109
  //#endregion
138
110
  //#region src/builder/table-assertion.d.ts
111
+ /** Assertion helper for verifying database table contents after a specification run. */
139
112
  declare class TableAssertion {
140
113
  private tableName;
141
114
  private db;
142
115
  constructor(tableName: string, db: DatabasePort);
116
+ /**
117
+ * Assert that the table contains exactly the expected rows for the given columns.
118
+ *
119
+ * @example
120
+ * await result.table("users").toMatch({
121
+ * columns: ["name", "email"],
122
+ * rows: [["Alice", "alice@example.com"]],
123
+ * });
124
+ */
143
125
  toMatch(expected: {
144
126
  columns: string[];
145
127
  rows: unknown[][];
146
128
  }): Promise<void>;
129
+ /** Assert that the table has zero rows. */
147
130
  toBeEmpty(): Promise<void>;
148
131
  }
149
132
  //#endregion
150
133
  //#region src/builder/specification-result.d.ts
134
+ /** Read-only handle to a single file produced by a CLI action. */
151
135
  interface FileAccessor {
136
+ /** The UTF-8 text content. Throws if the file does not exist. */
152
137
  readonly content: string;
153
138
  readonly exists: boolean;
154
139
  }
140
+ /**
141
+ * The outcome of a single specification run.
142
+ * Provides accessors for CLI output, HTTP responses, files, directories, and database tables.
143
+ */
155
144
  declare class SpecificationResult {
156
145
  private commandResult?;
157
146
  private config;
@@ -171,13 +160,29 @@ declare class SpecificationResult {
171
160
  testDir: string;
172
161
  workDir?: string;
173
162
  });
163
+ /** The process exit code. Only available after a CLI action. */
174
164
  get exitCode(): number;
165
+ /** The HTTP response status code. Only available after an HTTP action. */
175
166
  get status(): number;
167
+ /** The captured standard output. Only available after a CLI action. */
176
168
  get stdout(): string;
169
+ /** The captured standard error. Only available after a CLI action. */
177
170
  get stderr(): string;
171
+ /**
172
+ * Extract text blocks from stdout that contain a pattern.
173
+ * Useful for parsing structured CLI output (linters, compilers).
174
+ *
175
+ * @example
176
+ * expect(result.grep('error.ts')).toContain('no-unused-vars');
177
+ */
178
+ grep(pattern: string): string;
179
+ /** Access the HTTP response body for assertions. Only available after an HTTP action. */
178
180
  get response(): ResponseAccessor;
181
+ /** Access a directory (relative to the working directory) for snapshot assertions. */
179
182
  directory(path?: string): DirectoryAccessor;
183
+ /** Access a single file (relative to the working directory) for content assertions. */
180
184
  file(path: string): FileAccessor;
185
+ /** Access a database table for row-level assertions. */
181
186
  table(tableName: string, options?: {
182
187
  service?: string;
183
188
  }): TableAssertion;
@@ -185,6 +190,7 @@ declare class SpecificationResult {
185
190
  }
186
191
  //#endregion
187
192
  //#region src/builder/specification-builder.d.ts
193
+ /** Adapter configuration passed to the specification runner at setup time. */
188
194
  interface SpecificationConfig {
189
195
  command?: CommandPort;
190
196
  database?: DatabasePort;
@@ -192,6 +198,13 @@ interface SpecificationConfig {
192
198
  fixturesRoot?: string;
193
199
  server?: ServerPort;
194
200
  }
201
+ /**
202
+ * Fluent builder for declaring a single test specification.
203
+ *
204
+ * Chain setup methods ({@link seed}, {@link fixture}, {@link env}), an action
205
+ * ({@link get}, {@link post}, {@link exec}), then call {@link run} to execute
206
+ * and receive a {@link SpecificationResult} for assertions.
207
+ */
195
208
  declare class SpecificationBuilder {
196
209
  private commandArgs;
197
210
  private commandEnv;
@@ -205,11 +218,20 @@ declare class SpecificationBuilder {
205
218
  private spawnConfig;
206
219
  private testDir;
207
220
  constructor(config: SpecificationConfig, testDir: string, label: string);
221
+ /**
222
+ * Queue a SQL seed file to run before the action.
223
+ *
224
+ * @example
225
+ * spec("creates user").seed("users.sql").exec("list-users").run();
226
+ */
208
227
  seed(file: string, options?: {
209
228
  service?: string;
210
229
  }): this;
230
+ /** Copy a file or directory from `fixtures/` into the working directory before execution. */
211
231
  fixture(file: string): this;
232
+ /** Copy an entire project fixture from `fixturesRoot` into the working directory. */
212
233
  project(name: string): this;
234
+ /** Register an MSW mock definition file from `mock/` to intercept HTTP calls. */
213
235
  mock(file: string): this;
214
236
  /**
215
237
  * Set environment variables for the CLI process. Merged on top of process.env.
@@ -222,26 +244,152 @@ declare class SpecificationBuilder {
222
244
  * spec("...").env({ HOME: "$WORKDIR", TZ: "UTC" }).exec("status").run();
223
245
  */
224
246
  env(env: CommandEnv): this;
247
+ /**
248
+ * Send a GET request to the server adapter.
249
+ *
250
+ * @example
251
+ * spec("list items").get("/api/items").run();
252
+ */
225
253
  get(path: string): this;
254
+ /**
255
+ * Send a POST request to the server adapter.
256
+ *
257
+ * @param bodyFile - Optional JSON file from `requests/` to use as the request body.
258
+ * @example
259
+ * spec("create item").post("/api/items", "new-item.json").run();
260
+ */
226
261
  post(path: string, bodyFile?: string): this;
262
+ /** Send a PUT request to the server adapter. */
227
263
  put(path: string, bodyFile?: string): this;
264
+ /** Send a DELETE request to the server adapter. */
228
265
  delete(path: string): this;
266
+ /**
267
+ * Execute a CLI command (or a sequence of commands) in an isolated working directory.
268
+ * When an array is passed, commands run sequentially and stop on the first non-zero exit code.
269
+ *
270
+ * @example
271
+ * spec("init project").exec("init --name demo").run();
272
+ * spec("multi-step").exec(["init", "build"]).run();
273
+ */
229
274
  exec(args: string | string[]): this;
275
+ /** Spawn a long-running CLI process with custom spawn options (e.g. timeout, signal). */
230
276
  spawn(args: string, options: SpawnOptions): this;
277
+ /**
278
+ * Execute the specification: run seeds, copy fixtures, then perform the
279
+ * configured action (HTTP or CLI).
280
+ *
281
+ * @returns The result object used for assertions.
282
+ * @example
283
+ * const result = await spec("test").exec("status").run();
284
+ * expect(result.exitCode).toBe(0);
285
+ */
231
286
  run(): Promise<SpecificationResult>;
232
287
  private resolveEnv;
233
288
  private prepareWorkDir;
234
289
  private runHttpAction;
235
290
  private runCliAction;
236
291
  }
292
+ /** Factory function returned by `cli()`, `integration()`, or `e2e()` that starts a new spec. */
237
293
  type SpecificationRunner = (label: string) => SpecificationBuilder;
294
+ /**
295
+ * Create a {@link SpecificationRunner} bound to the given adapter configuration.
296
+ * The test file directory is auto-detected from the call stack.
297
+ */
238
298
  declare function createSpecificationRunner(config: SpecificationConfig): SpecificationRunner;
239
299
  //#endregion
300
+ //#region src/docker/docker-port.d.ts
301
+ /** Abstract interface for interacting with a Docker container (exec, inspect, file I/O). */
302
+ interface DockerContainerPort {
303
+ /** Execute a command inside the container, return stdout */
304
+ exec(cmd: string[]): Promise<string>;
305
+ /** Read a file from inside the container */
306
+ file(path: string): Promise<{
307
+ exists: boolean;
308
+ content: string;
309
+ }>;
310
+ /** Check if container is running */
311
+ isRunning(): Promise<boolean>;
312
+ /** Get container logs */
313
+ logs(tail?: number): Promise<string>;
314
+ /** Get full docker inspect JSON */
315
+ inspect(): Promise<DockerInspectResult>;
316
+ /** Check if a file/directory exists */
317
+ exists(path: string): Promise<boolean>;
318
+ }
319
+ /** Normalized subset of `docker inspect` output for assertion use. */
320
+ interface DockerInspectResult {
321
+ id: string;
322
+ name: string;
323
+ state: {
324
+ running: boolean;
325
+ exitCode: number;
326
+ status: string;
327
+ };
328
+ config: {
329
+ image: string;
330
+ env: string[];
331
+ };
332
+ hostConfig: {
333
+ memory: number;
334
+ cpuQuota: number;
335
+ networkMode: string;
336
+ mounts: Array<{
337
+ source: string;
338
+ destination: string;
339
+ type: string;
340
+ }>;
341
+ };
342
+ networkSettings: {
343
+ networks: Record<string, {
344
+ gateway: string;
345
+ ipAddress: string;
346
+ }>;
347
+ };
348
+ }
349
+ //#endregion
350
+ //#region src/docker/docker-assertion.d.ts
351
+ /**
352
+ * Fluent assertion builder for Docker containers.
353
+ * Chain async assertions like `toBeRunning()`, `toHaveFile()`, `toHaveMount()`.
354
+ */
355
+ declare class DockerAssertion {
356
+ private container;
357
+ constructor(container: DockerContainerPort);
358
+ /** Assert the container is running */
359
+ toBeRunning(): Promise<this>;
360
+ /** Assert the container is NOT running / doesn't exist */
361
+ toNotExist(): Promise<this>;
362
+ /** Assert a file exists inside the container */
363
+ toHaveFile(path: string, opts?: {
364
+ containing?: string;
365
+ }): Promise<this>;
366
+ /** Assert a file does NOT exist */
367
+ toNotHaveFile(path: string): Promise<this>;
368
+ /** Assert a directory exists */
369
+ toHaveDirectory(path: string): Promise<this>;
370
+ /** Assert a mount exists */
371
+ toHaveMount(destination: string): Promise<this>;
372
+ /** Assert network mode */
373
+ toHaveNetwork(mode: string): Promise<this>;
374
+ /** Assert memory limit */
375
+ toHaveMemoryLimit(bytes: number): Promise<this>;
376
+ /** Assert CPU quota */
377
+ toHaveCpuQuota(quota: number): Promise<this>;
378
+ /** Execute a command and return output for custom assertions */
379
+ exec(cmd: string[]): Promise<string>;
380
+ /** Read a file for custom assertions */
381
+ readFile(path: string): Promise<string>;
382
+ /** Get logs for custom assertions */
383
+ getLogs(tail?: number): Promise<string>;
384
+ }
385
+ //#endregion
240
386
  //#region src/orchestrator/orchestrator.d.ts
241
387
  interface OrchestratorOptions {
242
388
  services: ServiceHandle[];
243
389
  mode: 'e2e' | 'integration';
244
390
  root?: string;
391
+ /** Compose project name — used for per-worker stack isolation. */
392
+ projectName?: string;
245
393
  }
246
394
  /**
247
395
  * Orchestrator for test infrastructure.
@@ -252,6 +400,7 @@ declare class Orchestrator {
252
400
  private services;
253
401
  private mode;
254
402
  private root;
403
+ private projectName;
255
404
  private running;
256
405
  private composeStack;
257
406
  private composeHandles;
@@ -290,54 +439,105 @@ declare class Orchestrator {
290
439
  getAppUrl(): null | string;
291
440
  }
292
441
  //#endregion
293
- //#region src/runner/integration.d.ts
294
- type HonoApp = {
442
+ //#region src/runner/targets.d.ts
443
+ /**
444
+ * Target factories for {@link spec}. Each target describes what is being tested
445
+ * and how the specification runner should connect to it.
446
+ */
447
+ type HonoApp$1 = {
295
448
  fetch: (...args: any[]) => any;
296
449
  request: (path: string, init?: RequestInit) => Promise<Response> | Response;
297
450
  };
298
- interface IntegrationOptions {
299
- /** Factory that returns a Hono app — called after services start. */
300
- app: () => HonoApp;
301
- /** Project root for compose detection (relative paths supported). */
302
- root?: string;
303
- /** Declared services started via testcontainers. */
304
- services: ServiceHandle[];
305
- }
306
- interface SpecificationRunnerWithCleanup extends SpecificationRunner {
307
- cleanup: () => Promise<void>;
308
- orchestrator: Orchestrator;
309
- }
451
+ /** In-process Hono app target. Created by {@link app}. */
452
+ interface AppTarget {
453
+ readonly kind: 'app';
454
+ readonly factory: () => HonoApp$1;
455
+ }
456
+ /** Docker compose stack target. Created by {@link stack}. */
457
+ interface StackTarget {
458
+ readonly kind: 'stack';
459
+ readonly root: string;
460
+ }
461
+ /** CLI command target. Created by {@link command}. */
462
+ interface CommandTarget {
463
+ readonly kind: 'command';
464
+ readonly bin: string;
465
+ }
466
+ /** Any target that produces an HTTP interface (app or stack). */
467
+ type HttpTarget = AppTarget | StackTarget;
468
+ /** Any valid spec target. */
469
+ type SpecTarget = AppTarget | CommandTarget | StackTarget;
310
470
  /**
311
- * Create an integration specification runner.
312
- * Starts infra containers via testcontainers, app runs in-process.
471
+ * Test against an in-process Hono app. Services are started via testcontainers
472
+ * and the app runs without network overhead.
473
+ *
474
+ * @param factory - Function that returns a Hono app instance (called after services start).
475
+ *
476
+ * @example
477
+ * await spec(app(() => createApp(db)), { services: [db] });
313
478
  */
314
- declare function integration(options: IntegrationOptions): Promise<SpecificationRunnerWithCleanup>;
315
- //#endregion
316
- //#region src/runner/cli.d.ts
317
- interface CliOptions {
318
- /** CLI command to run (resolved from node_modules/.bin or PATH). */
319
- command: string;
320
- /** Project root — base dir for .project() fixture lookup (relative paths supported). */
321
- root?: string;
322
- /** Optional infrastructure services (started via testcontainers). */
323
- services?: ServiceHandle[];
324
- }
479
+ declare function app(factory: () => HonoApp$1): AppTarget;
325
480
  /**
326
- * Create a CLI specification runner.
327
- * Runs CLI commands against fixture projects. Optionally starts infrastructure.
481
+ * Test against a full docker compose stack. The stack is started with
482
+ * `docker compose up` and real HTTP requests are sent to the app service.
483
+ *
484
+ * @param root - Project root containing `docker/compose.test.yaml`.
485
+ *
486
+ * @example
487
+ * await spec(stack('../../'));
328
488
  */
329
- declare function cli(options: CliOptions): Promise<SpecificationRunnerWithCleanup>;
489
+ declare function stack(root: string): StackTarget;
490
+ /**
491
+ * Test a CLI binary. Each spec runs in a fresh temp directory.
492
+ *
493
+ * @param bin - Path to the CLI binary or command name (resolved from node_modules/.bin or PATH).
494
+ *
495
+ * @example
496
+ * await spec(command('my-cli'), { root: '../fixtures' });
497
+ */
498
+ declare function command(bin: string): CommandTarget;
330
499
  //#endregion
331
- //#region src/runner/e2e.d.ts
332
- interface E2eOptions {
333
- /** Project root — must contain docker/compose.test.yaml. */
500
+ //#region src/runner/spec.d.ts
501
+ /** Shared options for all spec targets. */
502
+ interface SpecOptions {
503
+ /** Project root for fixture lookup and compose detection (relative paths supported). */
334
504
  root?: string;
505
+ /** Infrastructure services to start via testcontainers. */
506
+ services?: ServiceHandle[];
507
+ }
508
+ /** A specification runner with teardown support and orchestrator access. */
509
+ interface SpecRunner {
510
+ /** The function to create individual specs: `runner('label').get('/path').run()`. */
511
+ (label: string): SpecificationBuilder;
512
+ /** Stop all infrastructure started by this runner. */
513
+ cleanup: () => Promise<void>;
514
+ /**
515
+ * Get a Docker assertion builder for a running container.
516
+ *
517
+ * @example
518
+ * await runner.docker('my-container').toBeRunning();
519
+ */
520
+ docker: (containerId: string) => DockerAssertion;
521
+ /** The orchestrator managing the test infrastructure lifecycle. */
522
+ orchestrator: Orchestrator;
335
523
  }
336
524
  /**
337
- * Create an E2E specification runner.
338
- * Starts full docker compose stack. App URL and database auto-detected.
525
+ * Create a specification runner for the given target.
526
+ *
527
+ * @param target - What to test against: {@link app}, {@link stack}, or {@link command}.
528
+ * @param options - Shared options: root directory, infrastructure services.
529
+ *
530
+ * @example
531
+ * // HTTP — in-process app with testcontainers
532
+ * const s = await spec(app(() => createApp(db)), { services: [db] });
533
+ *
534
+ * // HTTP — full docker compose stack
535
+ * const s = await spec(stack('../../'));
536
+ *
537
+ * // CLI — command binary
538
+ * const s = await spec(command('my-cli'), { root: '../fixtures' });
339
539
  */
340
- declare function e2e(options?: E2eOptions): Promise<SpecificationRunnerWithCleanup>;
540
+ declare function spec(target: SpecTarget, options?: SpecOptions): Promise<SpecRunner>;
341
541
  //#endregion
342
542
  //#region src/ports/container.port.d.ts
343
543
  /**
@@ -361,8 +561,9 @@ interface ContainerPort {
361
561
  //#endregion
362
562
  //#region src/adapters/exec.adapter.d.ts
363
563
  /**
364
- * Executes CLI commands via execSync (blocking) or spawn (long-running).
365
- * Used by cli() for local command execution.
564
+ * Executes CLI commands via Node.js child_process.
565
+ * Uses `execSync` for one-shot commands and `spawn` for long-running processes.
566
+ * Used by the `cli()` specification runner.
366
567
  */
367
568
  declare class ExecAdapter implements CommandPort {
368
569
  private command;
@@ -373,8 +574,8 @@ declare class ExecAdapter implements CommandPort {
373
574
  //#endregion
374
575
  //#region src/adapters/fetch.adapter.d.ts
375
576
  /**
376
- * Server adapter for real HTTP sends actual fetch requests.
377
- * Used by e2e() specification runner.
577
+ * Server adapter that sends real HTTP requests via the Fetch API.
578
+ * Used by the `e2e()` specification runner to hit a live server.
378
579
  */
379
580
  declare class FetchAdapter implements ServerPort {
380
581
  private baseUrl;
@@ -384,8 +585,8 @@ declare class FetchAdapter implements ServerPort {
384
585
  //#endregion
385
586
  //#region src/adapters/hono.adapter.d.ts
386
587
  /**
387
- * Server adapter for Hono in-process requests, no real HTTP.
388
- * Used by integration() specification runner.
588
+ * Server adapter that dispatches requests in-process through a Hono app instance.
589
+ * Used by the `integration()` specification runner -- no network overhead.
389
590
  */
390
591
  declare class HonoAdapter implements ServerPort {
391
592
  private app;
@@ -395,158 +596,57 @@ declare class HonoAdapter implements ServerPort {
395
596
  request(method: string, path: string, body?: unknown): Promise<ServerResponse>;
396
597
  }
397
598
  //#endregion
398
- //#region src/adapters/postgres.adapter.d.ts
399
- interface PostgresOptions {
400
- /** Map to a service in docker-compose.test.yaml. */
401
- compose?: string;
402
- /** Override image. */
403
- image?: string;
404
- /** Override environment variables. */
405
- env?: Record<string, string>;
599
+ //#region src/runner/integration.d.ts
600
+ type HonoApp = {
601
+ fetch: (...args: any[]) => any;
602
+ request: (path: string, init?: RequestInit) => Promise<Response> | Response;
603
+ };
604
+ interface IntegrationOptions {
605
+ /** Factory that returns a Hono app — called after services start. */
606
+ app: () => HonoApp;
607
+ /** Project root for compose detection (relative paths supported). */
608
+ root?: string;
609
+ /** Declared services — started via testcontainers. */
610
+ services: ServiceHandle[];
406
611
  }
407
- declare class PostgresHandle implements DatabasePort, ServiceHandle {
408
- readonly type = "postgres";
409
- readonly composeName: null | string;
410
- readonly defaultPort = 5432;
411
- readonly defaultImage: string;
412
- readonly environment: Record<string, string>;
413
- connectionString: string;
414
- started: boolean;
415
- private client;
416
- constructor(options?: PostgresOptions);
417
- buildConnectionString(host: string, port: number): string;
418
- createDatabaseAdapter(): DatabasePort;
419
- healthcheck(): Promise<void>;
420
- initialize(composeDir: string): Promise<void>;
421
- private getClient;
422
- seed(sql: string): Promise<void>;
423
- query(table: string, columns: string[]): Promise<unknown[][]>;
424
- reset(): Promise<void>;
612
+ /** A specification runner that also exposes teardown and the underlying orchestrator. */
613
+ interface SpecificationRunnerWithCleanup extends SpecificationRunner {
614
+ /** Stop all infrastructure containers started by this runner. */
615
+ cleanup: () => Promise<void>;
616
+ /** The orchestrator managing the test infrastructure lifecycle. */
617
+ orchestrator: Orchestrator;
425
618
  }
426
619
  /**
427
- * Create a PostgreSQL service handle.
428
- *
429
- * @example
430
- * const db = postgres({ compose: "db" });
431
- * // After start: db.connectionString is populated
620
+ * Create an integration specification runner.
621
+ * Starts infra containers via testcontainers, app runs in-process.
432
622
  */
433
- declare function postgres(options?: PostgresOptions): PostgresHandle;
623
+ declare function integration(options: IntegrationOptions): Promise<SpecificationRunnerWithCleanup>;
434
624
  //#endregion
435
- //#region src/adapters/redis.adapter.d.ts
436
- interface RedisOptions {
437
- /** Map to a service in docker-compose.test.yaml. */
438
- compose?: string;
439
- /** Override image. */
440
- image?: string;
441
- }
442
- declare class RedisHandle implements ServiceHandle {
443
- readonly type = "redis";
444
- readonly composeName: null | string;
445
- readonly defaultPort = 6379;
446
- readonly defaultImage: string;
447
- readonly environment: Record<string, string>;
448
- connectionString: string;
449
- started: boolean;
450
- constructor(options?: RedisOptions);
451
- buildConnectionString(host: string, port: number): string;
452
- createDatabaseAdapter(): DatabasePort | null;
453
- healthcheck(): Promise<void>;
454
- initialize(): Promise<void>;
455
- reset(): Promise<void>;
625
+ //#region src/runner/cli.d.ts
626
+ interface CliOptions {
627
+ /** CLI command to run (resolved from node_modules/.bin or PATH). */
628
+ command: string;
629
+ /** Project root — base dir for .project() fixture lookup (relative paths supported). */
630
+ root?: string;
631
+ /** Optional infrastructure services (started via testcontainers). */
632
+ services?: ServiceHandle[];
456
633
  }
457
634
  /**
458
- * Create a Redis service handle.
459
- *
460
- * @example
461
- * const cache = redis({ compose: "cache" });
462
- * // After start: cache.connectionString is populated
635
+ * Create a CLI specification runner.
636
+ * Runs CLI commands against fixture projects. Optionally starts infrastructure.
463
637
  */
464
- declare function redis(options?: RedisOptions): RedisHandle;
465
- //#endregion
466
- //#region src/docker/docker-port.d.ts
467
- interface DockerContainerPort {
468
- /** Execute a command inside the container, return stdout */
469
- exec(cmd: string[]): Promise<string>;
470
- /** Read a file from inside the container */
471
- file(path: string): Promise<{
472
- exists: boolean;
473
- content: string;
474
- }>;
475
- /** Check if container is running */
476
- isRunning(): Promise<boolean>;
477
- /** Get container logs */
478
- logs(tail?: number): Promise<string>;
479
- /** Get full docker inspect JSON */
480
- inspect(): Promise<DockerInspectResult>;
481
- /** Check if a file/directory exists */
482
- exists(path: string): Promise<boolean>;
483
- }
484
- interface DockerInspectResult {
485
- id: string;
486
- name: string;
487
- state: {
488
- running: boolean;
489
- exitCode: number;
490
- status: string;
491
- };
492
- config: {
493
- image: string;
494
- env: string[];
495
- };
496
- hostConfig: {
497
- memory: number;
498
- cpuQuota: number;
499
- networkMode: string;
500
- mounts: Array<{
501
- source: string;
502
- destination: string;
503
- type: string;
504
- }>;
505
- };
506
- networkSettings: {
507
- networks: Record<string, {
508
- gateway: string;
509
- ipAddress: string;
510
- }>;
511
- };
512
- }
513
- //#endregion
514
- //#region src/docker/docker-adapter.d.ts
515
- /** Create a Docker container port for an existing container */
516
- declare function dockerContainer(containerId: string): DockerContainerPort;
638
+ declare function cli(options: CliOptions): Promise<SpecificationRunnerWithCleanup>;
517
639
  //#endregion
518
- //#region src/docker/docker-assertion.d.ts
519
- /** Fluent assertion builder for Docker containers */
520
- declare class DockerAssertion {
521
- private container;
522
- constructor(container: DockerContainerPort);
523
- /** Assert the container is running */
524
- toBeRunning(): Promise<this>;
525
- /** Assert the container is NOT running / doesn't exist */
526
- toNotExist(): Promise<this>;
527
- /** Assert a file exists inside the container */
528
- toHaveFile(path: string, opts?: {
529
- containing?: string;
530
- }): Promise<this>;
531
- /** Assert a file does NOT exist */
532
- toNotHaveFile(path: string): Promise<this>;
533
- /** Assert a directory exists */
534
- toHaveDirectory(path: string): Promise<this>;
535
- /** Assert a mount exists */
536
- toHaveMount(destination: string): Promise<this>;
537
- /** Assert network mode */
538
- toHaveNetwork(mode: string): Promise<this>;
539
- /** Assert memory limit */
540
- toHaveMemoryLimit(bytes: number): Promise<this>;
541
- /** Assert CPU quota */
542
- toHaveCpuQuota(quota: number): Promise<this>;
543
- /** Execute a command and return output for custom assertions */
544
- exec(cmd: string[]): Promise<string>;
545
- /** Read a file for custom assertions */
546
- readFile(path: string): Promise<string>;
547
- /** Get logs for custom assertions */
548
- getLogs(tail?: number): Promise<string>;
640
+ //#region src/runner/e2e.d.ts
641
+ interface E2eOptions {
642
+ /** Project root — must contain docker/compose.test.yaml. */
643
+ root?: string;
549
644
  }
645
+ /**
646
+ * Create an E2E specification runner.
647
+ * Starts full docker compose stack. App URL and database auto-detected.
648
+ */
649
+ declare function e2e(options?: E2eOptions): Promise<SpecificationRunnerWithCleanup>;
550
650
  //#endregion
551
651
  //#region src/utilities/grep.d.ts
552
652
  /**
@@ -561,19 +661,14 @@ declare class DockerAssertion {
561
661
  declare function grep(output: string, pattern: string): string;
562
662
  //#endregion
563
663
  //#region src/utilities/reporter.d.ts
664
+ /** Strip ANSI escape codes from a string. */
564
665
  declare function stripAnsi(str: string): string;
666
+ /** Strip ANSI codes and replace volatile tokens (ports, durations) with placeholders. */
565
667
  declare function normalizeOutput(str: string): string;
566
668
  //#endregion
567
- //#region src/mocking/mock-of-date.d.ts
568
- interface MockDatePort {
569
- reset: () => void;
570
- set: (date: Date | number | string) => void;
571
- }
572
- declare const mockOfDate: MockDatePort;
573
- //#endregion
574
- //#region src/mocking/mock-of.d.ts
575
- type MockPort = <T>() => DeepMockProxy<T>;
576
- declare const mockOf: MockPort;
669
+ //#region src/docker/docker-adapter.d.ts
670
+ /** Create a {@link DockerContainerPort} bound to an existing container by ID. */
671
+ declare function dockerContainer(containerId: string): DockerContainerPort;
577
672
  //#endregion
578
- export { type CliOptions, type CommandEnv, type CommandPort, type CommandResult, type ContainerPort, type DatabasePort, DirectoryAccessor, type DirectorySnapshotOptions, DockerAssertion, type DockerContainerPort, type DockerInspectResult, type E2eOptions, ExecAdapter, FetchAdapter, type FileAccessor, HonoAdapter, type IntegrationOptions, type MockDatePort, type MockPort, Orchestrator, type PostgresOptions, type RedisOptions, ResponseAccessor, type ServerPort, type ServerResponse, type ServiceHandle, type SpawnOptions, SpecificationBuilder, type SpecificationConfig, SpecificationResult, type SpecificationRunner, type SpecificationRunnerWithCleanup, TableAssertion, cli, createSpecificationRunner, dockerContainer, e2e, grep, integration, mockOf, mockOfDate, normalizeOutput, postgres, redis, stripAnsi };
673
+ export { type AppTarget, type CliOptions, type CommandEnv, type CommandPort, type CommandResult, type CommandTarget, type ContainerPort, type DatabasePort, DirectoryAccessor, type DirectorySnapshotOptions, DockerAssertion, type DockerContainerPort, type DockerInspectResult, type E2eOptions, ExecAdapter, FetchAdapter, type FileAccessor, HonoAdapter, type HttpTarget, type IntegrationOptions, type IsolationStrategy, type MockDatePort, type MockPort, Orchestrator, type PostgresOptions, type RedisOptions, ResponseAccessor, type ServerPort, type ServerResponse, type ServiceHandle, type SpawnOptions, type SpecOptions, type SpecRunner, type SpecTarget, SpecificationBuilder, type SpecificationConfig, SpecificationResult, type SpecificationRunner, type SpecificationRunnerWithCleanup, type StackTarget, TableAssertion, app, cli, command, createSpecificationRunner, dockerContainer, e2e, grep, integration, mockOf, mockOfDate, normalizeOutput, postgres, redis, spec, stack, stripAnsi };
579
674
  //# sourceMappingURL=index.d.ts.map