@venturekit/testing 0.0.19 → 0.0.21
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 +105 -39
- package/bin/ensure-db.mjs +64 -0
- package/dist/ensure-database.d.ts +43 -0
- package/dist/ensure-database.d.ts.map +1 -0
- package/dist/ensure-database.js +76 -0
- package/dist/ensure-database.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/playwright/auth-setup.d.ts +58 -0
- package/dist/playwright/auth-setup.d.ts.map +1 -0
- package/dist/playwright/auth-setup.js +79 -0
- package/dist/playwright/auth-setup.js.map +1 -0
- package/dist/playwright/fixtures.d.ts +39 -0
- package/dist/playwright/fixtures.d.ts.map +1 -0
- package/dist/playwright/fixtures.js +46 -0
- package/dist/playwright/fixtures.js.map +1 -0
- package/dist/playwright/index.d.ts +24 -0
- package/dist/playwright/index.d.ts.map +1 -0
- package/dist/playwright/index.js +21 -0
- package/dist/playwright/index.js.map +1 -0
- package/dist/playwright/storage-state.d.ts +28 -0
- package/dist/playwright/storage-state.d.ts.map +1 -0
- package/dist/playwright/storage-state.js +40 -0
- package/dist/playwright/storage-state.js.map +1 -0
- package/dist/playwright/web-servers.d.ts +135 -0
- package/dist/playwright/web-servers.d.ts.map +1 -0
- package/dist/playwright/web-servers.js +122 -0
- package/dist/playwright/web-servers.js.map +1 -0
- package/dist/stack.d.ts +20 -0
- package/dist/stack.d.ts.map +1 -1
- package/dist/stack.js +12 -0
- package/dist/stack.js.map +1 -1
- package/dist/stage-db.d.ts +88 -0
- package/dist/stage-db.d.ts.map +1 -0
- package/dist/stage-db.js +96 -0
- package/dist/stage-db.js.map +1 -0
- package/package.json +25 -6
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-role API contexts as a Playwright fixture.
|
|
3
|
+
*
|
|
4
|
+
* A project pins one role through `use.storageState`, which covers the happy
|
|
5
|
+
* path. Authz tests need the others in the same spec — this exposes them on
|
|
6
|
+
* demand and disposes them at teardown, so no spec leaks a context.
|
|
7
|
+
*
|
|
8
|
+
* Requires the roles to have been established first; see ./auth-setup.ts.
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync } from 'node:fs';
|
|
11
|
+
import { test as base, request } from '@playwright/test';
|
|
12
|
+
import { DEFAULT_AUTH_DIR, storageStatePath } from './storage-state.js';
|
|
13
|
+
/**
|
|
14
|
+
* Build a `test` object carrying the `asRole` fixture.
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* // tests/api/fixtures.ts
|
|
18
|
+
* export const test = createVkTest();
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function createVkTest(options = {}) {
|
|
22
|
+
const authDir = options.authDir ?? DEFAULT_AUTH_DIR;
|
|
23
|
+
return base.extend({
|
|
24
|
+
asRole: async ({ baseURL }, use) => {
|
|
25
|
+
const opened = [];
|
|
26
|
+
await use(async (role) => {
|
|
27
|
+
const storageState = storageStatePath(role, authDir);
|
|
28
|
+
if (!existsSync(storageState)) {
|
|
29
|
+
throw new Error(`@venturekit/testing: no storage state for role "${role}" at ${storageState}. ` +
|
|
30
|
+
'Establish it in the setup project (establishRoles) and make this project ' +
|
|
31
|
+
"depend on it via `dependencies: ['setup']`.");
|
|
32
|
+
}
|
|
33
|
+
const context = await request.newContext({
|
|
34
|
+
baseURL: options.baseURL ?? baseURL,
|
|
35
|
+
storageState,
|
|
36
|
+
extraHTTPHeaders: options.extraHTTPHeaders ?? { Accept: 'application/json' },
|
|
37
|
+
});
|
|
38
|
+
opened.push(context);
|
|
39
|
+
return context;
|
|
40
|
+
});
|
|
41
|
+
for (const context of opened)
|
|
42
|
+
await context.dispose();
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=fixtures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixtures.js","sourceRoot":"","sources":["../../src/playwright/fixtures.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,IAAI,IAAI,EAAE,OAAO,EAA0B,MAAM,kBAAkB,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAuBxE;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,UAA+B,EAAE;IAC5D,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,gBAAgB,CAAC;IAEpD,OAAO,IAAI,CAAC,MAAM,CAAa;QAC7B,MAAM,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE;YACjC,MAAM,MAAM,GAAwB,EAAE,CAAC;YAEvC,MAAM,GAAG,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE;gBAC/B,MAAM,YAAY,GAAG,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBACrD,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;oBAC9B,MAAM,IAAI,KAAK,CACb,mDAAmD,IAAI,QAAQ,YAAY,IAAI;wBAC7E,2EAA2E;wBAC3E,6CAA6C,CAChD,CAAC;gBACJ,CAAC;gBAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC;oBACvC,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,OAAO;oBACnC,YAAY;oBACZ,gBAAgB,EAAE,OAAO,CAAC,gBAAgB,IAAI,EAAE,MAAM,EAAE,kBAAkB,EAAE;iBAC7E,CAAC,CAAC;gBACH,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACrB,OAAO,OAAO,CAAC;YACjB,CAAC,CAAC,CAAC;YAEH,KAAK,MAAM,OAAO,IAAI,MAAM;gBAAE,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QACxD,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @venturekit/testing/playwright
|
|
3
|
+
*
|
|
4
|
+
* Playwright-specific half of the harness. Import from here in
|
|
5
|
+
* `playwright.config.ts`, setup projects and specs:
|
|
6
|
+
*
|
|
7
|
+
* - `vkWebServers` — database creation + migration + `vk dev`, in the one
|
|
8
|
+
* order that works, with crons off.
|
|
9
|
+
* - `establishRoles` / `wipeAuthDir` — log every role in once, persist the
|
|
10
|
+
* cookie jars, and clear stale ones.
|
|
11
|
+
* - `storageStatePath` — where a role's jar lives.
|
|
12
|
+
* - `createVkTest` — `asRole()` fixture for authz specs.
|
|
13
|
+
*
|
|
14
|
+
* `@playwright/test` is an optional peer of the package as a whole, but it
|
|
15
|
+
* is required for this subpath.
|
|
16
|
+
*/
|
|
17
|
+
export { vkWebServers, ensureDbScriptPath, ENSURE_DB_ENV } from './web-servers.js';
|
|
18
|
+
export type { VkWebServersOptions, VkWebServerConfig, VkWebServerSpec, VkApiServerSpec, } from './web-servers.js';
|
|
19
|
+
export { storageStatePath, storageStatePaths, isSafeRoleKey, DEFAULT_AUTH_DIR, } from './storage-state.js';
|
|
20
|
+
export { establishRoles, wipeAuthDir } from './auth-setup.js';
|
|
21
|
+
export type { VkRoleSpec, EstablishRolesOptions } from './auth-setup.js';
|
|
22
|
+
export { createVkTest } from './fixtures.js';
|
|
23
|
+
export type { VkFixtures, CreateVkTestOptions } from './fixtures.js';
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/playwright/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACnF,YAAY,EACV,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9D,YAAY,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAEzE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,YAAY,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @venturekit/testing/playwright
|
|
3
|
+
*
|
|
4
|
+
* Playwright-specific half of the harness. Import from here in
|
|
5
|
+
* `playwright.config.ts`, setup projects and specs:
|
|
6
|
+
*
|
|
7
|
+
* - `vkWebServers` — database creation + migration + `vk dev`, in the one
|
|
8
|
+
* order that works, with crons off.
|
|
9
|
+
* - `establishRoles` / `wipeAuthDir` — log every role in once, persist the
|
|
10
|
+
* cookie jars, and clear stale ones.
|
|
11
|
+
* - `storageStatePath` — where a role's jar lives.
|
|
12
|
+
* - `createVkTest` — `asRole()` fixture for authz specs.
|
|
13
|
+
*
|
|
14
|
+
* `@playwright/test` is an optional peer of the package as a whole, but it
|
|
15
|
+
* is required for this subpath.
|
|
16
|
+
*/
|
|
17
|
+
export { vkWebServers, ensureDbScriptPath, ENSURE_DB_ENV } from './web-servers.js';
|
|
18
|
+
export { storageStatePath, storageStatePaths, isSafeRoleKey, DEFAULT_AUTH_DIR, } from './storage-state.js';
|
|
19
|
+
export { establishRoles, wipeAuthDir } from './auth-setup.js';
|
|
20
|
+
export { createVkTest } from './fixtures.js';
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/playwright/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAQnF,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9D,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where per-role `storageState` files live.
|
|
3
|
+
*
|
|
4
|
+
* The pattern: a `setup` project logs each role in once and writes its
|
|
5
|
+
* cookie jar to disk; every other project points `storageState` at one of
|
|
6
|
+
* those files. Roles then cost nothing per spec, and the authz matrix is a
|
|
7
|
+
* matter of picking a file rather than re-authenticating.
|
|
8
|
+
*
|
|
9
|
+
* Pure path math, kept apart from the IO in ./auth-setup.ts so it is
|
|
10
|
+
* unit-testable.
|
|
11
|
+
*/
|
|
12
|
+
/** Default directory, relative to the Playwright config. Add it to .gitignore. */
|
|
13
|
+
export declare const DEFAULT_AUTH_DIR = ".auth";
|
|
14
|
+
/**
|
|
15
|
+
* True when `role` is safe to use as a filename. Role keys end up in a path,
|
|
16
|
+
* so anything that could escape the auth directory is refused.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isSafeRoleKey(role: string): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Path to a role's storage state, e.g. `.auth/adminDev.json`.
|
|
21
|
+
*
|
|
22
|
+
* Forward slashes on purpose: Playwright accepts them on every platform, and
|
|
23
|
+
* it keeps the value stable in snapshots and error messages.
|
|
24
|
+
*/
|
|
25
|
+
export declare function storageStatePath(role: string, dir?: string): string;
|
|
26
|
+
/** Map every role key to its storage-state path. */
|
|
27
|
+
export declare function storageStatePaths(roles: readonly string[], dir?: string): Record<string, string>;
|
|
28
|
+
//# sourceMappingURL=storage-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-state.d.ts","sourceRoot":"","sources":["../../src/playwright/storage-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,kFAAkF;AAClF,eAAO,MAAM,gBAAgB,UAAU,CAAC;AAExC;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAE,MAAyB,GAAG,MAAM,CAOrF;AAED,oDAAoD;AACpD,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,GAAG,GAAE,MAAyB,GAC7B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAIxB"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where per-role `storageState` files live.
|
|
3
|
+
*
|
|
4
|
+
* The pattern: a `setup` project logs each role in once and writes its
|
|
5
|
+
* cookie jar to disk; every other project points `storageState` at one of
|
|
6
|
+
* those files. Roles then cost nothing per spec, and the authz matrix is a
|
|
7
|
+
* matter of picking a file rather than re-authenticating.
|
|
8
|
+
*
|
|
9
|
+
* Pure path math, kept apart from the IO in ./auth-setup.ts so it is
|
|
10
|
+
* unit-testable.
|
|
11
|
+
*/
|
|
12
|
+
/** Default directory, relative to the Playwright config. Add it to .gitignore. */
|
|
13
|
+
export const DEFAULT_AUTH_DIR = '.auth';
|
|
14
|
+
/**
|
|
15
|
+
* True when `role` is safe to use as a filename. Role keys end up in a path,
|
|
16
|
+
* so anything that could escape the auth directory is refused.
|
|
17
|
+
*/
|
|
18
|
+
export function isSafeRoleKey(role) {
|
|
19
|
+
return /^[A-Za-z0-9_-]+$/.test(role);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Path to a role's storage state, e.g. `.auth/adminDev.json`.
|
|
23
|
+
*
|
|
24
|
+
* Forward slashes on purpose: Playwright accepts them on every platform, and
|
|
25
|
+
* it keeps the value stable in snapshots and error messages.
|
|
26
|
+
*/
|
|
27
|
+
export function storageStatePath(role, dir = DEFAULT_AUTH_DIR) {
|
|
28
|
+
if (!isSafeRoleKey(role)) {
|
|
29
|
+
throw new Error(`@venturekit/testing: unsafe role key "${role}" — use letters, digits, dashes or underscores.`);
|
|
30
|
+
}
|
|
31
|
+
return `${dir.replace(/\/+$/, '')}/${role}.json`;
|
|
32
|
+
}
|
|
33
|
+
/** Map every role key to its storage-state path. */
|
|
34
|
+
export function storageStatePaths(roles, dir = DEFAULT_AUTH_DIR) {
|
|
35
|
+
const out = {};
|
|
36
|
+
for (const role of roles)
|
|
37
|
+
out[role] = storageStatePath(role, dir);
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=storage-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-state.js","sourceRoot":"","sources":["../../src/playwright/storage-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,kFAAkF;AAClF,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC;AAExC;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACvC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,MAAc,gBAAgB;IAC3E,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,yCAAyC,IAAI,iDAAiD,CAC/F,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,IAAI,OAAO,CAAC;AACnD,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,iBAAiB,CAC/B,KAAwB,EACxB,MAAc,gBAAgB;IAE9B,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,GAAG,CAAC,IAAI,CAAC,GAAG,gBAAgB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAClE,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playwright `webServer` wiring for a VentureKit stack.
|
|
3
|
+
*
|
|
4
|
+
* Encodes the ordering constraints that are easy to get wrong and fail
|
|
5
|
+
* confusingly when you do:
|
|
6
|
+
*
|
|
7
|
+
* 1. **Create the database first.** Nothing in the CLI creates it, and
|
|
8
|
+
* `globalSetup` is too late: Playwright starts `webServer` entries as
|
|
9
|
+
* config plugins, and plugin setup runs before `globalSetup`. So the
|
|
10
|
+
* creation step is chained *into* the command, ahead of `vk migrate`.
|
|
11
|
+
* 2. **Migrate the database `vk dev` will actually serve.** `vk dev`
|
|
12
|
+
* derives `<database>_<stage>` from `vk.config.ts` and ignores an
|
|
13
|
+
* inherited `DATABASE_URL`; `vk migrate` honours it. Both therefore get
|
|
14
|
+
* pointed at the same derived name — pick your own and you migrate one
|
|
15
|
+
* database while the API serves another empty one.
|
|
16
|
+
* 3. **Disable crons.** Declared schedules share the single-process dev
|
|
17
|
+
* server with the requests under test, write to the same rows the specs
|
|
18
|
+
* assert on, and can spend real provider quota. `--no-crons` keeps them
|
|
19
|
+
* dormant; drive the same handlers explicitly from a spec instead.
|
|
20
|
+
*
|
|
21
|
+
* Everything here is pure string/object assembly so it can be unit-tested —
|
|
22
|
+
* the assembled commands are what the regression tests assert on.
|
|
23
|
+
*/
|
|
24
|
+
import { type PgConnection } from '../stage-db.js';
|
|
25
|
+
/**
|
|
26
|
+
* Structural mirror of Playwright's `TestConfigWebServer`.
|
|
27
|
+
*
|
|
28
|
+
* Declared locally rather than imported so this module carries no runtime
|
|
29
|
+
* dependency on `@playwright/test` and stays assignable across versions.
|
|
30
|
+
*/
|
|
31
|
+
export interface VkWebServerConfig {
|
|
32
|
+
/**
|
|
33
|
+
* Label for the entry. Without it, a readiness timeout reports only
|
|
34
|
+
* "Timed out waiting 180000ms from config.webServer", which is ambiguous
|
|
35
|
+
* as soon as there is more than one server.
|
|
36
|
+
* Ignored by Playwright < 1.53.
|
|
37
|
+
*/
|
|
38
|
+
name?: string;
|
|
39
|
+
command: string;
|
|
40
|
+
url?: string;
|
|
41
|
+
port?: number;
|
|
42
|
+
cwd?: string;
|
|
43
|
+
timeout?: number;
|
|
44
|
+
reuseExistingServer?: boolean;
|
|
45
|
+
stdout?: 'pipe' | 'ignore';
|
|
46
|
+
stderr?: 'pipe' | 'ignore';
|
|
47
|
+
env?: Record<string, string>;
|
|
48
|
+
gracefulShutdown?: {
|
|
49
|
+
signal: 'SIGINT' | 'SIGTERM';
|
|
50
|
+
timeout: number;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/** Absolute path to the bundled database-creation script. */
|
|
54
|
+
export declare function ensureDbScriptPath(): string;
|
|
55
|
+
/** Env var names the bundled script reads. Also documented in bin/ensure-db.mjs. */
|
|
56
|
+
export declare const ENSURE_DB_ENV: {
|
|
57
|
+
readonly name: "VK_TEST_DB_NAME";
|
|
58
|
+
readonly adminUrl: "VK_TEST_ADMIN_DATABASE_URL";
|
|
59
|
+
};
|
|
60
|
+
export interface VkApiServerSpec {
|
|
61
|
+
/**
|
|
62
|
+
* Workspace filter for the package holding `vk.config.ts`, e.g. `@acme/api`.
|
|
63
|
+
* The CLI must run with that package as its cwd so the config and its
|
|
64
|
+
* `.env(.local)` resolve. Supply this or `cwd`.
|
|
65
|
+
*/
|
|
66
|
+
filter?: string;
|
|
67
|
+
/** Directory holding `vk.config.ts`. Used when `filter` is not set. */
|
|
68
|
+
cwd?: string;
|
|
69
|
+
/** Port for `vk dev`. */
|
|
70
|
+
port: number;
|
|
71
|
+
/** Base URL the specs use. Defaults to `http://127.0.0.1:<port>`. */
|
|
72
|
+
baseUrl?: string;
|
|
73
|
+
/** Readiness probe. Defaults to `<baseUrl>/_dev/health`. */
|
|
74
|
+
url?: string;
|
|
75
|
+
/** Run `vk migrate --seed`. On by default: E2E specs need the seed data. */
|
|
76
|
+
seed?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Leave declared cron schedules running. Off by default — see the header.
|
|
79
|
+
* Requires `vk dev --no-crons`, i.e. @venturekit/cli >= 0.2.0.
|
|
80
|
+
*/
|
|
81
|
+
crons?: boolean;
|
|
82
|
+
/** File watching. Off by default: a reload mid-run is pure flake. */
|
|
83
|
+
watch?: boolean;
|
|
84
|
+
/** Extra env for the migrate + dev processes. */
|
|
85
|
+
env?: Record<string, string>;
|
|
86
|
+
/** Command prefix used to invoke `vk`. Defaults to pnpm. */
|
|
87
|
+
execPrefix?: string;
|
|
88
|
+
}
|
|
89
|
+
export interface VkWebServersOptions extends PgConnection {
|
|
90
|
+
/** Stage label passed to `vk dev --stage` / `vk migrate --env`. */
|
|
91
|
+
stage: string;
|
|
92
|
+
/**
|
|
93
|
+
* Declared database name — `infrastructure.databases[].name` (or its `id`)
|
|
94
|
+
* from `vk.config.ts`. The stage suffix is added for you.
|
|
95
|
+
*/
|
|
96
|
+
database: string;
|
|
97
|
+
api: VkApiServerSpec;
|
|
98
|
+
/** Additional servers (a Next.js admin, a marketing site, …). */
|
|
99
|
+
web?: VkWebServerSpec | VkWebServerSpec[];
|
|
100
|
+
/**
|
|
101
|
+
* Reuse an already-running server. Defaults to `!process.env.CI`: handy
|
|
102
|
+
* locally, never in CI where a stale server would silently serve the suite.
|
|
103
|
+
*/
|
|
104
|
+
reuseExistingServer?: boolean;
|
|
105
|
+
/** Readiness timeout per server. Defaults to 180s (a cold migrate is slow). */
|
|
106
|
+
timeout?: number;
|
|
107
|
+
/** Base env for every spawned server. Defaults to `process.env`. */
|
|
108
|
+
baseEnv?: Record<string, string | undefined>;
|
|
109
|
+
}
|
|
110
|
+
export interface VkWebServerSpec {
|
|
111
|
+
name?: string;
|
|
112
|
+
command: string;
|
|
113
|
+
url?: string;
|
|
114
|
+
port?: number;
|
|
115
|
+
cwd?: string;
|
|
116
|
+
timeout?: number;
|
|
117
|
+
env?: Record<string, string>;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Build the `webServer` array for a VentureKit stack: database creation +
|
|
121
|
+
* migration + `vk dev`, followed by any extra servers.
|
|
122
|
+
*
|
|
123
|
+
* ```ts
|
|
124
|
+
* export default defineConfig({
|
|
125
|
+
* webServer: vkWebServers({
|
|
126
|
+
* stage: 'test',
|
|
127
|
+
* database: 'acme_app',
|
|
128
|
+
* api: { filter: '@acme/api', port: 4100 },
|
|
129
|
+
* web: { name: 'Admin', command: 'pnpm --filter @acme/admin exec next dev -p 3100', url: 'http://127.0.0.1:3100' },
|
|
130
|
+
* }),
|
|
131
|
+
* });
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
export declare function vkWebServers(options: VkWebServersOptions): VkWebServerConfig[];
|
|
135
|
+
//# sourceMappingURL=web-servers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-servers.d.ts","sourceRoot":"","sources":["../../src/playwright/web-servers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAyD,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE1G;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,gBAAgB,CAAC,EAAE;QAAE,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CACtE;AAED,6DAA6D;AAC7D,wBAAgB,kBAAkB,IAAI,MAAM,CAI3C;AAED,oFAAoF;AACpF,eAAO,MAAM,aAAa;;;CAGhB,CAAC;AAEX,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,qEAAqE;IACrE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,iDAAiD;IACjD,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,mBAAoB,SAAQ,YAAY;IACvD,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,eAAe,CAAC;IACrB,iEAAiE;IACjE,GAAG,CAAC,EAAE,eAAe,GAAG,eAAe,EAAE,CAAC;IAC1C;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,+EAA+E;IAC/E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAaD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,iBAAiB,EAAE,CAqE9E"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playwright `webServer` wiring for a VentureKit stack.
|
|
3
|
+
*
|
|
4
|
+
* Encodes the ordering constraints that are easy to get wrong and fail
|
|
5
|
+
* confusingly when you do:
|
|
6
|
+
*
|
|
7
|
+
* 1. **Create the database first.** Nothing in the CLI creates it, and
|
|
8
|
+
* `globalSetup` is too late: Playwright starts `webServer` entries as
|
|
9
|
+
* config plugins, and plugin setup runs before `globalSetup`. So the
|
|
10
|
+
* creation step is chained *into* the command, ahead of `vk migrate`.
|
|
11
|
+
* 2. **Migrate the database `vk dev` will actually serve.** `vk dev`
|
|
12
|
+
* derives `<database>_<stage>` from `vk.config.ts` and ignores an
|
|
13
|
+
* inherited `DATABASE_URL`; `vk migrate` honours it. Both therefore get
|
|
14
|
+
* pointed at the same derived name — pick your own and you migrate one
|
|
15
|
+
* database while the API serves another empty one.
|
|
16
|
+
* 3. **Disable crons.** Declared schedules share the single-process dev
|
|
17
|
+
* server with the requests under test, write to the same rows the specs
|
|
18
|
+
* assert on, and can spend real provider quota. `--no-crons` keeps them
|
|
19
|
+
* dormant; drive the same handlers explicitly from a spec instead.
|
|
20
|
+
*
|
|
21
|
+
* Everything here is pure string/object assembly so it can be unit-tested —
|
|
22
|
+
* the assembled commands are what the regression tests assert on.
|
|
23
|
+
*/
|
|
24
|
+
import { fileURLToPath } from 'node:url';
|
|
25
|
+
import { stageDatabaseName, stageDatabaseUrl, adminDatabaseUrl } from '../stage-db.js';
|
|
26
|
+
/** Absolute path to the bundled database-creation script. */
|
|
27
|
+
export function ensureDbScriptPath() {
|
|
28
|
+
// Two levels below the package root from both `src/playwright/` and the
|
|
29
|
+
// compiled `dist/playwright/`, so the same specifier works either way.
|
|
30
|
+
return fileURLToPath(new URL('../../bin/ensure-db.mjs', import.meta.url));
|
|
31
|
+
}
|
|
32
|
+
/** Env var names the bundled script reads. Also documented in bin/ensure-db.mjs. */
|
|
33
|
+
export const ENSURE_DB_ENV = {
|
|
34
|
+
name: 'VK_TEST_DB_NAME',
|
|
35
|
+
adminUrl: 'VK_TEST_ADMIN_DATABASE_URL',
|
|
36
|
+
};
|
|
37
|
+
const DEFAULT_TIMEOUT = 180_000;
|
|
38
|
+
/** Drop `undefined` values so the result satisfies `Record<string, string>`. */
|
|
39
|
+
function stringEnv(env) {
|
|
40
|
+
const out = {};
|
|
41
|
+
for (const [key, value] of Object.entries(env)) {
|
|
42
|
+
if (value !== undefined)
|
|
43
|
+
out[key] = value;
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Build the `webServer` array for a VentureKit stack: database creation +
|
|
49
|
+
* migration + `vk dev`, followed by any extra servers.
|
|
50
|
+
*
|
|
51
|
+
* ```ts
|
|
52
|
+
* export default defineConfig({
|
|
53
|
+
* webServer: vkWebServers({
|
|
54
|
+
* stage: 'test',
|
|
55
|
+
* database: 'acme_app',
|
|
56
|
+
* api: { filter: '@acme/api', port: 4100 },
|
|
57
|
+
* web: { name: 'Admin', command: 'pnpm --filter @acme/admin exec next dev -p 3100', url: 'http://127.0.0.1:3100' },
|
|
58
|
+
* }),
|
|
59
|
+
* });
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export function vkWebServers(options) {
|
|
63
|
+
const { stage, database, api } = options;
|
|
64
|
+
if (!api.filter && !api.cwd) {
|
|
65
|
+
throw new Error('@venturekit/testing: vkWebServers needs `api.filter` or `api.cwd` so the CLI runs where vk.config.ts lives.');
|
|
66
|
+
}
|
|
67
|
+
const baseEnv = options.baseEnv ?? process.env;
|
|
68
|
+
const reuseExistingServer = options.reuseExistingServer ?? !baseEnv.CI;
|
|
69
|
+
const timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
70
|
+
const baseUrl = api.baseUrl ?? `http://127.0.0.1:${api.port}`;
|
|
71
|
+
const exec = api.execPrefix ?? (api.filter ? `pnpm --filter ${api.filter} exec` : 'pnpm exec');
|
|
72
|
+
const migrateFlags = [`--env ${stage}`, api.seed === false ? '' : '--seed'].filter(Boolean);
|
|
73
|
+
const devFlags = [
|
|
74
|
+
`--stage ${stage}`,
|
|
75
|
+
`--port ${api.port}`,
|
|
76
|
+
api.watch === true ? '' : '--no-watch',
|
|
77
|
+
api.crons === true ? '' : '--no-crons',
|
|
78
|
+
].filter(Boolean);
|
|
79
|
+
// Chained with `&&` so a failure in creation or migration aborts the run
|
|
80
|
+
// instead of booting an API against a database that is not ready.
|
|
81
|
+
const command = [
|
|
82
|
+
`node ${JSON.stringify(ensureDbScriptPath())}`,
|
|
83
|
+
`${exec} vk migrate ${migrateFlags.join(' ')}`,
|
|
84
|
+
`${exec} vk dev ${devFlags.join(' ')}`,
|
|
85
|
+
].join(' && ');
|
|
86
|
+
const apiServer = {
|
|
87
|
+
name: `API (vk dev --stage ${stage})`,
|
|
88
|
+
command,
|
|
89
|
+
url: api.url ?? `${baseUrl}/_dev/health`,
|
|
90
|
+
cwd: api.filter ? undefined : api.cwd,
|
|
91
|
+
reuseExistingServer,
|
|
92
|
+
timeout,
|
|
93
|
+
stdout: 'pipe',
|
|
94
|
+
stderr: 'pipe',
|
|
95
|
+
env: stringEnv({
|
|
96
|
+
...baseEnv,
|
|
97
|
+
// Pins `vk migrate` to the database `vk dev` derives for itself.
|
|
98
|
+
DATABASE_URL: stageDatabaseUrl({ ...options, database, stage }),
|
|
99
|
+
// Read by bin/ensure-db.mjs, which runs under bare node.
|
|
100
|
+
[ENSURE_DB_ENV.name]: stageDatabaseName(database, stage),
|
|
101
|
+
[ENSURE_DB_ENV.adminUrl]: adminDatabaseUrl(options),
|
|
102
|
+
...api.env,
|
|
103
|
+
}),
|
|
104
|
+
};
|
|
105
|
+
const extra = options.web === undefined ? [] : Array.isArray(options.web) ? options.web : [options.web];
|
|
106
|
+
return [
|
|
107
|
+
apiServer,
|
|
108
|
+
...extra.map((spec) => ({
|
|
109
|
+
name: spec.name,
|
|
110
|
+
command: spec.command,
|
|
111
|
+
url: spec.url,
|
|
112
|
+
port: spec.port,
|
|
113
|
+
cwd: spec.cwd,
|
|
114
|
+
reuseExistingServer,
|
|
115
|
+
timeout: spec.timeout ?? timeout,
|
|
116
|
+
stdout: 'pipe',
|
|
117
|
+
stderr: 'pipe',
|
|
118
|
+
env: stringEnv({ ...baseEnv, ...spec.env }),
|
|
119
|
+
})),
|
|
120
|
+
];
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=web-servers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-servers.js","sourceRoot":"","sources":["../../src/playwright/web-servers.ts"],"names":[],"mappings":"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"}
|
package/dist/stack.d.ts
CHANGED
|
@@ -19,6 +19,19 @@ export interface StartTestStackOptions {
|
|
|
19
19
|
cwd?: string;
|
|
20
20
|
/** Stage name — flows into the local DB name. Default `test`. */
|
|
21
21
|
stage?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Declared database name — `infrastructure.databases[].name` (or its `id`)
|
|
24
|
+
* from `vk.config.ts`.
|
|
25
|
+
*
|
|
26
|
+
* Set this and the harness creates `<database>_<stage>` before migrating,
|
|
27
|
+
* and pins `DATABASE_URL` to it (overriding any inherited value). Without
|
|
28
|
+
* it, nothing creates the database — a cold run then fails with
|
|
29
|
+
* `database "…" does not exist` — and an inherited `DATABASE_URL` can send
|
|
30
|
+
* `vk migrate` somewhere `vk dev` will not serve.
|
|
31
|
+
*
|
|
32
|
+
* Requires the optional peer `pg`.
|
|
33
|
+
*/
|
|
34
|
+
database?: string;
|
|
22
35
|
/** Port for the API server. Default `4100`. */
|
|
23
36
|
port?: number;
|
|
24
37
|
/** Host to build the base URL from. Default `localhost`. */
|
|
@@ -31,6 +44,13 @@ export interface StartTestStackOptions {
|
|
|
31
44
|
seed?: boolean;
|
|
32
45
|
/** Enable file watching / hot reload (usually off for tests). Default `false`. */
|
|
33
46
|
watch?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Leave declared cron schedules running. Default `false` — they share the
|
|
49
|
+
* dev server with the requests under test, write to the same rows specs
|
|
50
|
+
* assert on, and can spend real provider quota. Requires
|
|
51
|
+
* `@venturekit/cli` >= 0.2.0 for `vk dev --no-crons`.
|
|
52
|
+
*/
|
|
53
|
+
crons?: boolean;
|
|
34
54
|
/** Max time to wait for readiness, in ms. Default 120_000. */
|
|
35
55
|
readyTimeoutMs?: number;
|
|
36
56
|
/** Override the resolved `vk` binary path. */
|
package/dist/stack.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stack.d.ts","sourceRoot":"","sources":["../src/stack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;
|
|
1
|
+
{"version":3,"file":"stack.d.ts","sourceRoot":"","sources":["../src/stack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AASH,MAAM,WAAW,qBAAqB;IACpC,4EAA4E;IAC5E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,mEAAmE;IACnE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sDAAsD;IACtD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,kFAAkF;IAClF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8DAA8D;IAC9D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,KAAK,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;CAC9B;AAED,MAAM,WAAW,SAAS;IACxB,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAoED;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,SAAS,CAAC,CAiE5F"}
|
package/dist/stack.js
CHANGED
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
import { spawn } from 'node:child_process';
|
|
18
18
|
import { existsSync } from 'node:fs';
|
|
19
19
|
import { join } from 'node:path';
|
|
20
|
+
import { ensureStageDatabase } from './ensure-database.js';
|
|
20
21
|
import { waitForReady, vkDevServerReady } from './ready.js';
|
|
22
|
+
import { stageDatabaseUrl } from './stage-db.js';
|
|
21
23
|
/** Resolve the `vk` binary from the nearest `node_modules/.bin`, else PATH. */
|
|
22
24
|
function resolveVkBin(cwd, override) {
|
|
23
25
|
if (override)
|
|
@@ -98,6 +100,14 @@ export async function startTestStack(options = {}) {
|
|
|
98
100
|
const stdio = options.stdio ?? 'inherit';
|
|
99
101
|
const vk = resolveVkBin(cwd, options.vkBin);
|
|
100
102
|
const env = { ...process.env, ...options.env, VENTURE_STAGE: stage };
|
|
103
|
+
// Nothing in the CLI creates the database, so do it here — before the
|
|
104
|
+
// migration that would otherwise fail on a cold machine. Pinning
|
|
105
|
+
// DATABASE_URL to the derived name keeps `vk migrate` on the database
|
|
106
|
+
// `vk dev` picks for itself.
|
|
107
|
+
if (options.database) {
|
|
108
|
+
await ensureStageDatabase({ database: options.database, stage });
|
|
109
|
+
env.DATABASE_URL = stageDatabaseUrl({ database: options.database, stage });
|
|
110
|
+
}
|
|
101
111
|
// `vk dev` does NOT auto-migrate — apply schema (and optionally seeds) first.
|
|
102
112
|
if (options.migrate !== false) {
|
|
103
113
|
const migrateArgs = ['migrate', '--env', stage];
|
|
@@ -108,6 +118,8 @@ export async function startTestStack(options = {}) {
|
|
|
108
118
|
const devArgs = ['dev', '--stage', stage, '--port', String(port)];
|
|
109
119
|
if (options.watch !== true)
|
|
110
120
|
devArgs.push('--no-watch');
|
|
121
|
+
if (options.crons !== true)
|
|
122
|
+
devArgs.push('--no-crons');
|
|
111
123
|
const child = spawn(vk, devArgs, {
|
|
112
124
|
cwd,
|
|
113
125
|
env,
|
package/dist/stack.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stack.js","sourceRoot":"","sources":["../src/stack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"stack.js","sourceRoot":"","sources":["../src/stack.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage database naming + creation.
|
|
3
|
+
*
|
|
4
|
+
* `vk dev --stage <s>` and `vk migrate --env <s>` both derive their local
|
|
5
|
+
* Postgres database from the *declared database intent*, not from the
|
|
6
|
+
* environment: `<databases[].name ?? id>_<stage>`, with dashes folded to
|
|
7
|
+
* underscores so the result is a valid unquoted identifier. An inherited
|
|
8
|
+
* `DATABASE_URL` does **not** override that choice.
|
|
9
|
+
*
|
|
10
|
+
* Two consequences bite every test harness, and both are silent:
|
|
11
|
+
*
|
|
12
|
+
* 1. Point `vk migrate` at a name you picked yourself and the API will
|
|
13
|
+
* happily serve a *different*, unmigrated database — the suite fails
|
|
14
|
+
* with `relation "…" does not exist` rather than a connection error.
|
|
15
|
+
* 2. Nothing creates the database. `vk migrate` connects to it and fails
|
|
16
|
+
* with `database "…" does not exist` on any cold machine or CI runner.
|
|
17
|
+
*
|
|
18
|
+
* `stageDatabaseName` mirrors the CLI's derivation so a harness never has
|
|
19
|
+
* to hardcode the name; `ensureStageDatabase` (./ensure-database.ts) closes
|
|
20
|
+
* the creation gap.
|
|
21
|
+
*
|
|
22
|
+
* Everything here is pure so it can be unit-tested — the one piece that
|
|
23
|
+
* talks to Postgres lives in its own module.
|
|
24
|
+
*/
|
|
25
|
+
/** Local Postgres defaults used by `vk dev`'s generated docker-compose stack. */
|
|
26
|
+
export declare const LOCAL_PG: {
|
|
27
|
+
readonly host: "localhost";
|
|
28
|
+
readonly port: 5432;
|
|
29
|
+
readonly user: "postgres";
|
|
30
|
+
readonly password: "postgres";
|
|
31
|
+
/** Maintenance database — `CREATE DATABASE` cannot run inside the target. */
|
|
32
|
+
readonly maintenanceDatabase: "postgres";
|
|
33
|
+
};
|
|
34
|
+
export interface StageDatabaseTarget {
|
|
35
|
+
/**
|
|
36
|
+
* The declared database name — `infrastructure.databases[].name` (falling
|
|
37
|
+
* back to its `id`) from `vk.config.ts`. NOT the project name: the CLI
|
|
38
|
+
* deliberately does not prefix it.
|
|
39
|
+
*/
|
|
40
|
+
database: string;
|
|
41
|
+
/** Stage label, e.g. `test`. Matches `vk dev --stage` / `vk migrate --env`. */
|
|
42
|
+
stage: string;
|
|
43
|
+
}
|
|
44
|
+
export interface PgConnection {
|
|
45
|
+
host?: string;
|
|
46
|
+
port?: number;
|
|
47
|
+
user?: string;
|
|
48
|
+
password?: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Derive the local Postgres database name for a declared database + stage.
|
|
52
|
+
*
|
|
53
|
+
* Mirrors the CLI's `pgName()` exactly — keep the two in step.
|
|
54
|
+
*/
|
|
55
|
+
export declare function stageDatabaseName(database: string, stage: string): string;
|
|
56
|
+
/**
|
|
57
|
+
* True when `name` is a safe unquoted Postgres identifier. Database names
|
|
58
|
+
* reach `CREATE DATABASE` as literal DDL (they cannot be parameterized), so
|
|
59
|
+
* anything else is refused rather than escaped.
|
|
60
|
+
*/
|
|
61
|
+
export declare function isSafeDatabaseName(name: string): boolean;
|
|
62
|
+
/** Build a Postgres URL for an arbitrary database, filling in local defaults. */
|
|
63
|
+
export declare function pgConnectionString(conn: PgConnection, database: string): string;
|
|
64
|
+
/**
|
|
65
|
+
* Connection string for the stage database — the one `vk dev` will serve.
|
|
66
|
+
* Point `vk migrate` and any harness-side pool at this exact URL.
|
|
67
|
+
*/
|
|
68
|
+
export declare function stageDatabaseUrl(target: StageDatabaseTarget & PgConnection): string;
|
|
69
|
+
/**
|
|
70
|
+
* Connection string for the maintenance database, used to issue
|
|
71
|
+
* `CREATE DATABASE`.
|
|
72
|
+
*/
|
|
73
|
+
export declare function adminDatabaseUrl(conn?: PgConnection): string;
|
|
74
|
+
/** Hide the password before a connection string reaches a log. */
|
|
75
|
+
export declare function redactUrl(url: string): string;
|
|
76
|
+
/**
|
|
77
|
+
* Resolve the database name from either an explicit `name` or a
|
|
78
|
+
* `database` + `stage` pair, and refuse anything unsafe as DDL.
|
|
79
|
+
*
|
|
80
|
+
* Shared by `ensureStageDatabase` so its validation is unit-testable
|
|
81
|
+
* without a live Postgres.
|
|
82
|
+
*/
|
|
83
|
+
export declare function resolveStageDatabaseName(options: {
|
|
84
|
+
name?: string;
|
|
85
|
+
database?: string;
|
|
86
|
+
stage?: string;
|
|
87
|
+
}): string;
|
|
88
|
+
//# sourceMappingURL=stage-db.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stage-db.d.ts","sourceRoot":"","sources":["../src/stage-db.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,iFAAiF;AACjF,eAAO,MAAM,QAAQ;;;;;IAKnB,6EAA6E;;CAErE,CAAC;AAEX,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,iFAAiF;AACjF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM/E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,mBAAmB,GAAG,YAAY,GAAG,MAAM,CAEnF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,GAAE,YAAiB,GAAG,MAAM,CAEhE;AAED,kEAAkE;AAClE,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,MAAM,CAgBT"}
|