@stratal/testing 0.0.22 → 0.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -16
- package/dist/database/index.d.mts +2 -0
- package/dist/database/index.mjs +2 -0
- package/dist/database-B02eYKhE.mjs +334 -0
- package/dist/database-B02eYKhE.mjs.map +1 -0
- package/dist/decorate-B7nr7eBl.mjs +9 -0
- package/dist/feature-flags/index.d.mts +2 -0
- package/dist/feature-flags/index.mjs +2 -0
- package/dist/feature-flags-BiLhfSGh.mjs +86 -0
- package/dist/feature-flags-BiLhfSGh.mjs.map +1 -0
- package/dist/index-BIr5nLof.d.mts +122 -0
- package/dist/index-BIr5nLof.d.mts.map +1 -0
- package/dist/{index-D-Q2cR2v.d.mts → index-CrHzUDKX.d.mts} +1 -1
- package/dist/index-CrHzUDKX.d.mts.map +1 -0
- package/dist/index-qgWNJRdC.d.mts +65 -0
- package/dist/index-qgWNJRdC.d.mts.map +1 -0
- package/dist/index.d.mts +29 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +95 -65
- package/dist/index.mjs.map +1 -1
- package/dist/mocks/zenstack-language.d.mts.map +1 -1
- package/dist/mocks/zenstack-language.mjs.map +1 -1
- package/dist/storage/index.d.mts +2 -2
- package/dist/storage/index.mjs +1 -1
- package/dist/{storage-BXOfzNKK.mjs → storage-DhoxWqyF.mjs} +4 -11
- package/dist/{storage-BXOfzNKK.mjs.map → storage-DhoxWqyF.mjs.map} +1 -1
- package/dist/vitest-plugin/index.d.mts +41 -5
- package/dist/vitest-plugin/index.d.mts.map +1 -1
- package/dist/vitest-plugin/index.mjs +29 -9
- package/dist/vitest-plugin/index.mjs.map +1 -1
- package/package.json +26 -16
- package/dist/index-D-Q2cR2v.d.mts.map +0 -1
- package/dist/mocks/nodemailer.d.mts +0 -12
- package/dist/mocks/nodemailer.d.mts.map +0 -1
- package/dist/mocks/nodemailer.mjs +0 -7
- package/dist/mocks/nodemailer.mjs.map +0 -1
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
//#region src/database/test-database.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Test database isolation helpers.
|
|
4
|
+
*
|
|
5
|
+
* Implements database-per-test-file isolation for parallel e2e runs against
|
|
6
|
+
* Postgres. A migrated **template** database is built once in global setup;
|
|
7
|
+
* each test file clones it instantly via `CREATE DATABASE ... TEMPLATE` and
|
|
8
|
+
* drops it on teardown. See `@stratal/testing/database`.
|
|
9
|
+
*
|
|
10
|
+
* `pg` is imported dynamically so this module loads without it — consumers
|
|
11
|
+
* that don't use a database never pay the dependency.
|
|
12
|
+
*/
|
|
13
|
+
/** Postgres isolation mode for tests. */
|
|
14
|
+
type DatabaseIsolation = 'shared' | 'database';
|
|
15
|
+
/** Env var that selects the isolation mode (single source of truth). */
|
|
16
|
+
declare const ISOLATION_ENV_VAR = "STRATAL_TEST_DB_ISOLATION";
|
|
17
|
+
/** Env var carrying the name of the Hyperdrive binding to isolate. */
|
|
18
|
+
declare const BINDING_ENV_VAR = "STRATAL_TEST_DB_BINDING";
|
|
19
|
+
/** Default Hyperdrive binding name when none is configured. */
|
|
20
|
+
declare const DEFAULT_DB_BINDING = "DB";
|
|
21
|
+
/**
|
|
22
|
+
* Normalize an isolation value (from an option or env var) to a mode.
|
|
23
|
+
* Anything other than the literal `'database'` resolves to `'shared'` — the
|
|
24
|
+
* default — so parallel isolation is strictly opt-in.
|
|
25
|
+
*/
|
|
26
|
+
declare function normalizeIsolation(value: string | undefined): DatabaseIsolation;
|
|
27
|
+
/**
|
|
28
|
+
* Derive an admin connection string pointing at the `postgres` maintenance
|
|
29
|
+
* database. `CREATE`/`DROP DATABASE` cannot run on a connection bound to the
|
|
30
|
+
* target database, so administration always goes through `postgres`.
|
|
31
|
+
*/
|
|
32
|
+
declare function deriveAdminConnectionString(connectionString: string): string;
|
|
33
|
+
/** Build a connection string identical to `base` but pointing at `dbName`. */
|
|
34
|
+
declare function buildConnectionString(base: string, dbName: string): string;
|
|
35
|
+
/** The shared prefix for per-file databases, used as the leak-sweep key. */
|
|
36
|
+
declare function databasePrefix(base: string): string;
|
|
37
|
+
/** Name of the migrated template database cloned per file. */
|
|
38
|
+
declare function deriveTemplateName(base: string): string;
|
|
39
|
+
/**
|
|
40
|
+
* Generate a unique per-`compile()` database name. Random (not path-based) so
|
|
41
|
+
* it is collision-free across concurrent isolates and multiple modules in the
|
|
42
|
+
* same file, and stays well within Postgres' 63-char identifier limit.
|
|
43
|
+
*/
|
|
44
|
+
declare function deriveDbName(base: string): string;
|
|
45
|
+
/**
|
|
46
|
+
* Clone the template database into `dbName`. `CREATE DATABASE ... TEMPLATE`
|
|
47
|
+
* fails (SQLSTATE 55006) if any session is connected to the template, so we
|
|
48
|
+
* proactively terminate lingering template backends before each attempt and
|
|
49
|
+
* retry with exponential backoff while a concurrent clone briefly locks it.
|
|
50
|
+
*/
|
|
51
|
+
declare function createDatabaseFromTemplate(adminConn: string, dbName: string, template: string, attempts?: number): Promise<void>;
|
|
52
|
+
/** Drop a database, terminating any lingering connections. */
|
|
53
|
+
declare function dropDatabase(adminConn: string, dbName: string): Promise<void>;
|
|
54
|
+
/** Options for {@link createTestDatabaseGlobalSetup}. */
|
|
55
|
+
interface TestDatabaseGlobalSetupOptions {
|
|
56
|
+
/**
|
|
57
|
+
* Run migrations against the given connection string. In `'database'` mode
|
|
58
|
+
* the string points at the template database; in `'shared'` mode at the base
|
|
59
|
+
* database. Framework consumers typically run `zenstack db push` here.
|
|
60
|
+
*/
|
|
61
|
+
migrate: (connectionString: string) => void | Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Schema source(s) — a file or directory path, or a list of them. Their
|
|
64
|
+
* contents (plus the `migrate` routine) are hashed into a fingerprint; the
|
|
65
|
+
* template is reused across runs while the fingerprint is unchanged and
|
|
66
|
+
* rebuilt + re-migrated when it changes, so only the first run after a schema
|
|
67
|
+
* edit pays the migration cost. **Required** for `'database'` isolation.
|
|
68
|
+
*
|
|
69
|
+
* For a ZenStack multi-file schema, pass the **root `.zmodel`** — its `import`
|
|
70
|
+
* graph is followed, so editing any imported file invalidates the fingerprint.
|
|
71
|
+
* A directory path hashes every `.zmodel`/`.prisma`/`.sql` file in its tree.
|
|
72
|
+
*/
|
|
73
|
+
schema?: string | string[];
|
|
74
|
+
/** Isolation mode. Defaults to {@link ISOLATION_ENV_VAR} or `'shared'`. */
|
|
75
|
+
isolation?: DatabaseIsolation;
|
|
76
|
+
/** Base/admin connection string. Defaults to `process.env.DATABASE_URL`. */
|
|
77
|
+
connectionString?: string;
|
|
78
|
+
/** Template database name. Defaults to `<baseDbName>_template`. */
|
|
79
|
+
templateName?: string;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Build a Vitest `globalSetup` default export that prepares the test database.
|
|
83
|
+
*
|
|
84
|
+
* - `'shared'` (default): migrates the base database in place (no isolation).
|
|
85
|
+
* - `'database'`: under a Postgres advisory lock (so concurrent setups across
|
|
86
|
+
* CI shards / multiple e2e projects don't clobber each other), sweeps leaked
|
|
87
|
+
* per-file databases, then ensures a migrated template exists — ready to be
|
|
88
|
+
* cloned per test file.
|
|
89
|
+
*
|
|
90
|
+
* **Template reuse.** The template is fingerprinted from the `schema` source(s)
|
|
91
|
+
* + the `migrate` routine and the fingerprint is stored as the template's
|
|
92
|
+
* database COMMENT. On each run, a matching fingerprint means the schema is
|
|
93
|
+
* unchanged and the existing template is reused as-is — `migrate` runs **only**
|
|
94
|
+
* on the first run after a schema edit (or on a fresh database). The fingerprint
|
|
95
|
+
* is stamped only after a successful migrate, so a match always implies a
|
|
96
|
+
* complete template; there is no force/skip flag — reuse is purely fingerprint-
|
|
97
|
+
* driven.
|
|
98
|
+
*
|
|
99
|
+
* **Concurrency model.** The reuse check + rebuild runs under
|
|
100
|
+
* `pg_advisory_lock(hashtext(<template>))`, so only one process rebuilds the
|
|
101
|
+
* template at a time. The stale-database sweep only drops per-file databases
|
|
102
|
+
* with **no active connections**, leaving a sibling process's live databases
|
|
103
|
+
* intact. Teardown deliberately does **not** sweep or drop the template: a
|
|
104
|
+
* concurrent process may still be using both, and the next run's setup sweep is
|
|
105
|
+
* the backstop for any leak.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* // test/global-setup.ts
|
|
110
|
+
* import { createTestDatabaseGlobalSetup } from '@stratal/testing/database'
|
|
111
|
+
*
|
|
112
|
+
* export default createTestDatabaseGlobalSetup({
|
|
113
|
+
* schema: schemaPath, // file or directory — reused-when-unchanged fingerprint
|
|
114
|
+
* migrate: (conn) => execFileSync(zenstackBin, ['db', 'push', '--force-reset', `--schema=${schemaPath}`, '--accept-data-loss'],
|
|
115
|
+
* { env: { ...process.env, DATABASE_URL: conn }, stdio: 'inherit' }),
|
|
116
|
+
* })
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
declare function createTestDatabaseGlobalSetup(opts: TestDatabaseGlobalSetupOptions): () => Promise<void | (() => Promise<void>)>;
|
|
120
|
+
//#endregion
|
|
121
|
+
export { TestDatabaseGlobalSetupOptions as a, createTestDatabaseGlobalSetup as c, deriveDbName as d, deriveTemplateName as f, ISOLATION_ENV_VAR as i, databasePrefix as l, normalizeIsolation as m, DEFAULT_DB_BINDING as n, buildConnectionString as o, dropDatabase as p, DatabaseIsolation as r, createDatabaseFromTemplate as s, BINDING_ENV_VAR as t, deriveAdminConnectionString as u };
|
|
122
|
+
//# sourceMappingURL=index-BIr5nLof.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-BIr5nLof.d.mts","names":[],"sources":["../src/database/test-database.ts"],"mappings":";;AAmBA;;;;AAA6B;AAG7B;;;;AAA8B;AAG9B;AAAA,KANY,iBAAA;;cAGC,iBAAA;AAGe;AAAA,cAAf,eAAA;;cAGA,kBAAA;;AAAkB;AAO/B;;;iBAAgB,kBAAA,CAAmB,KAAA,uBAA4B,iBAAiB;AAAA;AAkEhF;;;;AAlEgF,iBAkEhE,2BAAA,CAA4B,gBAAwB;AAOpE;AAAA,iBAAgB,qBAAA,CAAsB,IAAA,UAAc,MAAc;;iBAUlD,cAAA,CAAe,IAAY;AAVuB;AAAA,iBAoBlD,kBAAA,CAAmB,IAAY;;;;AAVJ;AAU3C;iBAWgB,YAAA,CAAa,IAAY;;;AAXM;AAW/C;;;iBA0CsB,0BAAA,CACpB,SAAA,UACA,MAAA,UACA,QAAA,UACA,QAAA,YACC,OAAO;AA/C+B;AAAA,iBAoEnB,YAAA,CAAa,SAAA,UAAmB,MAAA,WAAiB,OAAO;;UAqJ7D,8BAAA;EA1KP;;;;;EAgLR,OAAA,GAAU,gBAAA,oBAAoC,OAAA;EAhLtC;AAAA;AAqBV;;;;;;;;AAA8E;EAuK5E,MAAA;EAlB6C;EAoB7C,SAAA,GAAY,iBAAiB;EAAA;EAE7B,gBAAA;EAhBU;EAkBV,YAAA;AAAA;;;;;;AAAY;AAyCd;;;;;;;;;;;;;AAEsC;;;;;;;;;;;;;;;;;;;iBAFtB,6BAAA,CACd,IAAA,EAAM,8BAAA,SACC,OAAA,eAAsB,OAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-CrHzUDKX.d.mts","names":[],"sources":["../src/storage/fake-storage.service.ts"],"mappings":";;;;;AAkBA;UAAiB,UAAA;EACf,OAAA,EAAS,UAAA;EACT,QAAA;EACA,IAAA;EACA,QAAA,GAAW,MAAA;EACX,UAAA,EAAY,IAAA;AAAA;;;;;;;;;;AAAI;AAoBlB;;;;;;;cACa,kBAAA,SAA2B,cAAA;EAAA,mBAKjB,cAAA,EAAgB,qBAAA;EAAA,mBAEhB,OAAA,EAAS,aAAA;EAAA,QANtB,KAAA;cAIa,cAAA,EAAgB,qBAAA,EAEhB,OAAA,EAAS,aAAA;EAsCN;;;EA9BlB,MAAA,CACJ,IAAA,EAAM,8BAAA,EACN,YAAA,UACA,OAAA,EAAS,aAAA,EACT,IAAA,YACC,OAAA,CAAQ,YAAA;EAoER;;;EA3CH,QAAA,CAAS,IAAA,WAAe,OAAA,CAAQ,cAAA;EA+D7B;;;EAtCH,MAAA,CAAO,IAAA,WAAe,OAAA;EAkDX;;;EA1CX,MAAA,CAAO,IAAA,WAAe,OAAA;EAyHC;;;EAlHvB,uBAAA,CACE,IAAA,UACA,SAAA,YACC,OAAA,CAAQ,kBAAA;EAxF2B;;;EA+FtC,qBAAA,CACE,IAAA,UACA,SAAA,YACC,OAAA,CAAQ,kBAAA;EA3FmB;;;EAkG9B,qBAAA,CACE,IAAA,UACA,SAAA,YACC,OAAA,CAAQ,kBAAA;EAvGU;;;EA8Gf,aAAA,CACJ,IAAA,EAAM,8BAAA,EACN,IAAA,UACA,OAAA,EAAS,IAAA,CAAK,aAAA;IAA2B,IAAA;EAAA,GACzC,IAAA,YACC,OAAA,CAAQ,YAAA;EAvGT;;;;;;EAwHF,YAAA,CAAa,IAAA;EA5FJ;;;;;;EAyGT,aAAA,CAAc,IAAA;EAxEP;;;;;EAoFP,WAAA;EA1EW;;;;;;EAuFX,WAAA,CAAY,KAAA;EArEV;;;EA+EF,cAAA,IAAkB,GAAA,SAAY,UAAA;EAtExB;;;EA6EN,cAAA;EA1EW;;;EAiFX,OAAA,CAAQ,IAAA,WAAe,UAAA;EAhFrB;;;EAuFF,KAAA;EAAA,QAQQ,kBAAA;EAAA,QAeM,gBAAA;AAAA"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
//#region src/feature-flags/fake-feature-flag.service.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Global DI token for the feature-flags service.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors `FEATURE_FLAG_TOKENS.FeatureFlagService` from `@stratal/feature-flags`
|
|
6
|
+
* — `Symbol.for(...)` resolves to the same symbol across packages via the global
|
|
7
|
+
* registry. Declared here so `@stratal/testing` needs no dependency on the
|
|
8
|
+
* optional feature-flags package. Keep this string in sync with
|
|
9
|
+
* `packages/feature-flags/src/feature-flags.tokens.ts`.
|
|
10
|
+
*/
|
|
11
|
+
declare const FEATURE_FLAG_SERVICE_TOKEN: unique symbol;
|
|
12
|
+
/** A value a feature flag can resolve to. */
|
|
13
|
+
type FlagValue = boolean | string | number | object;
|
|
14
|
+
interface FakeFlagDetails<T> {
|
|
15
|
+
flagKey: string;
|
|
16
|
+
value: T;
|
|
17
|
+
reason: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* FakeFeatureFlagService
|
|
21
|
+
*
|
|
22
|
+
* In-memory stand-in for `@stratal/feature-flags`'s request-scoped
|
|
23
|
+
* `FeatureFlagService`, auto-registered by the testing module so feature-gated
|
|
24
|
+
* code resolves without a real Cloudflare Flagship binding (which only exists at
|
|
25
|
+
* runtime). Mirrors the real service's public evaluation surface.
|
|
26
|
+
*
|
|
27
|
+
* Unset flags return the per-call default (or the type's zero value). Configure
|
|
28
|
+
* values with {@link set} / {@link setAll}; access it in tests via
|
|
29
|
+
* `module.featureFlags`.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* module.featureFlags.set('new-checkout', true)
|
|
34
|
+
* const enabled = await flags.getBooleanValue('new-checkout') // true
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
declare class FakeFeatureFlagService {
|
|
38
|
+
private readonly flags;
|
|
39
|
+
/** Set a single flag value. */
|
|
40
|
+
set(flagKey: string, value: FlagValue): this;
|
|
41
|
+
/** Replace all configured flags with the given map. */
|
|
42
|
+
setAll(flags: Record<string, FlagValue>): this;
|
|
43
|
+
/** Clear every configured flag. */
|
|
44
|
+
reset(): this;
|
|
45
|
+
get(flagKey: string, defaultValue?: unknown): Promise<unknown>;
|
|
46
|
+
getBooleanValue(flagKey: string, defaultValue?: boolean): Promise<boolean>;
|
|
47
|
+
getStringValue(flagKey: string, defaultValue?: string): Promise<string>;
|
|
48
|
+
getNumberValue(flagKey: string, defaultValue?: number): Promise<number>;
|
|
49
|
+
getObjectValue<T extends object>(flagKey: string, defaultValue?: T): Promise<T>;
|
|
50
|
+
getBooleanDetails(flagKey: string, defaultValue?: boolean): Promise<FakeFlagDetails<boolean>>;
|
|
51
|
+
getStringDetails(flagKey: string, defaultValue?: string): Promise<FakeFlagDetails<string>>;
|
|
52
|
+
getNumberDetails(flagKey: string, defaultValue?: number): Promise<FakeFlagDetails<number>>;
|
|
53
|
+
getObjectDetails<T extends object>(flagKey: string, defaultValue?: T): Promise<FakeFlagDetails<T>>;
|
|
54
|
+
/** Returns every configured flag as a `{ key: value }` map. */
|
|
55
|
+
all(): Promise<Record<string, FlagValue>>;
|
|
56
|
+
/** Switching Flagship apps is a no-op in the fake. */
|
|
57
|
+
use(): this;
|
|
58
|
+
/** The binding name this instance targets. */
|
|
59
|
+
get app(): string;
|
|
60
|
+
private resolve;
|
|
61
|
+
private details;
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
export { FakeFeatureFlagService as n, FlagValue as r, FEATURE_FLAG_SERVICE_TOKEN as t };
|
|
65
|
+
//# sourceMappingURL=index-qgWNJRdC.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-qgWNJRdC.d.mts","names":[],"sources":["../src/feature-flags/fake-feature-flag.service.ts"],"mappings":";;AAWA;;;;AAAqF;AAGrF;;;cAHa,0BAAA;AAGQ;AAAA,KAAT,SAAA;AAAA,UAEF,eAAA;EACR,OAAA;EACA,KAAA,EAAO,CAAC;EACR,MAAA;AAAA;;;;;AAAM;AAqBR;;;;;;;;;;;;;cACa,sBAAA;EAAA,iBACM,KAAA;EAiDmD;EA5CpE,GAAA,CAAI,OAAA,UAAiB,KAAA,EAAO,SAAA;EAgDuC;EA1CnE,MAAA,CAAO,KAAA,EAAO,MAAA,SAAe,SAAA;EA8C2C;EAvCxE,KAAA;EAOM,GAAA,CAAI,OAAA,UAAiB,YAAA,aAAyB,OAAA;EAI9C,eAAA,CAAgB,OAAA,UAAiB,YAAA,aAAuB,OAAA;EAIxD,cAAA,CAAe,OAAA,UAAiB,YAAA,YAAoB,OAAA;EAIpD,cAAA,CAAe,OAAA,UAAiB,YAAA,YAAmB,OAAA;EAInD,cAAA,mBAAiC,OAAA,UAAiB,YAAA,GAAc,CAAA,GAAc,OAAA,CAAQ,CAAA;EAItF,iBAAA,CAAkB,OAAA,UAAiB,YAAA,aAAuB,OAAA,CAAQ,eAAA;EAIlE,gBAAA,CAAiB,OAAA,UAAiB,YAAA,YAAoB,OAAA,CAAQ,eAAA;EAI9D,gBAAA,CAAiB,OAAA,UAAiB,YAAA,YAAmB,OAAA,CAAQ,eAAA;EAI7D,gBAAA,mBAAmC,OAAA,UAAiB,YAAA,GAAc,CAAA,GAAc,OAAA,CAAQ,eAAA,CAAgB,CAAA;EApD1G;EAyDE,GAAA,IAAO,OAAA,CAAQ,MAAA,SAAe,SAAA;EAzDf;EA8DrB,GAAA;EAxDc;EAAA,IA8DV,GAAA;EAAA,QAMI,OAAA;EAAA,QAIA,OAAA;AAAA"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as FakeFeatureFlagService } from "./index-qgWNJRdC.mjs";
|
|
2
|
+
import { t as FakeStorageService } from "./index-CrHzUDKX.mjs";
|
|
2
3
|
import { Application, ApplicationConfig, Constructor, StratalEnv, StratalExecutionContext } from "stratal";
|
|
3
4
|
import { DynamicModule, InjectionToken, ModuleClass, ModuleOptions } from "stratal/module";
|
|
4
5
|
import { Container } from "stratal/di";
|
|
@@ -611,13 +612,24 @@ declare class TestWsRequest {
|
|
|
611
612
|
* await module.close()
|
|
612
613
|
* ```
|
|
613
614
|
*/
|
|
615
|
+
/**
|
|
616
|
+
* Identifies a per-file database created for test isolation, so it can be
|
|
617
|
+
* dropped on teardown. Produced by the testing module builder.
|
|
618
|
+
*/
|
|
619
|
+
interface IsolatedDatabase {
|
|
620
|
+
/** Name of the cloned database. */
|
|
621
|
+
name: string;
|
|
622
|
+
/** Admin (maintenance-database) connection string used to drop it. */
|
|
623
|
+
adminConnectionString: string;
|
|
624
|
+
}
|
|
614
625
|
declare class TestingModule {
|
|
615
626
|
private readonly app;
|
|
616
627
|
private readonly env;
|
|
617
628
|
private readonly ctx;
|
|
629
|
+
private readonly isolatedDatabase;
|
|
618
630
|
private _http;
|
|
619
631
|
private readonly _requestContainer;
|
|
620
|
-
constructor(app: Application, env: StratalEnv, ctx: StratalExecutionContext);
|
|
632
|
+
constructor(app: Application, env: StratalEnv, ctx: StratalExecutionContext, isolatedDatabase?: IsolatedDatabase | null);
|
|
621
633
|
/**
|
|
622
634
|
* Resolve a service from the container
|
|
623
635
|
*/
|
|
@@ -634,6 +646,11 @@ declare class TestingModule {
|
|
|
634
646
|
* Get fake storage service for assertions
|
|
635
647
|
*/
|
|
636
648
|
get storage(): FakeStorageService;
|
|
649
|
+
/**
|
|
650
|
+
* Get the fake feature-flag service to configure flags in tests
|
|
651
|
+
* (e.g. `module.featureFlags.set('my-flag', true)`).
|
|
652
|
+
*/
|
|
653
|
+
get featureFlags(): FakeFeatureFlagService;
|
|
637
654
|
/**
|
|
638
655
|
* Create a WebSocket test request builder for the given path
|
|
639
656
|
*/
|
|
@@ -749,6 +766,16 @@ declare class TestingModuleBuilder {
|
|
|
749
766
|
* Creates the Application, applies overrides, initializes, and returns TestingModule.
|
|
750
767
|
*/
|
|
751
768
|
compile(): Promise<TestingModule>;
|
|
769
|
+
/**
|
|
770
|
+
* When `STRATAL_TEST_DB_ISOLATION=database`, create a fresh database cloned
|
|
771
|
+
* from the migrated template and rewrite the Hyperdrive binding's
|
|
772
|
+
* `connectionString` to target it. The binding name is configurable via
|
|
773
|
+
* `stratalTest({ database: { binding } })` (defaults to `DB`). Returns the
|
|
774
|
+
* created name + admin connection so `close()` can drop it, or `null` when
|
|
775
|
+
* isolation is off. Throws if isolation is on but the binding is missing — a
|
|
776
|
+
* misconfiguration, not a case to skip.
|
|
777
|
+
*/
|
|
778
|
+
private setupIsolatedDatabase;
|
|
752
779
|
/**
|
|
753
780
|
* Create a test root module with the given options
|
|
754
781
|
*/
|
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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"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as createDatabaseFromTemplate, c as deriveAdminConnectionString, d as dropDatabase, f as normalizeIsolation, i as buildConnectionString, l as deriveDbName, u as deriveTemplateName } from "./database-B02eYKhE.mjs";
|
|
2
|
+
import { t as FakeStorageService } from "./storage-DhoxWqyF.mjs";
|
|
3
|
+
import { t as __decorate } from "./decorate-B7nr7eBl.mjs";
|
|
4
|
+
import { n as FakeFeatureFlagService, t as FEATURE_FLAG_SERVICE_TOKEN } from "./feature-flags-BiLhfSGh.mjs";
|
|
2
5
|
import { Application } from "stratal";
|
|
3
6
|
import { LogLevel } from "stratal/logger";
|
|
4
7
|
import { Module } from "stratal/module";
|
|
@@ -1254,45 +1257,18 @@ var TestWsRequest = class {
|
|
|
1254
1257
|
};
|
|
1255
1258
|
//#endregion
|
|
1256
1259
|
//#region src/core/testing-module.ts
|
|
1257
|
-
/**
|
|
1258
|
-
* TestingModule
|
|
1259
|
-
*
|
|
1260
|
-
* Provides access to the test application, container, HTTP client, and utilities.
|
|
1261
|
-
*
|
|
1262
|
-
* @example
|
|
1263
|
-
* ```typescript
|
|
1264
|
-
* const module = await Test.createTestingModule({
|
|
1265
|
-
* modules: [RegistrationModule],
|
|
1266
|
-
* }).compile()
|
|
1267
|
-
*
|
|
1268
|
-
* // Make HTTP requests
|
|
1269
|
-
* const response = await module.http
|
|
1270
|
-
* .post('/api/v1/register')
|
|
1271
|
-
* .withBody({ ... })
|
|
1272
|
-
* .send()
|
|
1273
|
-
*
|
|
1274
|
-
* // Access services
|
|
1275
|
-
* const service = module.get(REGISTRATION_TOKENS.RegistrationService)
|
|
1276
|
-
*
|
|
1277
|
-
* // Database utilities
|
|
1278
|
-
* await module.truncateDb()
|
|
1279
|
-
* await module.seed(UserSeeder)
|
|
1280
|
-
* await module.assertDatabaseHas('user', { email: 'test@example.com' })
|
|
1281
|
-
*
|
|
1282
|
-
* // Cleanup
|
|
1283
|
-
* await module.close()
|
|
1284
|
-
* ```
|
|
1285
|
-
*/
|
|
1286
1260
|
var TestingModule = class {
|
|
1287
1261
|
app;
|
|
1288
1262
|
env;
|
|
1289
1263
|
ctx;
|
|
1264
|
+
isolatedDatabase;
|
|
1290
1265
|
_http = null;
|
|
1291
1266
|
_requestContainer;
|
|
1292
|
-
constructor(app, env, ctx) {
|
|
1267
|
+
constructor(app, env, ctx, isolatedDatabase = null) {
|
|
1293
1268
|
this.app = app;
|
|
1294
1269
|
this.env = env;
|
|
1295
1270
|
this.ctx = ctx;
|
|
1271
|
+
this.isolatedDatabase = isolatedDatabase;
|
|
1296
1272
|
const mockContext = this.app.createMockRouterContext();
|
|
1297
1273
|
this._requestContainer = this.app.container.createRequestScope(mockContext);
|
|
1298
1274
|
}
|
|
@@ -1325,6 +1301,13 @@ var TestingModule = class {
|
|
|
1325
1301
|
return this.get(STORAGE_TOKENS.StorageService);
|
|
1326
1302
|
}
|
|
1327
1303
|
/**
|
|
1304
|
+
* Get the fake feature-flag service to configure flags in tests
|
|
1305
|
+
* (e.g. `module.featureFlags.set('my-flag', true)`).
|
|
1306
|
+
*/
|
|
1307
|
+
get featureFlags() {
|
|
1308
|
+
return this.get(FEATURE_FLAG_SERVICE_TOKEN);
|
|
1309
|
+
}
|
|
1310
|
+
/**
|
|
1328
1311
|
* Create a WebSocket test request builder for the given path
|
|
1329
1312
|
*/
|
|
1330
1313
|
ws(path) {
|
|
@@ -1419,7 +1402,15 @@ var TestingModule = class {
|
|
|
1419
1402
|
*/
|
|
1420
1403
|
async close() {
|
|
1421
1404
|
this._requestContainer.dispose();
|
|
1422
|
-
|
|
1405
|
+
try {
|
|
1406
|
+
await this.app.shutdown();
|
|
1407
|
+
} finally {
|
|
1408
|
+
if (this.isolatedDatabase) try {
|
|
1409
|
+
await dropDatabase(this.isolatedDatabase.adminConnectionString, this.isolatedDatabase.name);
|
|
1410
|
+
} catch (error) {
|
|
1411
|
+
console.warn(`[stratal-testing] Failed to drop isolated test database "${this.isolatedDatabase.name}"; it will be reclaimed by the next run's stale-database sweep.`, error);
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1423
1414
|
}
|
|
1424
1415
|
};
|
|
1425
1416
|
//#endregion
|
|
@@ -1479,40 +1470,79 @@ var TestingModuleBuilder = class {
|
|
|
1479
1470
|
const ctx = { waitUntil: cf ? cf.waitUntil : (p) => {
|
|
1480
1471
|
p.catch(() => {});
|
|
1481
1472
|
} };
|
|
1482
|
-
const
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1473
|
+
const isolatedDb = await this.setupIsolatedDatabase(env);
|
|
1474
|
+
try {
|
|
1475
|
+
const allImports = [...Test.getBaseModules(), ...this.config.imports ?? []];
|
|
1476
|
+
const app = new Application({
|
|
1477
|
+
module: this.createTestRootModule({
|
|
1478
|
+
imports: allImports,
|
|
1479
|
+
providers: this.config.providers,
|
|
1480
|
+
controllers: this.config.controllers,
|
|
1481
|
+
consumers: this.config.consumers,
|
|
1482
|
+
jobs: this.config.jobs
|
|
1483
|
+
}),
|
|
1484
|
+
logging: {
|
|
1485
|
+
level: this.config.logging?.level ?? LogLevel.ERROR,
|
|
1486
|
+
formatter: this.config.logging?.formatter ?? "pretty"
|
|
1487
|
+
},
|
|
1488
|
+
env,
|
|
1489
|
+
ctx,
|
|
1490
|
+
exceptionHandler: this.config.exceptionHandler
|
|
1491
|
+
});
|
|
1492
|
+
await app.initialize();
|
|
1493
|
+
app.container.registerSingleton(STORAGE_TOKENS.StorageService, FakeStorageService);
|
|
1494
|
+
app.container.registerSingleton(FEATURE_FLAG_SERVICE_TOKEN, FakeFeatureFlagService);
|
|
1495
|
+
for (const override of this.overrides) switch (override.type) {
|
|
1496
|
+
case "value":
|
|
1497
|
+
app.container.registerValue(override.token, override.implementation);
|
|
1498
|
+
break;
|
|
1499
|
+
case "class":
|
|
1500
|
+
app.container.registerSingleton(override.token, override.implementation);
|
|
1501
|
+
break;
|
|
1502
|
+
case "factory":
|
|
1503
|
+
app.container.registerFactory(override.token, override.implementation);
|
|
1504
|
+
break;
|
|
1505
|
+
case "existing":
|
|
1506
|
+
app.container.registerExisting(override.token, override.implementation);
|
|
1507
|
+
break;
|
|
1508
|
+
}
|
|
1509
|
+
return new TestingModule(app, env, ctx, isolatedDb);
|
|
1510
|
+
} catch (error) {
|
|
1511
|
+
if (isolatedDb) await dropDatabase(isolatedDb.adminConnectionString, isolatedDb.name).catch(() => {});
|
|
1512
|
+
throw error;
|
|
1514
1513
|
}
|
|
1515
|
-
|
|
1514
|
+
}
|
|
1515
|
+
/**
|
|
1516
|
+
* When `STRATAL_TEST_DB_ISOLATION=database`, create a fresh database cloned
|
|
1517
|
+
* from the migrated template and rewrite the Hyperdrive binding's
|
|
1518
|
+
* `connectionString` to target it. The binding name is configurable via
|
|
1519
|
+
* `stratalTest({ database: { binding } })` (defaults to `DB`). Returns the
|
|
1520
|
+
* created name + admin connection so `close()` can drop it, or `null` when
|
|
1521
|
+
* isolation is off. Throws if isolation is on but the binding is missing — a
|
|
1522
|
+
* misconfiguration, not a case to skip.
|
|
1523
|
+
*/
|
|
1524
|
+
async setupIsolatedDatabase(env) {
|
|
1525
|
+
const bindings = env;
|
|
1526
|
+
if (normalizeIsolation(bindings["STRATAL_TEST_DB_ISOLATION"]) !== "database") return null;
|
|
1527
|
+
const bindingName = bindings["STRATAL_TEST_DB_BINDING"] ?? "DB";
|
|
1528
|
+
const db = bindings[bindingName];
|
|
1529
|
+
const base = db?.connectionString;
|
|
1530
|
+
if (!base) throw new Error(`Database isolation is 'database' but no \`${bindingName}\` Hyperdrive binding with a connectionString was found. Provide it via \`stratalTest({ miniflare: { hyperdrives: { ${bindingName} } } })\`, or set isolation to 'shared'.`);
|
|
1531
|
+
const adminConnectionString = deriveAdminConnectionString(base);
|
|
1532
|
+
const name = deriveDbName(base);
|
|
1533
|
+
await createDatabaseFromTemplate(adminConnectionString, name, deriveTemplateName(base));
|
|
1534
|
+
const isolated = Object.create(Object.getPrototypeOf(db), Object.getOwnPropertyDescriptors(db));
|
|
1535
|
+
Object.defineProperty(isolated, "connectionString", {
|
|
1536
|
+
value: buildConnectionString(base, name),
|
|
1537
|
+
enumerable: true,
|
|
1538
|
+
configurable: true,
|
|
1539
|
+
writable: true
|
|
1540
|
+
});
|
|
1541
|
+
bindings[bindingName] = isolated;
|
|
1542
|
+
return {
|
|
1543
|
+
name,
|
|
1544
|
+
adminConnectionString
|
|
1545
|
+
};
|
|
1516
1546
|
}
|
|
1517
1547
|
/**
|
|
1518
1548
|
* Create a test root module with the given options
|