@fuzdev/fuz_app 0.69.0 → 0.70.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/testing/CLAUDE.md +13 -8
- package/dist/testing/cross_backend/create_cross_backend_global_setup.d.ts +57 -0
- package/dist/testing/cross_backend/create_cross_backend_global_setup.d.ts.map +1 -0
- package/dist/testing/cross_backend/create_cross_backend_global_setup.js +31 -0
- package/dist/testing/cross_backend/default_backend_configs.d.ts +13 -0
- package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_backend_configs.js +4 -4
- package/dist/testing/cross_backend/make_cross_backend_project.d.ts +72 -0
- package/dist/testing/cross_backend/make_cross_backend_project.d.ts.map +1 -0
- package/dist/testing/cross_backend/make_cross_backend_project.js +51 -0
- package/dist/testing/cross_backend/standard.d.ts +8 -0
- package/dist/testing/cross_backend/standard.d.ts.map +1 -1
- package/dist/testing/cross_backend/standard.js +1 -0
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +12 -8
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.js +5 -2
- package/dist/testing/integration.d.ts.map +1 -1
- package/dist/testing/integration.js +20 -3
- package/package.json +1 -1
package/dist/testing/CLAUDE.md
CHANGED
|
@@ -219,15 +219,16 @@ test-only by construction.
|
|
|
219
219
|
- `assert_schema_snapshots_equal(a, b, labels?)` — throws on drift with a fully-formatted diff message.
|
|
220
220
|
- `SchemaDiff` — tagged-union per drift kind: `schema_version_only_in`, `schema_version_sequence_differs`, `table_only_in`, `column_only_in`, `column_field_differs`, `index_only_in`, `index_definition_differs`, `constraint_only_in`, `constraint_differs`, `sequence_only_in`, `sequence_data_type_differs`.
|
|
221
221
|
|
|
222
|
-
**Cross-impl gate pattern** —
|
|
223
|
-
|
|
224
|
-
bootstrap each impl against an isolated
|
|
222
|
+
**Cross-impl gate pattern** — a dual-impl consumer running two backends
|
|
223
|
+
(a TS Hono server and a Rust spine server) against a shared schema, plus
|
|
224
|
+
fuz_app's own cross-backend suite, bootstrap each impl against an isolated
|
|
225
|
+
DB, snapshot, then compare:
|
|
225
226
|
|
|
226
227
|
```ts
|
|
227
|
-
await drop_recreate_db('
|
|
228
|
+
await drop_recreate_db('app_test');
|
|
228
229
|
await spawn_backend(deno_config);
|
|
229
230
|
const snapshot_deno = await query_schema_snapshot(db);
|
|
230
|
-
await drop_recreate_db('
|
|
231
|
+
await drop_recreate_db('app_test');
|
|
231
232
|
await spawn_backend(rust_config);
|
|
232
233
|
const snapshot_rust = await query_schema_snapshot(db);
|
|
233
234
|
assert_schema_snapshots_equal(snapshot_deno, snapshot_rust, {a: 'deno', b: 'rust'});
|
|
@@ -789,8 +790,8 @@ points:
|
|
|
789
790
|
The standard test suites take a unified
|
|
790
791
|
`{setup_test, surface_source, capabilities}` shape so the same suite bodies
|
|
791
792
|
run against an in-process Hono harness today and against a spawned backend
|
|
792
|
-
over real HTTP — either the Rust spine (`zzz_server`,
|
|
793
|
-
the non-domain `testing_spine_stub`) or a **TS** spine binary built on the
|
|
793
|
+
over real HTTP — either the Rust spine (`zzz_server`, another consumer's
|
|
794
|
+
spine server, or the non-domain `testing_spine_stub`) or a **TS** spine binary built on the
|
|
794
795
|
test-server core below (fuz_app's own domain-free `testing_spine_server`, run
|
|
795
796
|
on Node + Deno + Bun). In-process is the fast feedback path; cross-process is the
|
|
796
797
|
source of truth for wire-shape conformance.
|
|
@@ -1094,7 +1095,11 @@ in-process legs (plain `gro test`) are `src/test/auth/cell_crud_parity.db.test.t
|
|
|
1094
1095
|
same bootstrap-equivalent step (the only path for roles like
|
|
1095
1096
|
`ROLE_KEEPER` whose `grant_paths` is bootstrap-only), refreshes
|
|
1096
1097
|
`DaemonTokenState.keeper_account_id` to the new row, then fires the
|
|
1097
|
-
consumer-supplied `reset_state` callback for domain-state reset
|
|
1098
|
+
consumer-supplied `reset_state(db)` callback for domain-state reset —
|
|
1099
|
+
passed the **transactional** `Db` the auth wipe ran on, so DB-domain
|
|
1100
|
+
consumers (e.g. fuz_forge truncating its cell / fact / file tables) reset
|
|
1101
|
+
on the same connection rather than a separately-pooled one that would
|
|
1102
|
+
deadlock against this open transaction under PGlite. Auth
|
|
1098
1103
|
gates on `credential_types: ['daemon_token']` — effectively keeper-only
|
|
1099
1104
|
without forcing the `actor: 'required'` ⟺ `acting?: ActingActor`
|
|
1100
1105
|
biconditional. No free-form runtime grant action exists — see the
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import '../assert_dev_env.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generic vitest `globalSetup` factory for cross-backend integration suites.
|
|
4
|
+
*
|
|
5
|
+
* Pairs with `make_cross_backend_project`: each cross-backend vitest project
|
|
6
|
+
* sets its own `test.name`, and this factory derives the backend name from
|
|
7
|
+
* that project name (vitest 4 passes the `TestProject` to globalSetup), picks
|
|
8
|
+
* the matching `BackendConfig`, spawns + bootstraps it via `bootstrap_backend`,
|
|
9
|
+
* and `provide`s a serializable handle that `*.cross.test.ts` files
|
|
10
|
+
* `inject` and rebuild with `reconstruct_bootstrapped_handle`.
|
|
11
|
+
*
|
|
12
|
+
* A consumer's `global_setup.ts` collapses to:
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* import {create_cross_backend_global_setup} from
|
|
16
|
+
* '@fuzdev/fuz_app/testing/cross_backend/create_cross_backend_global_setup.js';
|
|
17
|
+
* import {deno_backend_config, rust_backend_config} from './my_backend_config.js';
|
|
18
|
+
* import './cross_test_types.js'; // augments inject('backend_handle')
|
|
19
|
+
*
|
|
20
|
+
* export default create_cross_backend_global_setup({
|
|
21
|
+
* configs: {deno: deno_backend_config, rust: rust_backend_config},
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* vitest 4's `provide` hard-rejects non-serializable values, so the live
|
|
26
|
+
* `child` / `teardown` / `keeper_transport` are stripped via
|
|
27
|
+
* `serialize_bootstrapped_handle`; the teardown closure stays in the
|
|
28
|
+
* globalSetup process and is returned for vitest to fire after the suite.
|
|
29
|
+
*
|
|
30
|
+
* @module
|
|
31
|
+
*/
|
|
32
|
+
import type { TestProject } from 'vitest/node';
|
|
33
|
+
import type { BackendConfig } from './backend_config.js';
|
|
34
|
+
export interface CrossBackendGlobalSetupOptions {
|
|
35
|
+
/**
|
|
36
|
+
* Map of derived backend name → `BackendConfig` factory. The derived
|
|
37
|
+
* name (see `derive_name`) selects the factory; unknown names throw with
|
|
38
|
+
* the full supported list so a misnamed project surfaces clearly.
|
|
39
|
+
*/
|
|
40
|
+
readonly configs: Readonly<Record<string, () => BackendConfig>>;
|
|
41
|
+
/**
|
|
42
|
+
* Derive the backend name from the vitest project name. Default strips
|
|
43
|
+
* `cross_backend_(ts_)?`.
|
|
44
|
+
*/
|
|
45
|
+
readonly derive_name?: (project_name: string) => string;
|
|
46
|
+
/**
|
|
47
|
+
* Key passed to `project.provide` (and read by `inject` in test files).
|
|
48
|
+
* Default `'backend_handle'`. Augment vitest's `ProvidedContext` for it.
|
|
49
|
+
*/
|
|
50
|
+
readonly provide_key?: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Build a vitest `globalSetup` default export. Returns the
|
|
54
|
+
* `(project) => teardown` function vitest 4 expects.
|
|
55
|
+
*/
|
|
56
|
+
export declare const create_cross_backend_global_setup: ({ configs, derive_name, provide_key, }: CrossBackendGlobalSetupOptions) => ((project: TestProject) => Promise<() => Promise<void>>);
|
|
57
|
+
//# sourceMappingURL=create_cross_backend_global_setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create_cross_backend_global_setup.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/create_cross_backend_global_setup.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,aAAa,CAAC;AAE7C,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAYvD,MAAM,WAAW,8BAA8B;IAC9C;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,aAAa,CAAC,CAAC,CAAC;IAChE;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,CAAC;IACxD;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;GAGG;AACH,eAAO,MAAM,iCAAiC,GAAI,wCAI/C,8BAA8B,KAAG,CAAC,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAqB1F,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import '../assert_dev_env.js';
|
|
2
|
+
import { bootstrap_backend } from './bootstrap_backend.js';
|
|
3
|
+
import { serialize_bootstrapped_handle } from './setup.js';
|
|
4
|
+
/**
|
|
5
|
+
* Default project-name → backend-name reduction: strips the
|
|
6
|
+
* `cross_backend_` prefix plus an optional `ts_` discriminator (the TS
|
|
7
|
+
* canonical backends carry it to distinguish JS runtimes). So
|
|
8
|
+
* `cross_backend_ts_deno` → `deno` and `cross_backend_rust` → `rust`.
|
|
9
|
+
*/
|
|
10
|
+
const DEFAULT_PROJECT_NAME_PREFIX = /^cross_backend_(?:ts_)?/;
|
|
11
|
+
/**
|
|
12
|
+
* Build a vitest `globalSetup` default export. Returns the
|
|
13
|
+
* `(project) => teardown` function vitest 4 expects.
|
|
14
|
+
*/
|
|
15
|
+
export const create_cross_backend_global_setup = ({ configs, derive_name = (project_name) => project_name.replace(DEFAULT_PROJECT_NAME_PREFIX, ''), provide_key = 'backend_handle', }) => {
|
|
16
|
+
return async (project) => {
|
|
17
|
+
const name = derive_name(project.name);
|
|
18
|
+
const factory = configs[name];
|
|
19
|
+
if (!factory) {
|
|
20
|
+
throw new Error(`Could not derive backend config from vitest project '${project.name}' ` +
|
|
21
|
+
`(derived name '${name}') — expected one of: ${Object.keys(configs).join(', ')}`);
|
|
22
|
+
}
|
|
23
|
+
const bootstrapped = await bootstrap_backend(factory());
|
|
24
|
+
// vitest's `provide` is keyed on the consumer-augmented `ProvidedContext`;
|
|
25
|
+
// the generic key is a plain string, so cast past the keyof constraint.
|
|
26
|
+
project.provide(provide_key, serialize_bootstrapped_handle(bootstrapped));
|
|
27
|
+
return async () => {
|
|
28
|
+
await bootstrapped.teardown();
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
};
|
|
@@ -70,6 +70,14 @@ export interface MakeDefaultTsBackendConfigOptions {
|
|
|
70
70
|
* override.
|
|
71
71
|
*/
|
|
72
72
|
readonly port_env_var?: string;
|
|
73
|
+
/**
|
|
74
|
+
* Session cookie name the binary's `create_session_config` uses.
|
|
75
|
+
* Defaults to `'fuz_session'`. Must match the consumer's session config
|
|
76
|
+
* — the harness threads the `_testing_reset`-returned keeper cookie into
|
|
77
|
+
* its jar under this name, so a mismatch surfaces as 401s on the
|
|
78
|
+
* `create_account` path (e.g. fuz_forge uses `'fuz_forge_session'`).
|
|
79
|
+
*/
|
|
80
|
+
readonly cookie_name?: string;
|
|
73
81
|
}
|
|
74
82
|
/**
|
|
75
83
|
* Shared builder for TS-family backends (Deno + Node). Owns the common
|
|
@@ -111,6 +119,11 @@ export interface MakeDefaultRustBackendConfigOptions {
|
|
|
111
119
|
* (e.g. `'info,zzz_server=info,testing_zzz_server=info'`).
|
|
112
120
|
*/
|
|
113
121
|
readonly rust_log?: string;
|
|
122
|
+
/**
|
|
123
|
+
* Session cookie name the binary uses. Defaults to `'fuz_session'`.
|
|
124
|
+
* Must match the consumer's session config (see the TS builder's note).
|
|
125
|
+
*/
|
|
126
|
+
readonly cookie_name?: string;
|
|
114
127
|
}
|
|
115
128
|
/**
|
|
116
129
|
* Shared builder for Rust-family backends. Owns the common env baseline
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default_backend_configs.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/default_backend_configs.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAC,sBAAsB,EAAE,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAC/E,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAA2B,KAAK,gBAAgB,EAAC,MAAM,+BAA+B,CAAC;AAQ9F;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,EAAE,mBASpC,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,EAAE,mBAStC,CAAC;AAeH,MAAM,WAAW,iCAAiC;IACjD,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC9C,oDAAoD;IACpD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,iEAAiE;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,6CAA6C;IAC7C,QAAQ,CAAC,YAAY,CAAC,EAAE,mBAAmB,CAAC;IAC5C,wEAAwE;IACxE,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAClC,sEAAsE;IACtE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAC/D;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"default_backend_configs.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/default_backend_configs.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAC,sBAAsB,EAAE,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAC/E,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAA2B,KAAK,gBAAgB,EAAC,MAAM,+BAA+B,CAAC;AAQ9F;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,EAAE,mBASpC,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,EAAE,mBAStC,CAAC;AAeH,MAAM,WAAW,iCAAiC;IACjD,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC9C,oDAAoD;IACpD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,iEAAiE;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,6CAA6C;IAC7C,QAAQ,CAAC,YAAY,CAAC,EAAE,mBAAmB,CAAC;IAC5C,wEAAwE;IACxE,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAClC,sEAAsE;IACtE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAC/D;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,GAC1C,MAAM,iCAAiC,KACrC,aAoCF,CAAC;AAEF,MAAM,WAAW,mCAAmC;IACnD,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC9C;;;;OAIG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,iEAAiE;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,+CAA+C;IAC/C,QAAQ,CAAC,YAAY,CAAC,EAAE,mBAAmB,CAAC;IAC5C,wEAAwE;IACxE,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAClC,sEAAsE;IACtE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAC/D;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,GAC5C,MAAM,mCAAmC,KACvC,aA4CF,CAAC"}
|
|
@@ -49,7 +49,7 @@ const build_default_bootstrap = (paths, overrides) => ({
|
|
|
49
49
|
* genuinely differs.
|
|
50
50
|
*/
|
|
51
51
|
export const make_default_ts_backend_config = (opts) => {
|
|
52
|
-
const { name, port, start_command, database_url = 'memory://', extra_env, capabilities = ts_default_capabilities, paths = build_test_backend_paths(name), bootstrap_overrides, port_env_var = 'PORT', } = opts;
|
|
52
|
+
const { name, port, start_command, database_url = 'memory://', extra_env, capabilities = ts_default_capabilities, paths = build_test_backend_paths(name), bootstrap_overrides, port_env_var = 'PORT', cookie_name = 'fuz_session', } = opts;
|
|
53
53
|
return {
|
|
54
54
|
name,
|
|
55
55
|
start_command,
|
|
@@ -58,7 +58,7 @@ export const make_default_ts_backend_config = (opts) => {
|
|
|
58
58
|
ws_path: '/api/ws',
|
|
59
59
|
health_path: '/health',
|
|
60
60
|
bootstrap_path: '/api/account/bootstrap',
|
|
61
|
-
cookie_name
|
|
61
|
+
cookie_name,
|
|
62
62
|
startup_timeout_ms: 30_000,
|
|
63
63
|
env: {
|
|
64
64
|
NODE_ENV: 'development',
|
|
@@ -81,7 +81,7 @@ export const make_default_ts_backend_config = (opts) => {
|
|
|
81
81
|
* the 120s startup window for cargo's first-run build cost.
|
|
82
82
|
*/
|
|
83
83
|
export const make_default_rust_backend_config = (opts) => {
|
|
84
|
-
const { name, port, start_command, database_url, extra_env, capabilities = rust_default_capabilities, paths = build_test_backend_paths(name), bootstrap_overrides, port_env_var = 'PORT', rust_log = 'info', } = opts;
|
|
84
|
+
const { name, port, start_command, database_url, extra_env, capabilities = rust_default_capabilities, paths = build_test_backend_paths(name), bootstrap_overrides, port_env_var = 'PORT', rust_log = 'info', cookie_name = 'fuz_session', } = opts;
|
|
85
85
|
return {
|
|
86
86
|
name,
|
|
87
87
|
start_command,
|
|
@@ -90,7 +90,7 @@ export const make_default_rust_backend_config = (opts) => {
|
|
|
90
90
|
ws_path: '/api/ws',
|
|
91
91
|
health_path: '/health',
|
|
92
92
|
bootstrap_path: '/api/account/bootstrap',
|
|
93
|
-
cookie_name
|
|
93
|
+
cookie_name,
|
|
94
94
|
startup_timeout_ms: 120_000,
|
|
95
95
|
env: {
|
|
96
96
|
RUST_LOG: rust_log,
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic vitest project factory for cross-backend integration suites.
|
|
3
|
+
*
|
|
4
|
+
* One vitest project per spawned backend; each runs the consumer's shared
|
|
5
|
+
* `*.cross.test.ts` files against its own bootstrapped binary. The paired
|
|
6
|
+
* `create_cross_backend_global_setup` (in `global_setup.ts`) reads the
|
|
7
|
+
* project's `name` to pick which `BackendConfig` to spawn, so the project
|
|
8
|
+
* name is the single source of truth for backend selection.
|
|
9
|
+
*
|
|
10
|
+
* Consumers compose these into their `vite.config.ts`:
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* const cross_backend_projects = process.env.FUZ_TEST_CROSS_BACKEND
|
|
14
|
+
* ? [
|
|
15
|
+
* make_cross_backend_project({name: 'cross_backend_ts_deno', global_setup: GLOBAL_SETUP}),
|
|
16
|
+
* make_cross_backend_project({name: 'cross_backend_rust', global_setup: GLOBAL_SETUP}),
|
|
17
|
+
* ]
|
|
18
|
+
* : [];
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* where `GLOBAL_SETUP = './src/test/cross_backend/global_setup.ts'`.
|
|
22
|
+
*
|
|
23
|
+
* This module is intentionally dependency-free and `assert_dev_env`-free:
|
|
24
|
+
* it runs at vite **config** time (including production builds, where the
|
|
25
|
+
* consumer gates the projects behind an env flag), so it must not pull in
|
|
26
|
+
* the DEV-only test runtime.
|
|
27
|
+
*
|
|
28
|
+
* @module
|
|
29
|
+
*/
|
|
30
|
+
export interface CrossBackendProjectOptions {
|
|
31
|
+
/**
|
|
32
|
+
* vitest project name. `create_cross_backend_global_setup` derives the
|
|
33
|
+
* backend name from it (by default stripping a `cross_backend_(ts_)?`
|
|
34
|
+
* prefix), so name projects `cross_backend_<backend>` (e.g.
|
|
35
|
+
* `cross_backend_rust`, `cross_backend_ts_deno`).
|
|
36
|
+
*/
|
|
37
|
+
readonly name: string;
|
|
38
|
+
/**
|
|
39
|
+
* Path to the consumer's vitest `globalSetup` module, relative to the
|
|
40
|
+
* consumer repo root (e.g. `'./src/test/cross_backend/global_setup.ts'`).
|
|
41
|
+
* That module is expected to export a `create_cross_backend_global_setup`
|
|
42
|
+
* result as its default.
|
|
43
|
+
*/
|
|
44
|
+
readonly global_setup: string;
|
|
45
|
+
/** Test-file globs. Default: `['src/test/cross_backend/*.cross.test.ts']`. */
|
|
46
|
+
readonly include?: ReadonlyArray<string>;
|
|
47
|
+
/** Globs to exclude from `include` (e.g. a backend-specific variant file). Default: `[]`. */
|
|
48
|
+
readonly exclude?: ReadonlyArray<string>;
|
|
49
|
+
/** vitest `sequence.groupOrder`. Default: `3` (runs after unit + db). */
|
|
50
|
+
readonly group_order?: number;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Build a single cross-backend vitest project config. Spread the results
|
|
54
|
+
* into `test.projects` in the consumer's `vite.config.ts`. `isolate: false`
|
|
55
|
+
* + `fileParallelism: false` because a project shares one spawned backend
|
|
56
|
+
* across its files.
|
|
57
|
+
*/
|
|
58
|
+
export declare const make_cross_backend_project: ({ name, global_setup, include, exclude, group_order, }: CrossBackendProjectOptions) => {
|
|
59
|
+
extends: true;
|
|
60
|
+
test: {
|
|
61
|
+
name: string;
|
|
62
|
+
include: Array<string>;
|
|
63
|
+
exclude: Array<string>;
|
|
64
|
+
globalSetup: Array<string>;
|
|
65
|
+
isolate: false;
|
|
66
|
+
fileParallelism: false;
|
|
67
|
+
sequence: {
|
|
68
|
+
groupOrder: number;
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=make_cross_backend_project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"make_cross_backend_project.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/make_cross_backend_project.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAQH,MAAM,WAAW,0BAA0B;IAC1C;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACzC,6FAA6F;IAC7F,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACzC,yEAAyE;IACzE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,GAAI,wDAMxC,0BAA0B,KAAG;IAC/B,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACvB,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACvB,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QAC3B,OAAO,EAAE,KAAK,CAAC;QACf,eAAe,EAAE,KAAK,CAAC;QACvB,QAAQ,EAAE;YAAC,UAAU,EAAE,MAAM,CAAA;SAAC,CAAC;KAC/B,CAAC;CAYD,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic vitest project factory for cross-backend integration suites.
|
|
3
|
+
*
|
|
4
|
+
* One vitest project per spawned backend; each runs the consumer's shared
|
|
5
|
+
* `*.cross.test.ts` files against its own bootstrapped binary. The paired
|
|
6
|
+
* `create_cross_backend_global_setup` (in `global_setup.ts`) reads the
|
|
7
|
+
* project's `name` to pick which `BackendConfig` to spawn, so the project
|
|
8
|
+
* name is the single source of truth for backend selection.
|
|
9
|
+
*
|
|
10
|
+
* Consumers compose these into their `vite.config.ts`:
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* const cross_backend_projects = process.env.FUZ_TEST_CROSS_BACKEND
|
|
14
|
+
* ? [
|
|
15
|
+
* make_cross_backend_project({name: 'cross_backend_ts_deno', global_setup: GLOBAL_SETUP}),
|
|
16
|
+
* make_cross_backend_project({name: 'cross_backend_rust', global_setup: GLOBAL_SETUP}),
|
|
17
|
+
* ]
|
|
18
|
+
* : [];
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* where `GLOBAL_SETUP = './src/test/cross_backend/global_setup.ts'`.
|
|
22
|
+
*
|
|
23
|
+
* This module is intentionally dependency-free and `assert_dev_env`-free:
|
|
24
|
+
* it runs at vite **config** time (including production builds, where the
|
|
25
|
+
* consumer gates the projects behind an env flag), so it must not pull in
|
|
26
|
+
* the DEV-only test runtime.
|
|
27
|
+
*
|
|
28
|
+
* @module
|
|
29
|
+
*/
|
|
30
|
+
/** Default test-file globs — the convention is `src/test/cross_backend/*.cross.test.ts`. */
|
|
31
|
+
const DEFAULT_INCLUDE = ['src/test/cross_backend/*.cross.test.ts'];
|
|
32
|
+
/** vitest `sequence.groupOrder` for cross-backend projects — after unit (1) + db (2). */
|
|
33
|
+
const DEFAULT_GROUP_ORDER = 3;
|
|
34
|
+
/**
|
|
35
|
+
* Build a single cross-backend vitest project config. Spread the results
|
|
36
|
+
* into `test.projects` in the consumer's `vite.config.ts`. `isolate: false`
|
|
37
|
+
* + `fileParallelism: false` because a project shares one spawned backend
|
|
38
|
+
* across its files.
|
|
39
|
+
*/
|
|
40
|
+
export const make_cross_backend_project = ({ name, global_setup, include = DEFAULT_INCLUDE, exclude = [], group_order = DEFAULT_GROUP_ORDER, }) => ({
|
|
41
|
+
extends: true,
|
|
42
|
+
test: {
|
|
43
|
+
name,
|
|
44
|
+
include: [...include],
|
|
45
|
+
exclude: [...exclude],
|
|
46
|
+
globalSetup: [global_setup],
|
|
47
|
+
isolate: false,
|
|
48
|
+
fileParallelism: false,
|
|
49
|
+
sequence: { groupOrder: group_order },
|
|
50
|
+
},
|
|
51
|
+
});
|
|
@@ -86,6 +86,14 @@ export interface StandardCrossProcessTestOptions {
|
|
|
86
86
|
* `0` to skip the assertion entirely.
|
|
87
87
|
*/
|
|
88
88
|
error_coverage_min?: number;
|
|
89
|
+
/**
|
|
90
|
+
* Forwarded to `describe_round_trip_validation` as `skip_routes`
|
|
91
|
+
* (`'METHOD /path'` keys). For consumer REST routes whose responses
|
|
92
|
+
* aren't JSON-with-an-output-schema and so can't be round-tripped — e.g.
|
|
93
|
+
* fuz_forge's git smart-HTTP routes (`git-upload-pack` / `git-receive-pack`
|
|
94
|
+
* / `info/refs`) which stream git protocol bytes.
|
|
95
|
+
*/
|
|
96
|
+
round_trip_skip_routes?: Array<string>;
|
|
89
97
|
}
|
|
90
98
|
/**
|
|
91
99
|
* Run the cross-process standard test bundle — integration, admin (when
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"standard.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/standard.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAM1D,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,WAAW,+BAA+B;IAC/C,2CAA2C;IAC3C,UAAU,EAAE,SAAS,CAAC;IACtB;;;OAGG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,uCAAuC;IACvC,YAAY,EAAE,mBAAmB,CAAC;IAClC,uFAAuF;IACvF,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;OAKG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;OAGG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"standard.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/standard.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAM1D,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,YAAY,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,WAAW,+BAA+B;IAC/C,2CAA2C;IAC3C,UAAU,EAAE,SAAS,CAAC;IACtB;;;OAGG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,uCAAuC;IACvC,YAAY,EAAE,mBAAmB,CAAC;IAClC,uFAAuF;IACvF,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;OAKG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;OAGG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;OAMG;IACH,sBAAsB,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACvC;AAED;;;;GAIG;AACH,eAAO,MAAM,qCAAqC,GACjD,SAAS,+BAA+B,KACtC,IAsCF,CAAC"}
|
|
@@ -22,6 +22,7 @@ export const describe_standard_cross_process_tests = (options) => {
|
|
|
22
22
|
setup_test: options.setup_test,
|
|
23
23
|
surface_source: options.surface_source,
|
|
24
24
|
capabilities: options.capabilities,
|
|
25
|
+
skip_routes: options.round_trip_skip_routes,
|
|
25
26
|
});
|
|
26
27
|
describe_rpc_round_trip_tests({
|
|
27
28
|
setup_test: options.setup_test,
|
|
@@ -62,6 +62,7 @@ import { type RpcAction } from '../../actions/action_rpc.js';
|
|
|
62
62
|
import type { AppDeps } from '../../auth/deps.js';
|
|
63
63
|
import type { SessionOptions } from '../../auth/session_cookie.js';
|
|
64
64
|
import type { DaemonTokenState } from '../../auth/daemon_token.js';
|
|
65
|
+
import type { Db } from '../../db/db.js';
|
|
65
66
|
/**
|
|
66
67
|
* The `_testing_reset` action spec.
|
|
67
68
|
*
|
|
@@ -229,15 +230,18 @@ export interface CreateTestingActionsOptions {
|
|
|
229
230
|
*/
|
|
230
231
|
readonly daemon_token_state: DaemonTokenState;
|
|
231
232
|
/**
|
|
232
|
-
* Consumer-supplied callback invoked after the auth-table reset
|
|
233
|
-
* `
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
238
|
-
*
|
|
233
|
+
* Consumer-supplied callback invoked after the auth-table reset, passed
|
|
234
|
+
* the same transactional `Db` the auth wipes ran on. DB-domain consumers
|
|
235
|
+
* (e.g. fuz_forge truncating its cell / fact / file tables) MUST use this
|
|
236
|
+
* `db` rather than a separately-pooled connection — under PGlite's single
|
|
237
|
+
* connection a second connection deadlocks against this still-open
|
|
238
|
+
* transaction. `testing_zzz_server` clears in-memory workspace registry +
|
|
239
|
+
* terminals + scoped-FS scratch (ignores `db`); `testing_spine_stub` has
|
|
240
|
+
* no domain layer and omits the option. Runs inside the same RPC dispatch
|
|
241
|
+
* as the auth-table writes, so a throw surfaces to the caller as a
|
|
242
|
+
* JSON-RPC error and the per-test fixture short-circuits.
|
|
239
243
|
*/
|
|
240
|
-
readonly reset_state?: () => Promise<void> | void;
|
|
244
|
+
readonly reset_state?: (db: Db) => Promise<void> | void;
|
|
241
245
|
}
|
|
242
246
|
/**
|
|
243
247
|
* Build the testing RPC actions for a test binary's registry.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing_reset_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_reset_actions.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB,OAAO,EAAa,KAAK,SAAS,EAAC,MAAM,6BAA6B,CAAC;AAEvE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"testing_reset_actions.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/testing_reset_actions.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB,OAAO,EAAa,KAAK,SAAS,EAAC,MAAM,6BAA6B,CAAC;AAEvE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,8BAA8B,CAAC;AACjE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,4BAA4B,CAAC;AACjE,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,gBAAgB,CAAC;AAiBvC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwBQ,CAAC;AAE/C;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;CAWA,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;CAeC,CAAC;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,mCAAmC,QAAO,SACiB,CAAC;AAEzE,4CAA4C;AAC5C,MAAM,WAAW,2BAA2B;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACjD;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;IAC9C;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACxD;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB,GAClC,MAAM,OAAO,EACb,SAAS,2BAA2B,KAClC,KAAK,CAAC,SAAS,CA0GjB,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,0BAA0B,UAAmC,CAAC"}
|
|
@@ -279,9 +279,12 @@ export const create_testing_actions = (deps, options) => {
|
|
|
279
279
|
// of stale-id-then-refresh on the next call.
|
|
280
280
|
daemon_token_state.keeper_account_id = keeper.account.id;
|
|
281
281
|
// 7. Fire domain-state reset (zzz workspaces/terminals/scratch,
|
|
282
|
-
// or no-op for spine_stub).
|
|
282
|
+
// fuz_forge cell/fact/file truncation, or no-op for spine_stub).
|
|
283
|
+
// Pass the transactional `ctx.db` so DB-domain truncation runs
|
|
284
|
+
// on the same connection — a separate pool connection deadlocks
|
|
285
|
+
// against this open transaction under PGlite.
|
|
283
286
|
if (reset_state)
|
|
284
|
-
await reset_state();
|
|
287
|
+
await reset_state(ctx.db);
|
|
285
288
|
return { ...keeper, extra_accounts: extras };
|
|
286
289
|
}),
|
|
287
290
|
rpc_action(testing_mint_session_action_spec, async (input, ctx) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/integration.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAsB7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAM9D,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAiB1B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAC,KAAK,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,0BAA0B,CAAC;AAGxD;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC9C;;;;OAIG;IACH,UAAU,EAAE,SAAS,CAAC;IACtB;;;;;;;;;OASG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,kEAAkE;IAClE,YAAY,EAAE,mBAAmB,CAAC;IAClC;;;;OAIG;IACH,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;;;;;;;;OAYG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,mCAAmC,GAC/C,SAAS,8BAA8B,KACrC,
|
|
1
|
+
{"version":3,"file":"integration.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/integration.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAsB7B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,2BAA2B,CAAC;AAM9D,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAiB1B,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAC,KAAK,mBAAmB,EAAC,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,0BAA0B,CAAC;AAGxD;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC9C;;;;OAIG;IACH,UAAU,EAAE,SAAS,CAAC;IACtB;;;;;;;;;OASG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,kEAAkE;IAClE,YAAY,EAAE,mBAAmB,CAAC;IAClC;;;;OAIG;IACH,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC;;;;;;;;;;;;OAYG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,mCAAmC,GAC/C,SAAS,8BAA8B,KACrC,IA60CF,CAAC"}
|
|
@@ -605,13 +605,30 @@ export const describe_standard_integration_tests = (options) => {
|
|
|
605
605
|
test('non-admin cannot access admin routes', async () => {
|
|
606
606
|
const fixture = await options.setup_test();
|
|
607
607
|
// admin routes are optional in the base suite — admin-specific coverage
|
|
608
|
-
// lives in describe_standard_admin_integration_tests
|
|
609
|
-
|
|
608
|
+
// lives in describe_standard_admin_integration_tests.
|
|
609
|
+
//
|
|
610
|
+
// Pick an admin REST route where a clean role-denial 403 is
|
|
611
|
+
// reachable: account-grain (`actor: 'none'`, so the authorization
|
|
612
|
+
// phase doesn't first demand an acting actor → `actor_required`)
|
|
613
|
+
// and input/param/query-free (so input validation doesn't 400
|
|
614
|
+
// first, per the 401 → 400 → 403 phase order). Admin surfaces are
|
|
615
|
+
// RPC-first now; a consumer may expose no such REST route (fuz_app
|
|
616
|
+
// itself, zzz) — then this REST-era check is a no-op and RPC denial
|
|
617
|
+
// is covered by `describe_rpc_attack_surface_tests`.
|
|
618
|
+
const admin_route = route_specs.find((s) => (s.auth.roles?.includes('admin') ?? false) &&
|
|
619
|
+
s.auth.actor === 'none' &&
|
|
620
|
+
!s.input &&
|
|
621
|
+
!s.params &&
|
|
622
|
+
!s.query);
|
|
610
623
|
if (!admin_route)
|
|
611
624
|
return;
|
|
625
|
+
// Probe with a freshly-created account — it holds no admin role
|
|
626
|
+
// (the keeper fixture behind `create_session_headers` does, so it
|
|
627
|
+
// would pass the gate).
|
|
628
|
+
const non_admin = await fixture.create_account({ username: 'non_admin_admin_probe' });
|
|
612
629
|
const res = await fixture.transport(admin_route.path, {
|
|
613
630
|
method: admin_route.method,
|
|
614
|
-
headers:
|
|
631
|
+
headers: { cookie: `${cookie_name}=${non_admin.session_cookie}` },
|
|
615
632
|
});
|
|
616
633
|
assert.strictEqual(res.status, 403);
|
|
617
634
|
const body = await res.json();
|