@venturekit/testing 0.0.20 → 0.0.22
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/cognito.d.ts +5 -2
- package/dist/cognito.d.ts.map +1 -1
- package/dist/cognito.js +14 -2
- package/dist/cognito.js.map +1 -1
- package/dist/ensure-database.d.ts +52 -0
- package/dist/ensure-database.d.ts.map +1 -0
- package/dist/ensure-database.js +82 -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 +139 -0
- package/dist/playwright/web-servers.d.ts.map +1 -0
- package/dist/playwright/web-servers.js +128 -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,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log every role in once, up front, and persist its cookie jar.
|
|
3
|
+
*
|
|
4
|
+
* Run from a Playwright `setup` project that the other projects depend on.
|
|
5
|
+
* Specs then adopt a role by pointing `storageState` at a file — no
|
|
6
|
+
* per-spec login, no token plumbing, and the authz matrix costs one line.
|
|
7
|
+
*
|
|
8
|
+
* Assumes cookie-based sessions, which is what `@venturekit/auth`'s
|
|
9
|
+
* `/auth/login` route issues: the response `Set-Cookie` lands in the
|
|
10
|
+
* request context's jar, and `storageState()` writes it out.
|
|
11
|
+
*
|
|
12
|
+
* IO-bound, so the pure path math lives in ./storage-state.ts.
|
|
13
|
+
*/
|
|
14
|
+
import { mkdir, rm } from 'node:fs/promises';
|
|
15
|
+
import { dirname } from 'node:path';
|
|
16
|
+
import { createTestUser } from '../cognito.js';
|
|
17
|
+
import { DEFAULT_AUTH_DIR, storageStatePath } from './storage-state.js';
|
|
18
|
+
async function loadPlaywright() {
|
|
19
|
+
try {
|
|
20
|
+
return await import('@playwright/test');
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
throw new Error("@venturekit/testing: this helper requires the optional peer '@playwright/test'.");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Delete the storage-state directory.
|
|
28
|
+
*
|
|
29
|
+
* Call from `globalSetup`: a jar left over from a previous run points at
|
|
30
|
+
* users that no longer exist in the freshly created database, and the
|
|
31
|
+
* resulting 401s look like an auth bug rather than stale state.
|
|
32
|
+
*/
|
|
33
|
+
export async function wipeAuthDir(dir = DEFAULT_AUTH_DIR) {
|
|
34
|
+
await rm(dir, { recursive: true, force: true });
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Provision each role, log it in, and write its `storageState`.
|
|
38
|
+
*
|
|
39
|
+
* Returns role key → file path, ready to drop into a project's `use`.
|
|
40
|
+
*/
|
|
41
|
+
export async function establishRoles(options) {
|
|
42
|
+
const { roles, baseUrl, intent, loginPath = '/auth/login', authDir = DEFAULT_AUTH_DIR, provision = true, loginBody = (role) => ({ email: role.email, password: role.password }), } = options;
|
|
43
|
+
const log = options.logger === null
|
|
44
|
+
? () => { }
|
|
45
|
+
: (options.logger ?? ((m) => console.log(`[vk-testing] ${m}`)));
|
|
46
|
+
const { request } = await loadPlaywright();
|
|
47
|
+
const written = {};
|
|
48
|
+
for (const [key, role] of Object.entries(roles)) {
|
|
49
|
+
const path = storageStatePath(key, authDir);
|
|
50
|
+
if (provision) {
|
|
51
|
+
await createTestUser({ baseUrl, intent, ...role });
|
|
52
|
+
}
|
|
53
|
+
const context = await request.newContext({ baseURL: baseUrl });
|
|
54
|
+
try {
|
|
55
|
+
const response = await context.post(loginPath, { data: loginBody(role) });
|
|
56
|
+
if (!response.ok()) {
|
|
57
|
+
const body = await response.text().catch(() => '');
|
|
58
|
+
throw new Error(`@venturekit/testing: login failed for role "${key}" (${role.email}) — ` +
|
|
59
|
+
`POST ${loginPath} returned ${response.status()}. ${body.slice(0, 400)}`);
|
|
60
|
+
}
|
|
61
|
+
// A 200 with no cookie writes a jar that authenticates nothing, and
|
|
62
|
+
// every later spec then fails with a 401 far from the cause.
|
|
63
|
+
const state = await context.storageState();
|
|
64
|
+
if (state.cookies.length === 0) {
|
|
65
|
+
throw new Error(`@venturekit/testing: login for role "${key}" succeeded but set no cookies. ` +
|
|
66
|
+
`Is ${loginPath} the right route, and does it issue a session cookie?`);
|
|
67
|
+
}
|
|
68
|
+
await mkdir(dirname(path), { recursive: true });
|
|
69
|
+
await context.storageState({ path });
|
|
70
|
+
written[key] = path;
|
|
71
|
+
log(`role ready: ${key} → ${path}`);
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
await context.dispose();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return written;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=auth-setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-setup.js","sourceRoot":"","sources":["../../src/playwright/auth-setup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
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 { type APIRequestContext } from '@playwright/test';
|
|
11
|
+
export interface VkFixtures {
|
|
12
|
+
/**
|
|
13
|
+
* Open an API request context authenticated as `role`.
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* const viewer = await asRole('viewer');
|
|
17
|
+
* expect((await viewer.post('/content')).status()).toBe(403);
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
asRole: (role: string) => Promise<APIRequestContext>;
|
|
21
|
+
}
|
|
22
|
+
export interface CreateVkTestOptions {
|
|
23
|
+
/** Directory holding the storage-state files. Defaults to `.auth`. */
|
|
24
|
+
authDir?: string;
|
|
25
|
+
/** Override the project's `baseURL` for these contexts. */
|
|
26
|
+
baseURL?: string;
|
|
27
|
+
/** Extra headers for every role context. Defaults to `Accept: application/json`. */
|
|
28
|
+
extraHTTPHeaders?: Record<string, string>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Build a `test` object carrying the `asRole` fixture.
|
|
32
|
+
*
|
|
33
|
+
* ```ts
|
|
34
|
+
* // tests/api/fixtures.ts
|
|
35
|
+
* export const test = createVkTest();
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function createVkTest(options?: CreateVkTestOptions): import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions & VkFixtures, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions>;
|
|
39
|
+
//# sourceMappingURL=fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../../src/playwright/fixtures.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAyB,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGjF,MAAM,WAAW,UAAU;IACzB;;;;;;;OAOG;IACH,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,mBAAmB;IAClC,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3C;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,4PA6B7D"}
|
|
@@ -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,139 @@
|
|
|
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
|
+
* Omit it when the project declares no database intent: there is then
|
|
97
|
+
* nothing to create and nothing to migrate, so both steps are skipped and
|
|
98
|
+
* the command is just `vk dev`.
|
|
99
|
+
*/
|
|
100
|
+
database?: string;
|
|
101
|
+
api: VkApiServerSpec;
|
|
102
|
+
/** Additional servers (a Next.js admin, a marketing site, …). */
|
|
103
|
+
web?: VkWebServerSpec | VkWebServerSpec[];
|
|
104
|
+
/**
|
|
105
|
+
* Reuse an already-running server. Defaults to `!process.env.CI`: handy
|
|
106
|
+
* locally, never in CI where a stale server would silently serve the suite.
|
|
107
|
+
*/
|
|
108
|
+
reuseExistingServer?: boolean;
|
|
109
|
+
/** Readiness timeout per server. Defaults to 180s (a cold migrate is slow). */
|
|
110
|
+
timeout?: number;
|
|
111
|
+
/** Base env for every spawned server. Defaults to `process.env`. */
|
|
112
|
+
baseEnv?: Record<string, string | undefined>;
|
|
113
|
+
}
|
|
114
|
+
export interface VkWebServerSpec {
|
|
115
|
+
name?: string;
|
|
116
|
+
command: string;
|
|
117
|
+
url?: string;
|
|
118
|
+
port?: number;
|
|
119
|
+
cwd?: string;
|
|
120
|
+
timeout?: number;
|
|
121
|
+
env?: Record<string, string>;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Build the `webServer` array for a VentureKit stack: database creation +
|
|
125
|
+
* migration + `vk dev`, followed by any extra servers.
|
|
126
|
+
*
|
|
127
|
+
* ```ts
|
|
128
|
+
* export default defineConfig({
|
|
129
|
+
* webServer: vkWebServers({
|
|
130
|
+
* stage: 'test',
|
|
131
|
+
* database: 'acme_app',
|
|
132
|
+
* api: { filter: '@acme/api', port: 4100 },
|
|
133
|
+
* web: { name: 'Admin', command: 'pnpm --filter @acme/admin exec next dev -p 3100', url: 'http://127.0.0.1:3100' },
|
|
134
|
+
* }),
|
|
135
|
+
* });
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
export declare function vkWebServers(options: VkWebServersOptions): VkWebServerConfig[];
|
|
139
|
+
//# 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;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,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,CA2E9E"}
|
|
@@ -0,0 +1,128 @@
|
|
|
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 steps = [];
|
|
82
|
+
if (database) {
|
|
83
|
+
steps.push(`node ${JSON.stringify(ensureDbScriptPath())}`);
|
|
84
|
+
steps.push(`${exec} vk migrate ${migrateFlags.join(' ')}`);
|
|
85
|
+
}
|
|
86
|
+
steps.push(`${exec} vk dev ${devFlags.join(' ')}`);
|
|
87
|
+
const command = steps.join(' && ');
|
|
88
|
+
const apiServer = {
|
|
89
|
+
name: `API (vk dev --stage ${stage})`,
|
|
90
|
+
command,
|
|
91
|
+
url: api.url ?? `${baseUrl}/_dev/health`,
|
|
92
|
+
cwd: api.filter ? undefined : api.cwd,
|
|
93
|
+
reuseExistingServer,
|
|
94
|
+
timeout,
|
|
95
|
+
stdout: 'pipe',
|
|
96
|
+
stderr: 'pipe',
|
|
97
|
+
env: stringEnv({
|
|
98
|
+
...baseEnv,
|
|
99
|
+
...(database
|
|
100
|
+
? {
|
|
101
|
+
// Pins `vk migrate` to the database `vk dev` derives for itself.
|
|
102
|
+
DATABASE_URL: stageDatabaseUrl({ ...options, database, stage }),
|
|
103
|
+
// Read by bin/ensure-db.mjs, which runs under bare node.
|
|
104
|
+
[ENSURE_DB_ENV.name]: stageDatabaseName(database, stage),
|
|
105
|
+
[ENSURE_DB_ENV.adminUrl]: adminDatabaseUrl(options),
|
|
106
|
+
}
|
|
107
|
+
: {}),
|
|
108
|
+
...api.env,
|
|
109
|
+
}),
|
|
110
|
+
};
|
|
111
|
+
const extra = options.web === undefined ? [] : Array.isArray(options.web) ? options.web : [options.web];
|
|
112
|
+
return [
|
|
113
|
+
apiServer,
|
|
114
|
+
...extra.map((spec) => ({
|
|
115
|
+
name: spec.name,
|
|
116
|
+
command: spec.command,
|
|
117
|
+
url: spec.url,
|
|
118
|
+
port: spec.port,
|
|
119
|
+
cwd: spec.cwd,
|
|
120
|
+
reuseExistingServer,
|
|
121
|
+
timeout: spec.timeout ?? timeout,
|
|
122
|
+
stdout: 'pipe',
|
|
123
|
+
stderr: 'pipe',
|
|
124
|
+
env: stringEnv({ ...baseEnv, ...spec.env }),
|
|
125
|
+
})),
|
|
126
|
+
];
|
|
127
|
+
}
|
|
128
|
+
//# 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"}
|