@stratal/testing 0.0.27 → 0.1.1
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/CHANGELOG.md +570 -0
- package/README.md +137 -36
- package/dist/database/index.d.mts +2 -2
- package/dist/database/index.mjs +2 -2
- package/dist/database-Rojs69r3.mjs +453 -0
- package/dist/database-Rojs69r3.mjs.map +1 -0
- package/dist/{decorate-B7nr7eBl.mjs → decorate-RQD1h28J.mjs} +1 -1
- package/dist/feature-flags/index.mjs +1 -1
- package/dist/{feature-flags-BiLhfSGh.mjs → feature-flags-CZ1a4M2g.mjs} +2 -2
- package/dist/{feature-flags-BiLhfSGh.mjs.map → feature-flags-CZ1a4M2g.mjs.map} +1 -1
- package/dist/index-B8Mw1Dxk.d.mts +175 -0
- package/dist/index-B8Mw1Dxk.d.mts.map +1 -0
- package/dist/{index-CrHzUDKX.d.mts → index-D7FM6EKp.d.mts} +21 -3
- package/dist/index-D7FM6EKp.d.mts.map +1 -0
- package/dist/index-qgWNJRdC.d.mts.map +1 -1
- package/dist/index.d.mts +105 -46
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +218 -108
- package/dist/index.mjs.map +1 -1
- package/dist/mocks/cloudflare-workers.d.mts +24 -0
- package/dist/mocks/cloudflare-workers.d.mts.map +1 -0
- package/dist/mocks/cloudflare-workers.mjs +28 -0
- package/dist/mocks/cloudflare-workers.mjs.map +1 -0
- package/dist/mocks/index.d.mts +2 -2
- package/dist/mocks/index.mjs +2 -2
- package/dist/mocks/noop-rate-limiter-store.d.mts +1 -3
- package/dist/mocks/noop-rate-limiter-store.d.mts.map +1 -1
- package/dist/mocks/zenstack-language.d.mts +26 -29
- package/dist/mocks/zenstack-language.d.mts.map +1 -1
- package/dist/mocks/zenstack-language.mjs +1 -1
- package/dist/mocks/zenstack-language.mjs.map +1 -1
- package/dist/storage/index.d.mts +1 -1
- package/dist/storage/index.mjs +1 -1
- package/dist/{storage-DhoxWqyF.mjs → storage-BiGamMA8.mjs} +73 -6
- package/dist/storage-BiGamMA8.mjs.map +1 -0
- package/dist/test-worker-exports-dCRARYEc.d.mts +144 -0
- package/dist/test-worker-exports-dCRARYEc.d.mts.map +1 -0
- package/dist/test-workers-cache-D02Pt_dE.mjs +183 -0
- package/dist/test-workers-cache-D02Pt_dE.mjs.map +1 -0
- package/dist/vitest-plugin/index.d.mts +14 -28
- package/dist/vitest-plugin/index.d.mts.map +1 -1
- package/dist/vitest-plugin/index.mjs +32 -20
- package/dist/vitest-plugin/index.mjs.map +1 -1
- package/package.json +30 -21
- package/dist/database-B02eYKhE.mjs +0 -334
- package/dist/database-B02eYKhE.mjs.map +0 -1
- package/dist/index-BIr5nLof.d.mts +0 -122
- package/dist/index-BIr5nLof.d.mts.map +0 -1
- package/dist/index-CrHzUDKX.d.mts.map +0 -1
- package/dist/storage-DhoxWqyF.mjs.map +0 -1
- package/dist/test-email-provider-B7cjj97-.d.mts +0 -21
- package/dist/test-email-provider-B7cjj97-.d.mts.map +0 -1
- package/dist/test-email-provider-Dr-nhE0x.mjs +0 -34
- package/dist/test-email-provider-Dr-nhE0x.mjs.map +0 -1
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
//#region src/database/test-database.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Test database isolation helpers.
|
|
4
|
+
*
|
|
5
|
+
* Implements leased worker databases for parallel runs against Postgres. A
|
|
6
|
+
* migrated **template** database is built once in global setup. Each test file
|
|
7
|
+
* leases one numbered worker database for as long as its isolate lives and
|
|
8
|
+
* receives a fresh clone of the template in it, so a run holds at most as many
|
|
9
|
+
* databases as it runs files at once. See `@stratal/testing/database`.
|
|
10
|
+
*
|
|
11
|
+
* `pg` is imported dynamically so this module loads without it — consumers
|
|
12
|
+
* that don't use a database never pay the dependency.
|
|
13
|
+
*/
|
|
14
|
+
/** Env var carrying the name of the Hyperdrive binding to isolate. */
|
|
15
|
+
declare const BINDING_ENV_VAR = "STRATAL_TEST_DB_BINDING";
|
|
16
|
+
/** Default Hyperdrive binding name when none is configured. */
|
|
17
|
+
declare const DEFAULT_DB_BINDING = "DB";
|
|
18
|
+
/**
|
|
19
|
+
* Derive an admin connection string pointing at the `postgres` maintenance
|
|
20
|
+
* database. `CREATE`/`DROP DATABASE` cannot run on a connection bound to the
|
|
21
|
+
* target database, so administration always goes through `postgres`.
|
|
22
|
+
*/
|
|
23
|
+
declare function deriveAdminConnectionString(connectionString: string): string;
|
|
24
|
+
/** Build a connection string identical to `base` but pointing at `dbName`. */
|
|
25
|
+
declare function buildConnectionString(base: string, dbName: string): string;
|
|
26
|
+
/** The shared prefix for worker databases, used as the sweep key. */
|
|
27
|
+
declare function databasePrefix(base: string): string;
|
|
28
|
+
/** Name of the migrated template database cloned per worker. */
|
|
29
|
+
declare function deriveTemplateName(base: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Name of the worker database behind lease `slot`. Asserted against Postgres'
|
|
32
|
+
* 63-char identifier limit (keep the base name short so `_w_<slot>` fits).
|
|
33
|
+
*/
|
|
34
|
+
declare function deriveWorkerDbName(base: string, slot: number): string;
|
|
35
|
+
/**
|
|
36
|
+
* Replace worker database `dbName` with a fresh clone of `template`.
|
|
37
|
+
*
|
|
38
|
+
* The clone is serialized across all workers and processes by one Postgres
|
|
39
|
+
* advisory lock keyed on the template. Postgres permits only one
|
|
40
|
+
* `CREATE DATABASE ... TEMPLATE t` at a time — a concurrent one fails with
|
|
41
|
+
* SQLSTATE 55006 — so without the lock every file starting at once would race
|
|
42
|
+
* and all but one would fail. The lock funnels them one at a time, each
|
|
43
|
+
* blocking *in Postgres* (not busy-waiting) until its turn. A create that still
|
|
44
|
+
* hits a transient 55006 is retried with backoff.
|
|
45
|
+
*
|
|
46
|
+
* `WITH (FORCE)` ends connections the previous lessee's pool left open: its
|
|
47
|
+
* isolate is gone, so nothing will close them.
|
|
48
|
+
*/
|
|
49
|
+
declare function cloneWorkerDatabase(adminConn: string, dbName: string, template: string): Promise<void>;
|
|
50
|
+
/** A worker database leased to the current isolate. */
|
|
51
|
+
interface WorkerDatabaseLease {
|
|
52
|
+
/** The leased database's name (`<base>_w_<slot>`). */
|
|
53
|
+
name: string;
|
|
54
|
+
/** `base` pointed at the leased database. */
|
|
55
|
+
connectionString: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Lease the lowest free worker database for `base` and fill it with a fresh
|
|
59
|
+
* clone of the template.
|
|
60
|
+
*
|
|
61
|
+
* A slot is free when no other session holds its advisory lock. The pool runs
|
|
62
|
+
* each test file in its own isolate and disposes that isolate when the file
|
|
63
|
+
* ends, so a run never holds more slots than it runs files at once — and so
|
|
64
|
+
* never more worker databases. Every lease re-clones, so a file starts from
|
|
65
|
+
* exactly the template, including anything `prepare` baked into it.
|
|
66
|
+
*/
|
|
67
|
+
declare function leaseWorkerDatabase(base: string): Promise<WorkerDatabaseLease>;
|
|
68
|
+
/** Options for {@link createTestDatabaseGlobalSetup}. */
|
|
69
|
+
interface TestDatabaseGlobalSetupOptions {
|
|
70
|
+
/** Run migrations against the template connection string. */
|
|
71
|
+
migrate: (connectionString: string) => void | Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Schema source(s) — file or directory path(s). Contents + `migrate` + `prepare`
|
|
74
|
+
* are hashed into the template fingerprint; the template is reused across runs
|
|
75
|
+
* while unchanged. For a ZenStack multi-file schema pass the root `.zmodel`.
|
|
76
|
+
*/
|
|
77
|
+
schema: string | string[];
|
|
78
|
+
/**
|
|
79
|
+
* One-time preparation run against the template **after** migrations (before
|
|
80
|
+
* the fingerprint is stamped). Bake expensive baseline state here — seed data,
|
|
81
|
+
* a default tenant schema, reference rows — so every worker database inherits
|
|
82
|
+
* it via the clone instead of rebuilding it per test.
|
|
83
|
+
*
|
|
84
|
+
* The fingerprint hashes this hook's **source text only** — if `prepare` reads
|
|
85
|
+
* external data files (seed JSON/SQL) at runtime, changing only those files
|
|
86
|
+
* will NOT invalidate the template. Bump the hook's source (e.g. a version
|
|
87
|
+
* comment) or drop the template manually when seed data changes.
|
|
88
|
+
*/
|
|
89
|
+
prepare?: (connectionString: string) => void | Promise<void>;
|
|
90
|
+
/** Base/admin connection string. Defaults to `process.env.DATABASE_URL`. */
|
|
91
|
+
connectionString?: string;
|
|
92
|
+
/** Template database name. Defaults to `<baseDbName>_template`. */
|
|
93
|
+
templateName?: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Build a Vitest `globalSetup` default export that prepares the test database.
|
|
97
|
+
*
|
|
98
|
+
* Under a Postgres advisory lock (so concurrent setups across CI shards /
|
|
99
|
+
* multiple e2e projects don't clobber each other), sweeps unused worker
|
|
100
|
+
* databases, then ensures a migrated (and optionally prepared) template exists
|
|
101
|
+
* — ready to be cloned into each leased worker database.
|
|
102
|
+
*
|
|
103
|
+
* **Template reuse.** The template is fingerprinted from the `schema` source(s)
|
|
104
|
+
* + the `migrate` routine + the `prepare` routine, and the fingerprint is
|
|
105
|
+
* stored as the template's database COMMENT. On each run, a matching
|
|
106
|
+
* fingerprint means nothing has changed and the existing template is reused
|
|
107
|
+
* as-is — `migrate`/`prepare` run **only** on the first run after an edit (or on
|
|
108
|
+
* a fresh database). The fingerprint is stamped only after a successful
|
|
109
|
+
* migrate + prepare, so a match always implies a complete template; there is no
|
|
110
|
+
* force/skip flag — reuse is purely fingerprint-driven.
|
|
111
|
+
*
|
|
112
|
+
* **Concurrency model.** The reuse check + rebuild runs under
|
|
113
|
+
* `pg_advisory_lock(hashtext(<template>))`, so only one process rebuilds the
|
|
114
|
+
* template at a time. The sweep only drops worker databases with **no active
|
|
115
|
+
* connections** and a free lease slot, leaving a sibling process's live databases
|
|
116
|
+
* intact — which is what lets it run at teardown as well as at setup, so a run
|
|
117
|
+
* takes its own databases with it. Teardown deliberately does **not** drop the
|
|
118
|
+
* template: it is shared, and the next run reuses it by fingerprint.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* // test/global-setup.ts
|
|
123
|
+
* import { createTestDatabaseGlobalSetup } from '@stratal/testing/database'
|
|
124
|
+
*
|
|
125
|
+
* export default createTestDatabaseGlobalSetup({
|
|
126
|
+
* schema: schemaPath, // file or directory — reused-when-unchanged fingerprint
|
|
127
|
+
* migrate: (conn) => execFileSync(zenstackBin, ['db', 'push', '--force-reset', `--schema=${schemaPath}`, '--accept-data-loss'],
|
|
128
|
+
* { env: { ...process.env, DATABASE_URL: conn }, stdio: 'inherit' }),
|
|
129
|
+
* })
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
declare function createTestDatabaseGlobalSetup(opts: TestDatabaseGlobalSetupOptions): () => Promise<() => Promise<void>>;
|
|
133
|
+
//#endregion
|
|
134
|
+
//#region src/database/reset.d.ts
|
|
135
|
+
/** Options controlling which tables a per-test reset truncates. */
|
|
136
|
+
interface ResetOptions {
|
|
137
|
+
/** Extra schemas to include beyond `current_schema()` (e.g. a tenant schema). */
|
|
138
|
+
schemas?: string[];
|
|
139
|
+
/**
|
|
140
|
+
* Bare table names or SQL LIKE patterns (matched against `tablename` across
|
|
141
|
+
* all target schemas) that must survive the reset — reference/seed data baked
|
|
142
|
+
* into the template. Not schema-qualified: a `schema.table` entry matches a
|
|
143
|
+
* table literally named `schema.table`, not `table` in `schema`. Migration
|
|
144
|
+
* bookkeeping (`_prisma%`) is always preserved.
|
|
145
|
+
*/
|
|
146
|
+
preserve?: string[];
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Build a single `TRUNCATE ... RESTART IDENTITY CASCADE` (empty when no tables).
|
|
150
|
+
* Takes `{ schema, table }` pairs and quotes each part independently, so a
|
|
151
|
+
* dotted identifier (a legal quoted name, e.g. `"my.table"`) is preserved
|
|
152
|
+
* verbatim rather than mis-split into extra qualifier segments.
|
|
153
|
+
*/
|
|
154
|
+
declare function buildTruncateSql(tables: {
|
|
155
|
+
schema: string;
|
|
156
|
+
table: string;
|
|
157
|
+
}[]): string;
|
|
158
|
+
/**
|
|
159
|
+
* Build the SQL that discovers truncatable tables: every base table in the
|
|
160
|
+
* given schemas ({@link CURRENT_SCHEMA} → `current_schema()`), excluding
|
|
161
|
+
* migration bookkeeping (`_prisma%`) and any caller-supplied preserve patterns.
|
|
162
|
+
* Returns a SELECT of `schemaname, tablename`. Escaping lives here so both reset
|
|
163
|
+
* paths share one implementation.
|
|
164
|
+
*/
|
|
165
|
+
declare function buildTableDiscoverySql(schemas: string[], preserve: string[]): string;
|
|
166
|
+
/**
|
|
167
|
+
* Reset a worker database between tests: discover every non-preserved table in
|
|
168
|
+
* the target schemas and truncate them in one statement. Fast because the
|
|
169
|
+
* schema/DDL is baked into the worker DB — reset only clears mutable rows and
|
|
170
|
+
* resets identities. Opens and closes a short-lived direct `pg` connection.
|
|
171
|
+
*/
|
|
172
|
+
declare function resetWorkerDatabase(connectionString: string, opts?: ResetOptions): Promise<void>;
|
|
173
|
+
//#endregion
|
|
174
|
+
export { BINDING_ENV_VAR as a, WorkerDatabaseLease as c, createTestDatabaseGlobalSetup as d, databasePrefix as f, leaseWorkerDatabase as g, deriveWorkerDbName as h, resetWorkerDatabase as i, buildConnectionString as l, deriveTemplateName as m, buildTableDiscoverySql as n, DEFAULT_DB_BINDING as o, deriveAdminConnectionString as p, buildTruncateSql as r, TestDatabaseGlobalSetupOptions as s, ResetOptions as t, cloneWorkerDatabase as u };
|
|
175
|
+
//# sourceMappingURL=index-B8Mw1Dxk.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-B8Mw1Dxk.d.mts","names":[],"sources":["../src/database/test-database.ts","../src/database/reset.ts"],"mappings":";;;;;;;;;;;;;;cAoBa;;cAGA;;;;;;iBAgEG,4BAA4B;;iBAO5B,sBAAsB,cAAc;;iBAOpC,eAAe;;iBAMf,mBAAmB;;;;;iBAUnB,mBAAmB,cAAc;;;;;;;;;;;;;;;iBA0D3B,oBACpB,mBACA,gBACA,mBACC;;UA0Bc;;EAEf;;EAEA;;;;;;;;;;;;iBAqBoB,oBAAoB,eAAe,QAAQ;;UA2LhD;;EAEf,UAAU,oCAAoC;;;;;;EAM9C;;;;;;;;;;;;EAYA,WAAW,oCAAoC;;EAE/C;;EAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwCc,8BACd,MAAM,uCACC,cAAc;;;;UCheN;;EAEf;;;;;;;;EAQA;;;;;;;;iBAac,iBAAiB;EAAU;EAAgB;;;;;;;;;iBAoB3C,uBAAuB,mBAAmB;;;;;;;iBAqBpC,oBAAoB,0BAA0B,OAAM,eAAoB"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { DownloadResult, PresignedUrlResult, StorageConfig, StorageManagerService, StorageService, StreamingBlobPayloadInputTypes, UploadOptions, UploadResult } from "stratal/storage";
|
|
2
|
-
|
|
1
|
+
import { DownloadResult, HeadResult, ListOptions, ListResult, PresignedUrlResult, StorageConfig, StorageManagerService, StorageService, StreamingBlobPayloadInputTypes, UploadOptions, UploadResult } from "stratal/storage";
|
|
3
2
|
//#region src/storage/fake-storage.service.d.ts
|
|
4
3
|
/**
|
|
5
4
|
* Stored file representation in memory
|
|
@@ -49,6 +48,25 @@ declare class FakeStorageService extends StorageService {
|
|
|
49
48
|
* Check if a file exists in fake storage
|
|
50
49
|
*/
|
|
51
50
|
exists(path: string): Promise<boolean>;
|
|
51
|
+
/**
|
|
52
|
+
* Delete many files from fake storage
|
|
53
|
+
*/
|
|
54
|
+
deleteMany(paths: string[], disk?: string): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Read a file's metadata from fake storage, without its contents
|
|
57
|
+
*/
|
|
58
|
+
head(path: string, disk?: string): Promise<HeadResult | null>;
|
|
59
|
+
/**
|
|
60
|
+
* List files in fake storage, one page at a time
|
|
61
|
+
*
|
|
62
|
+
* Truncates after ONE object unless `limit` says otherwise. Real R2 pages at 1000, but no
|
|
63
|
+
* fixture stores 1000 files — matching that number would return everything in one page and let
|
|
64
|
+
* a caller who never follows `cursor` pass every test, then undercount against a real bucket.
|
|
65
|
+
* Paging at one means any listing of two or more objects exercises the loop.
|
|
66
|
+
*
|
|
67
|
+
* Pass `limit` to widen the page when a test is asserting page contents rather than the loop.
|
|
68
|
+
*/
|
|
69
|
+
list(options?: ListOptions, disk?: string): Promise<ListResult>;
|
|
52
70
|
/**
|
|
53
71
|
* Generate a fake presigned download URL
|
|
54
72
|
*/
|
|
@@ -115,4 +133,4 @@ declare class FakeStorageService extends StorageService {
|
|
|
115
133
|
}
|
|
116
134
|
//#endregion
|
|
117
135
|
export { StoredFile as n, FakeStorageService as t };
|
|
118
|
-
//# sourceMappingURL=index-
|
|
136
|
+
//# sourceMappingURL=index-D7FM6EKp.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-D7FM6EKp.d.mts","names":[],"sources":["../src/storage/fake-storage.service.ts"],"mappings":";;;;;UAwCiB;EACf,SAAS;EACT;EACA;EACA,WAAW;EACX,YAAY;;;;;;;;;;;;;;;;;;;cAqBD,2BAA2B;qBAKjB,gBAAgB;qBAEhB,SAAS;UANtB;EAER,YAEqB,gBAAgB,uBAEhB,SAAS;;;;EAQxB,OACJ,MAAM,gCACN,sBACA,SAAS,eACT,gBACC,QAAQ;;;;EAyBX,SAAS,eAAe,QAAQ;;;;EAyBhC,OAAO,eAAe;;;;EAQtB,OAAO,eAAe;;;;EAUhB,WAAW,iBAAiB,gBAAgB;;;;EAa5C,KAAK,cAAc,gBAAgB,QAAQ;;;;;;;;;;;EAqB3C,KAAK,UAAS,aAAkB,gBAAgB,QAAQ;;;;EAuC9D,wBACE,cACA,qBACC,QAAQ;;;;EAOX,sBACE,cACA,qBACC,QAAQ;;;;EAOX,sBACE,cACA,qBACC,QAAQ;;;;EAOL,cACJ,MAAM,gCACN,cACA,SAAS,KAAK;IAA2B;KACzC,gBACC,QAAQ;;;;;;;EAoBX,aAAa;;;;;;;EAab,cAAc;;;;;;EAYd;;;;;;;EAaA,YAAY;;;;EAUZ,kBAAkB,YAAY;;;;EAO9B;;;;EAOA,QAAQ,eAAe;;;;EAOvB;UAQQ;UAeM"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-qgWNJRdC.d.mts","names":[],"sources":["../src/feature-flags/fake-feature-flag.service.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"index-qgWNJRdC.d.mts","names":[],"sources":["../src/feature-flags/fake-feature-flag.service.ts"],"mappings":";;;;;;;;;;cAWa;;KAGD;UAEF,gBAAgB;EACxB;EACA,OAAO;EACP;;;;;;;;;;;;;;;;;;;;cAsBW;mBACM;;EAKjB,IAAI,iBAAiB,OAAO;;EAM5B,OAAO,OAAO,eAAe;;EAO7B;EAOM,IAAI,iBAAiB,yBAAyB;EAI9C,gBAAgB,iBAAiB,yBAAuB;EAIxD,eAAe,iBAAiB,wBAAoB;EAIpD,eAAe,iBAAiB,wBAAmB;EAInD,eAAe,kBAAkB,iBAAiB,eAAc,IAAc,QAAQ;EAItF,kBAAkB,iBAAiB,yBAAuB,QAAQ;EAIlE,iBAAiB,iBAAiB,wBAAoB,QAAQ;EAI9D,iBAAiB,iBAAiB,wBAAmB,QAAQ;EAI7D,iBAAiB,kBAAkB,iBAAiB,eAAc,IAAc,QAAQ,gBAAgB;;EAKxG,OAAO,QAAQ,eAAe;;EAKpC;;MAMI;UAMI;UAIA"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { t as ResetOptions } from "./index-B8Mw1Dxk.mjs";
|
|
1
2
|
import { n as FakeFeatureFlagService } from "./index-qgWNJRdC.mjs";
|
|
2
|
-
import { t as FakeStorageService } from "./index-
|
|
3
|
-
import {
|
|
3
|
+
import { t as FakeStorageService } from "./index-D7FM6EKp.mjs";
|
|
4
|
+
import { i as TestEmailProvider, n as TestWorkerExports, r as TestWorkersCache } from "./test-worker-exports-dCRARYEc.mjs";
|
|
4
5
|
import { Application, ApplicationConfig, Constructor, StratalEnv, StratalExecutionContext } from "stratal";
|
|
5
6
|
import { DynamicModule, InjectionToken, ModuleClass, ModuleOptions } from "stratal/module";
|
|
6
7
|
import { ResolvedEmailMessage } from "stratal/email";
|
|
@@ -13,7 +14,6 @@ import { Macroable } from "stratal/macroable";
|
|
|
13
14
|
import { HttpResponse, RequestHandler, http } from "msw";
|
|
14
15
|
import { ExceptionHandler } from "stratal/errors";
|
|
15
16
|
import { CommandInput, CommandResult } from "stratal/quarry";
|
|
16
|
-
|
|
17
17
|
//#region src/core/http/test-response.d.ts
|
|
18
18
|
/**
|
|
19
19
|
* TestResponse
|
|
@@ -28,7 +28,7 @@ import { CommandInput, CommandResult } from "stratal/quarry";
|
|
|
28
28
|
* .assertJsonPath('data.id', userId)
|
|
29
29
|
* ```
|
|
30
30
|
*/
|
|
31
|
-
declare class TestResponse extends Macroable {
|
|
31
|
+
export declare class TestResponse extends Macroable {
|
|
32
32
|
private readonly response;
|
|
33
33
|
private jsonData;
|
|
34
34
|
private textData;
|
|
@@ -191,7 +191,7 @@ declare class TestResponse extends Macroable {
|
|
|
191
191
|
* .send()
|
|
192
192
|
* ```
|
|
193
193
|
*/
|
|
194
|
-
declare class TestHttpRequest extends Macroable {
|
|
194
|
+
export declare class TestHttpRequest extends Macroable {
|
|
195
195
|
protected readonly method: string;
|
|
196
196
|
protected readonly path: string;
|
|
197
197
|
protected readonly module: TestingModule;
|
|
@@ -264,7 +264,7 @@ declare class TestHttpRequest extends Macroable {
|
|
|
264
264
|
* response.assertCreated()
|
|
265
265
|
* ```
|
|
266
266
|
*/
|
|
267
|
-
declare class TestHttpClient {
|
|
267
|
+
export declare class TestHttpClient {
|
|
268
268
|
private readonly module;
|
|
269
269
|
private defaultHeaders;
|
|
270
270
|
private host;
|
|
@@ -329,7 +329,7 @@ declare class TestHttpClient {
|
|
|
329
329
|
* result.assertOutputContains('User created')
|
|
330
330
|
* ```
|
|
331
331
|
*/
|
|
332
|
-
declare class TestCommandResult {
|
|
332
|
+
export declare class TestCommandResult {
|
|
333
333
|
private readonly result;
|
|
334
334
|
constructor(result: CommandResult);
|
|
335
335
|
get exitCode(): number;
|
|
@@ -359,7 +359,7 @@ declare class TestCommandResult {
|
|
|
359
359
|
* result.assertOutputContains('User created')
|
|
360
360
|
* ```
|
|
361
361
|
*/
|
|
362
|
-
declare class TestCommandRequest {
|
|
362
|
+
export declare class TestCommandRequest {
|
|
363
363
|
private readonly commandName;
|
|
364
364
|
private readonly module;
|
|
365
365
|
private _input;
|
|
@@ -396,7 +396,7 @@ interface TestSseEvent {
|
|
|
396
396
|
* await sse.waitForEnd()
|
|
397
397
|
* ```
|
|
398
398
|
*/
|
|
399
|
-
declare class TestSseConnection {
|
|
399
|
+
export declare class TestSseConnection {
|
|
400
400
|
private readonly response;
|
|
401
401
|
private readonly eventQueue;
|
|
402
402
|
private eventWaiters;
|
|
@@ -454,7 +454,7 @@ declare class TestSseConnection {
|
|
|
454
454
|
* const sse = await module.sse('/streaming/sse').actingAs({ id: user.id }).connect()
|
|
455
455
|
* ```
|
|
456
456
|
*/
|
|
457
|
-
declare class TestSseRequest {
|
|
457
|
+
export declare class TestSseRequest {
|
|
458
458
|
private readonly path;
|
|
459
459
|
private readonly module;
|
|
460
460
|
private requestHeaders;
|
|
@@ -497,7 +497,7 @@ declare class TestSseRequest {
|
|
|
497
497
|
* await ws.waitForClose()
|
|
498
498
|
* ```
|
|
499
499
|
*/
|
|
500
|
-
declare class TestWsConnection {
|
|
500
|
+
export declare class TestWsConnection {
|
|
501
501
|
private readonly ws;
|
|
502
502
|
private readonly messageQueue;
|
|
503
503
|
private messageWaiters;
|
|
@@ -556,7 +556,7 @@ declare class TestWsConnection {
|
|
|
556
556
|
* const ws = await module.ws('/ws/chat').actingAs({ id: user.id }).connect()
|
|
557
557
|
* ```
|
|
558
558
|
*/
|
|
559
|
-
declare class TestWsRequest {
|
|
559
|
+
export declare class TestWsRequest {
|
|
560
560
|
private readonly path;
|
|
561
561
|
private readonly module;
|
|
562
562
|
private requestHeaders;
|
|
@@ -614,25 +614,17 @@ declare class TestWsRequest {
|
|
|
614
614
|
* await module.close()
|
|
615
615
|
* ```
|
|
616
616
|
*/
|
|
617
|
-
|
|
618
|
-
* Identifies a per-file database created for test isolation, so it can be
|
|
619
|
-
* dropped on teardown. Produced by the testing module builder.
|
|
620
|
-
*/
|
|
621
|
-
interface IsolatedDatabase {
|
|
622
|
-
/** Name of the cloned database. */
|
|
623
|
-
name: string;
|
|
624
|
-
/** Admin (maintenance-database) connection string used to drop it. */
|
|
625
|
-
adminConnectionString: string;
|
|
626
|
-
}
|
|
627
|
-
declare class TestingModule {
|
|
617
|
+
export declare class TestingModule {
|
|
628
618
|
private readonly app;
|
|
629
619
|
private readonly env;
|
|
630
620
|
private readonly ctx;
|
|
631
|
-
private readonly isolatedDatabase;
|
|
632
621
|
private readonly testEmailProvider;
|
|
622
|
+
private readonly pendingTasks;
|
|
623
|
+
private readonly testWorkersCache;
|
|
624
|
+
private readonly testWorkerExports;
|
|
633
625
|
private _http;
|
|
634
626
|
private readonly _requestContainer;
|
|
635
|
-
constructor(app: Application, env: StratalEnv, ctx: StratalExecutionContext,
|
|
627
|
+
constructor(app: Application, env: StratalEnv, ctx: StratalExecutionContext, testEmailProvider?: TestEmailProvider | null, pendingTasks?: Promise<unknown>[], testWorkersCache?: TestWorkersCache | undefined, testWorkerExports?: TestWorkerExports | undefined);
|
|
636
628
|
/**
|
|
637
629
|
* Emails recorded by the default {@link TestEmailProvider}, in send order.
|
|
638
630
|
* Empty when the email provider factory was overridden.
|
|
@@ -648,6 +640,15 @@ declare class TestingModule {
|
|
|
648
640
|
get http(): TestHttpClient;
|
|
649
641
|
/**
|
|
650
642
|
* Get Inertia test client for making Inertia requests
|
|
643
|
+
*
|
|
644
|
+
* Sends no `X-Inertia-Version`. It used to send `'1'`, which meant any app configuring a real
|
|
645
|
+
* asset version had every request from this client read as a stale client and answered with a
|
|
646
|
+
* version-mismatch 409 — an entire Inertia suite failing on a value the tests never chose. The
|
|
647
|
+
* check needs a version from BOTH sides, so omitting it here leaves the app under test in charge
|
|
648
|
+
* rather than this header.
|
|
649
|
+
*
|
|
650
|
+
* A test that wants the mismatch path asks for it:
|
|
651
|
+
* `module.inertia.withHeaders({ 'X-Inertia-Version': 'stale' })`.
|
|
651
652
|
*/
|
|
652
653
|
get inertia(): TestHttpClient;
|
|
653
654
|
/**
|
|
@@ -659,6 +660,30 @@ declare class TestingModule {
|
|
|
659
660
|
* (e.g. `module.featureFlags.set('my-flag', true)`).
|
|
660
661
|
*/
|
|
661
662
|
get featureFlags(): FakeFeatureFlagService;
|
|
663
|
+
/**
|
|
664
|
+
* The default `ctx.cache` stub — present unless this module was compiled
|
|
665
|
+
* with `cache: false`. Assert `@PurgesCache` routes purged what they should
|
|
666
|
+
* via `module.cache.purges`, in call order.
|
|
667
|
+
*
|
|
668
|
+
* @throws {TestSetupError} This module was compiled with `cache: false`,
|
|
669
|
+
* so there is no stub to inspect.
|
|
670
|
+
*/
|
|
671
|
+
get cache(): TestWorkersCache;
|
|
672
|
+
/**
|
|
673
|
+
* The default `ctx.exports` stub — present unless this module was compiled
|
|
674
|
+
* with `cache: false`.
|
|
675
|
+
*
|
|
676
|
+
* Assert which requests the response-cache gateway forwarded to the cached
|
|
677
|
+
* entrypoint, and with which resolved partitions, via
|
|
678
|
+
* `module.gateway.loopbacks` — in call order, mirroring
|
|
679
|
+
* `module.cache.purges`. An empty `loopbacks` is the assertion for every
|
|
680
|
+
* fail-closed case: an unresolved partition, a non-GET, or a `@Cacheable`
|
|
681
|
+
* route with no `partitionBy` all run inline and never appear here.
|
|
682
|
+
*
|
|
683
|
+
* @throws {TestSetupError} This module was compiled with `cache: false`,
|
|
684
|
+
* so there is no stub to inspect.
|
|
685
|
+
*/
|
|
686
|
+
get gateway(): TestWorkerExports;
|
|
662
687
|
/**
|
|
663
688
|
* Create a WebSocket test request builder for the given path
|
|
664
689
|
*/
|
|
@@ -683,6 +708,12 @@ declare class TestingModule {
|
|
|
683
708
|
* Execute an HTTP request through HonoApp
|
|
684
709
|
*/
|
|
685
710
|
fetch(request: Request): Promise<Response>;
|
|
711
|
+
/**
|
|
712
|
+
* Drain background work the most recent request(s) deferred via `ctx.waitUntil`, including any
|
|
713
|
+
* follow-up tasks those tasks enqueue. Settles each (errors are surfaced by the work itself, not
|
|
714
|
+
* here) so deferred side-effects don't outlive the request that triggered them.
|
|
715
|
+
*/
|
|
716
|
+
private flushDeferredWork;
|
|
686
717
|
/**
|
|
687
718
|
* Run callback in request scope (for DB operations, service access)
|
|
688
719
|
*/
|
|
@@ -693,9 +724,10 @@ declare class TestingModule {
|
|
|
693
724
|
getDb(): DatabaseService;
|
|
694
725
|
getDb<K extends ConnectionName>(name: K): DatabaseService<K>;
|
|
695
726
|
/**
|
|
696
|
-
* Truncate
|
|
727
|
+
* Truncate mutable tables in the connection's schema(s), honoring a preserve-list.
|
|
728
|
+
* Migration bookkeeping (`_prisma%`) is always preserved.
|
|
697
729
|
*/
|
|
698
|
-
truncateDb(name?: ConnectionName): Promise<void>;
|
|
730
|
+
truncateDb(name?: ConnectionName, opts?: ResetOptions): Promise<void>;
|
|
699
731
|
/**
|
|
700
732
|
* Run seeders by class constructor in the request-scoped container
|
|
701
733
|
*/
|
|
@@ -745,11 +777,40 @@ interface TestingModuleConfig extends ModuleOptions {
|
|
|
745
777
|
* `initialize()` (before overrides apply).
|
|
746
778
|
*/
|
|
747
779
|
exceptionHandler?: Constructor<ExceptionHandler>;
|
|
780
|
+
/**
|
|
781
|
+
* Trailing-slash canonicalisation. Mirrors `ApplicationConfig.trailingSlash`,
|
|
782
|
+
* so it takes the same bare mode or `{ mode, exclude }` object. Defaults to
|
|
783
|
+
* the framework default, `'ignore'`.
|
|
784
|
+
*
|
|
785
|
+
* A testing module builds its own `Application` and never runs the app's
|
|
786
|
+
* entry file, so an app that canonicalises URLs there only does so in
|
|
787
|
+
* production unless its suite repeats the setting here. Left unset, every
|
|
788
|
+
* route assertion checks a URL shape that configuration would never emit,
|
|
789
|
+
* and neither the 308 redirect nor any `exclude` entry is exercised.
|
|
790
|
+
*/
|
|
791
|
+
trailingSlash?: ApplicationConfig['trailingSlash'];
|
|
792
|
+
/**
|
|
793
|
+
* URI versioning. Mirrors `ApplicationConfig.versioning`, and is subject to
|
|
794
|
+
* the same constraint as {@link TestingModuleConfig.trailingSlash}: unset,
|
|
795
|
+
* routes register at their unversioned path, which an app configuring a
|
|
796
|
+
* version prefix never serves.
|
|
797
|
+
*/
|
|
798
|
+
versioning?: ApplicationConfig['versioning'];
|
|
799
|
+
/**
|
|
800
|
+
* Set to `false` to compile without a `ctx.cache` stub, reproducing a
|
|
801
|
+
* runtime where Workers Caching is genuinely unconfigured. Neither
|
|
802
|
+
* Miniflare nor workerd populates `ExecutionContext.cache` on its own, so by
|
|
803
|
+
* default `@stratal/testing` supplies a stub — a `@Cacheable`/`@PurgesCache`
|
|
804
|
+
* route otherwise 500s on its very first request (`ResponseCacheConfigError`).
|
|
805
|
+
* `cache: false` opts back into that failure, for testing the boot guard
|
|
806
|
+
* itself. See {@link TestWorkersCache}, exposed via `module.cache`.
|
|
807
|
+
*/
|
|
808
|
+
cache?: false;
|
|
748
809
|
}
|
|
749
810
|
/**
|
|
750
811
|
* Builder for creating test modules with provider overrides
|
|
751
812
|
*/
|
|
752
|
-
declare class TestingModuleBuilder {
|
|
813
|
+
export declare class TestingModuleBuilder {
|
|
753
814
|
private config;
|
|
754
815
|
private overrides;
|
|
755
816
|
constructor(config: TestingModuleConfig);
|
|
@@ -775,15 +836,13 @@ declare class TestingModuleBuilder {
|
|
|
775
836
|
*/
|
|
776
837
|
compile(): Promise<TestingModule>;
|
|
777
838
|
/**
|
|
778
|
-
*
|
|
779
|
-
*
|
|
780
|
-
*
|
|
781
|
-
* `stratalTest({ database
|
|
782
|
-
*
|
|
783
|
-
* isolation is off. Throws if isolation is on but the binding is missing — a
|
|
784
|
-
* misconfiguration, not a case to skip.
|
|
839
|
+
* Point this app's Hyperdrive binding at the database this file leased,
|
|
840
|
+
* leasing it on the file's first compile. Returns nothing to clean up — the
|
|
841
|
+
* lease ends with the isolate. No-op when the consumer didn't opt into
|
|
842
|
+
* `stratalTest({ database })`; throws if they did but no connection string is
|
|
843
|
+
* configured (a misconfiguration that would otherwise silently skip isolation).
|
|
785
844
|
*/
|
|
786
|
-
private
|
|
845
|
+
private attachWorkerDatabase;
|
|
787
846
|
/**
|
|
788
847
|
* Create a test root module with the given options
|
|
789
848
|
*/
|
|
@@ -814,7 +873,7 @@ interface ProviderOverrideConfig<T = unknown> {
|
|
|
814
873
|
* .compile()
|
|
815
874
|
* ```
|
|
816
875
|
*/
|
|
817
|
-
declare class ProviderOverrideBuilder<T> {
|
|
876
|
+
export declare class ProviderOverrideBuilder<T> {
|
|
818
877
|
private readonly parent;
|
|
819
878
|
private readonly token;
|
|
820
879
|
constructor(parent: TestingModuleBuilder, token: InjectionToken<T>);
|
|
@@ -887,7 +946,7 @@ declare class ProviderOverrideBuilder<T> {
|
|
|
887
946
|
* .compile()
|
|
888
947
|
* ```
|
|
889
948
|
*/
|
|
890
|
-
declare class Test {
|
|
949
|
+
export declare class Test {
|
|
891
950
|
/**
|
|
892
951
|
* Base modules to include in all test modules
|
|
893
952
|
* Set once in vitest.setup.ts
|
|
@@ -917,11 +976,11 @@ declare class Test {
|
|
|
917
976
|
/**
|
|
918
977
|
* Get value at dot-notation path.
|
|
919
978
|
*/
|
|
920
|
-
declare function getValueAtPath(obj: unknown, path: string): unknown;
|
|
979
|
+
export declare function getValueAtPath(obj: unknown, path: string): unknown;
|
|
921
980
|
/**
|
|
922
981
|
* Check if a path exists in the object (even if value is null/undefined).
|
|
923
982
|
*/
|
|
924
|
-
declare function hasValueAtPath(obj: unknown, path: string): boolean;
|
|
983
|
+
export declare function hasValueAtPath(obj: unknown, path: string): boolean;
|
|
925
984
|
//#endregion
|
|
926
985
|
//#region src/core/http/fetch-mock.types.d.ts
|
|
927
986
|
/**
|
|
@@ -999,7 +1058,7 @@ interface MockErrorOptions {
|
|
|
999
1058
|
* })
|
|
1000
1059
|
* ```
|
|
1001
1060
|
*/
|
|
1002
|
-
declare class MockFetch {
|
|
1061
|
+
export declare class MockFetch {
|
|
1003
1062
|
private server;
|
|
1004
1063
|
constructor(handlers?: RequestHandler[]);
|
|
1005
1064
|
/** Start intercepting. Call in beforeAll/beforeEach. */
|
|
@@ -1057,7 +1116,7 @@ declare class MockFetch {
|
|
|
1057
1116
|
* afterAll(() => mock.close())
|
|
1058
1117
|
* ```
|
|
1059
1118
|
*/
|
|
1060
|
-
declare function createMockFetch(handlers?: RequestHandler[]): MockFetch;
|
|
1119
|
+
export declare function createMockFetch(handlers?: RequestHandler[]): MockFetch;
|
|
1061
1120
|
//#endregion
|
|
1062
1121
|
//#region src/auth/acting-as.d.ts
|
|
1063
1122
|
/**
|
|
@@ -1072,7 +1131,7 @@ declare function createMockFetch(handlers?: RequestHandler[]): MockFetch;
|
|
|
1072
1131
|
* const headers = await actingAs.createSessionForUser({ id: 'user-123' })
|
|
1073
1132
|
* ```
|
|
1074
1133
|
*/
|
|
1075
|
-
declare class ActingAs {
|
|
1134
|
+
export declare class ActingAs {
|
|
1076
1135
|
private readonly authService;
|
|
1077
1136
|
constructor(authService: AuthService);
|
|
1078
1137
|
createSessionForUser(user: {
|
|
@@ -1085,7 +1144,7 @@ declare class ActingAs {
|
|
|
1085
1144
|
* Base error class for all test framework errors.
|
|
1086
1145
|
* Extends from Error and allows easy identification via `instanceof`.
|
|
1087
1146
|
*/
|
|
1088
|
-
declare class TestError extends Error {
|
|
1147
|
+
export declare class TestError extends Error {
|
|
1089
1148
|
readonly cause?: Error | undefined;
|
|
1090
1149
|
constructor(message: string, cause?: Error | undefined);
|
|
1091
1150
|
}
|
|
@@ -1095,9 +1154,9 @@ declare class TestError extends Error {
|
|
|
1095
1154
|
* Error thrown when test setup fails.
|
|
1096
1155
|
* Examples: schema creation failure, migration failure, application bootstrap failure.
|
|
1097
1156
|
*/
|
|
1098
|
-
declare class TestSetupError extends TestError {
|
|
1157
|
+
export declare class TestSetupError extends TestError {
|
|
1099
1158
|
constructor(message: string, cause?: Error);
|
|
1100
1159
|
}
|
|
1101
1160
|
//#endregion
|
|
1102
|
-
export {
|
|
1161
|
+
export { HttpResponse, type MockErrorOptions, type MockJsonOptions, type ProviderOverrideConfig, type TestSseEvent, type TestingModuleConfig, http };
|
|
1103
1162
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/core/http/test-response.ts","../src/core/http/test-http-request.ts","../src/core/http/test-http-client.ts","../src/core/quarry/test-command-result.ts","../src/core/quarry/test-command-request.ts","../src/core/sse/test-sse-connection.ts","../src/core/sse/test-sse-request.ts","../src/core/ws/test-ws-connection.ts","../src/core/ws/test-ws-request.ts","../src/core/testing-module.ts","../src/core/testing-module-builder.ts","../src/core/override/provider-override-builder.ts","../src/core/test.ts","../src/core/http/path-utils.ts","../src/core/http/fetch-mock.types.ts","../src/core/http/mock-fetch.ts","../src/auth/acting-as.ts","../src/errors/test-error.ts","../src/errors/setup-error.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/core/http/test-response.ts","../src/core/http/test-http-request.ts","../src/core/http/test-http-client.ts","../src/core/quarry/test-command-result.ts","../src/core/quarry/test-command-request.ts","../src/core/sse/test-sse-connection.ts","../src/core/sse/test-sse-request.ts","../src/core/ws/test-ws-connection.ts","../src/core/ws/test-ws-request.ts","../src/core/testing-module.ts","../src/core/testing-module-builder.ts","../src/core/override/provider-override-builder.ts","../src/core/test.ts","../src/core/http/path-utils.ts","../src/core/http/fetch-mock.types.ts","../src/core/http/mock-fetch.ts","../src/auth/acting-as.ts","../src/errors/test-error.ts","../src/errors/setup-error.ts"],"mappings":"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"}
|