@vurb/testing 3.1.31

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 ADDED
@@ -0,0 +1,255 @@
1
+ <p align="center">
2
+ <h1 align="center">@vurb/testing</h1>
3
+ <p align="center">
4
+ <strong>In-Memory MVA Pipeline Tester</strong> — Run the full execution pipeline without MCP transport
5
+ </p>
6
+ </p>
7
+
8
+ <p align="center">
9
+ <a href="https://www.npmjs.com/package/@vurb/testing"><img src="https://img.shields.io/npm/v/@vurb/testing?color=blue" alt="npm" /></a>
10
+ <a href="https://github.com/vinkius-labs/vurb.ts/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-green" alt="License" /></a>
11
+ <img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen" alt="Node" />
12
+ <img src="https://img.shields.io/badge/dependencies-0-brightgreen" alt="Zero Dependencies" />
13
+ </p>
14
+
15
+ ---
16
+
17
+ > The official test runner for Vurb.ts applications. In-memory MVA lifecycle emulator — runs the full execution pipeline without network transport. Zero runtime dependencies. Runner agnostic (Vitest, Jest, Mocha, `node:test`).
18
+
19
+ ## Why
20
+
21
+ Every MCP server today is tested with HTTP mocks, raw `JSON.stringify` assertions, and string matching. That's like testing a REST API by reading TCP packets.
22
+
23
+ **Vurb.ts** applications have **five auditable layers** (Zod Validation → Middleware Chain → Handler → Presenter Egress Firewall → System Rules). The `VurbTester` lets you assert each layer independently, in-memory, without starting a server.
24
+
25
+ ```
26
+ ┌─────────────────────────────────────────────────────────┐
27
+ │ VurbTester │
28
+ │ │
29
+ │ ┌──────────┐ ┌────────────┐ ┌─────────┐ │
30
+ │ │ Zod │──▶│ Middleware │──▶│ Handler │ │
31
+ │ │ Input │ │ Chain │ │ │ │
32
+ │ └──────────┘ └────────────┘ └────┬────┘ │
33
+ │ │ │
34
+ │ ┌────▼────┐ │
35
+ │ │Presenter│ │
36
+ │ │ (Egress │ │
37
+ │ │Firewall)│ │
38
+ │ └────┬────┘ │
39
+ │ │ │
40
+ │ ┌────────────────────────────────────▼──────────────┐ │
41
+ │ │ MvaTestResult │ │
42
+ │ │ ┌──────┐ ┌───────────┐ ┌────────┐ ┌───────────┐ │ │
43
+ │ │ │ data │ │systemRules│ │uiBlocks│ │rawResponse│ │ │
44
+ │ │ └──────┘ └───────────┘ └────────┘ └───────────┘ │ │
45
+ │ └───────────────────────────────────────────────────┘ │
46
+ └─────────────────────────────────────────────────────────┘
47
+ ```
48
+
49
+ ## What You Can Audit
50
+
51
+ | MVA Layer | What VurbTester asserts | SOC2 Relevance |
52
+ |---|---|---|
53
+ | **Egress Firewall** | Hidden fields (`passwordHash`, `tenantId`) are physically absent from `result.data` | Data leak prevention |
54
+ | **OOM Guard** | Zod rejects `take: 10000` before it reaches the handler | Memory exhaustion protection |
55
+ | **System Rules** | `result.systemRules` contains the expected domain rules | Deterministic LLM governance |
56
+ | **UI Blocks** | SSR blocks (echarts, summaries) are correctly generated | Agent response quality |
57
+ | **Middleware** | Auth guards block unauthorized calls, isError is true | Access control verification |
58
+ | **Agent Limit** | Collections are truncated at cognitive guardrail bounds | Context window protection |
59
+ | **HATEOAS** | `suggestActions` produces correct next-step affordances | Agent navigation safety |
60
+
61
+ ## Quick Start
62
+
63
+ ```typescript
64
+ import { describe, it, expect } from 'vitest';
65
+ import { createVurbTester } from '@vurb/testing';
66
+ import { registry } from './server/registry.js';
67
+
68
+ const tester = createVurbTester(registry, {
69
+ contextFactory: () => ({
70
+ prisma: mockPrisma,
71
+ tenantId: 't_enterprise_42',
72
+ role: 'ADMIN',
73
+ }),
74
+ });
75
+
76
+ describe('User MVA Audit', () => {
77
+ it('Egress Firewall strips sensitive fields', async () => {
78
+ const result = await tester.callAction('db_user', 'find_many', { take: 10 });
79
+
80
+ expect(result.data[0]).not.toHaveProperty('passwordHash');
81
+ expect(result.data[0]).not.toHaveProperty('tenantId');
82
+ expect(result.data[0].email).toBe('ceo@acme.com');
83
+ });
84
+
85
+ it('System rules are injected by Presenter', async () => {
86
+ const result = await tester.callAction('db_user', 'find_many', { take: 5 });
87
+
88
+ expect(result.systemRules).toContain(
89
+ 'Data originates from the database via Prisma ORM.'
90
+ );
91
+ });
92
+
93
+ it('OOM Guard rejects unbounded queries', async () => {
94
+ const result = await tester.callAction('db_user', 'find_many', { take: 99999 });
95
+ expect(result.isError).toBe(true);
96
+ });
97
+ });
98
+ ```
99
+
100
+ ## API Reference
101
+
102
+ ### `createVurbTester(registry, options)`
103
+
104
+ Factory function — creates a `VurbTester` instance.
105
+
106
+ ```typescript
107
+ function createVurbTester<TContext>(
108
+ registry: ToolRegistry<TContext>,
109
+ options: TesterOptions<TContext>,
110
+ ): VurbTester<TContext>;
111
+ ```
112
+
113
+ | Parameter | Type | Description |
114
+ |---|---|---|
115
+ | `registry` | `ToolRegistry<TContext>` | Your application's tool registry — the same one wired to the MCP server |
116
+ | `options` | `TesterOptions<TContext>` | Configuration object |
117
+
118
+ ### `TesterOptions<TContext>`
119
+
120
+ ```typescript
121
+ interface TesterOptions<TContext> {
122
+ contextFactory: () => TContext | Promise<TContext>;
123
+ }
124
+ ```
125
+
126
+ ### `tester.callAction(toolName, actionName, args?, overrideContext?)`
127
+
128
+ Executes a single tool action through the **full MVA pipeline** and returns a decomposed result.
129
+
130
+ ```typescript
131
+ async callAction<TArgs>(
132
+ toolName: string,
133
+ actionName: string,
134
+ args?: TArgs,
135
+ overrideContext?: Partial<TContext>,
136
+ ): Promise<MvaTestResult>;
137
+ ```
138
+
139
+ | Parameter | Type | Required | Description |
140
+ |---|---|---|---|
141
+ | `toolName` | `string` | ✅ | The registered tool name (e.g. `'db_user'`, `'analytics'`) |
142
+ | `actionName` | `string` | ✅ | The action discriminator (e.g. `'find_many'`, `'create'`) |
143
+ | `args` | `object` | ❌ | Arguments for the action — omit the `action` discriminator |
144
+ | `overrideContext` | `Partial<TContext>` | ❌ | Per-test context overrides. Shallow-merged with `contextFactory()` output |
145
+
146
+ ### `MvaTestResult<TData>`
147
+
148
+ Decomposed MVA response — each field maps to a specific pipeline layer.
149
+
150
+ | Field | Type | Source | Description |
151
+ |---|---|---|---|
152
+ | `data` | `TData` | Presenter Zod schema | Validated data **after** the Egress Firewall. Hidden fields are physically absent. |
153
+ | `systemRules` | `string[]` | Presenter `.systemRules()` | JIT domain rules injected by the Presenter. Empty array if no Presenter. |
154
+ | `uiBlocks` | `unknown[]` | Presenter `.uiBlocks()` | SSR UI blocks (charts, summaries, markdown). Empty array if no Presenter. |
155
+ | `isError` | `boolean` | Pipeline | `true` if Zod rejected, middleware blocked, or handler returned `error()`. |
156
+ | `rawResponse` | `unknown` | Pipeline | The raw MCP `ToolResponse` for protocol-level inspection. |
157
+
158
+ ## Cookbook
159
+
160
+ ### Egress Firewall Audit
161
+
162
+ ```typescript
163
+ it('strips PII from response', async () => {
164
+ const result = await tester.callAction('db_user', 'find_many', { take: 5 });
165
+
166
+ const users = result.data as Array<Record<string, unknown>>;
167
+ for (const user of users) {
168
+ expect(user).not.toHaveProperty('passwordHash');
169
+ expect(user).not.toHaveProperty('tenantId');
170
+ }
171
+ });
172
+ ```
173
+
174
+ ### Middleware Guards (RBAC)
175
+
176
+ ```typescript
177
+ it('blocks GUEST role', async () => {
178
+ const result = await tester.callAction(
179
+ 'db_user', 'find_many', { take: 5 },
180
+ { role: 'GUEST' },
181
+ );
182
+ expect(result.isError).toBe(true);
183
+ });
184
+
185
+ it('allows ADMIN role', async () => {
186
+ const result = await tester.callAction(
187
+ 'db_user', 'find_many', { take: 5 },
188
+ { role: 'ADMIN' },
189
+ );
190
+ expect(result.isError).toBe(false);
191
+ });
192
+ ```
193
+
194
+ ### Agent Limit (Cognitive Guardrail)
195
+
196
+ ```typescript
197
+ it('truncates at agentLimit', async () => {
198
+ const result = await tester.callAction('analytics', 'list', { limit: 100 });
199
+ expect((result.data as any[]).length).toBe(20);
200
+ });
201
+ ```
202
+
203
+ ### Protocol-Level Inspection
204
+
205
+ ```typescript
206
+ it('raw response follows MCP shape', async () => {
207
+ const result = await tester.callAction('db_user', 'find_many', { take: 1 });
208
+ const raw = result.rawResponse as { content: Array<{ type: string; text: string }> };
209
+
210
+ expect(raw.content).toBeInstanceOf(Array);
211
+ expect(raw.content[0].type).toBe('text');
212
+ });
213
+ ```
214
+
215
+ ## How It Works
216
+
217
+ The `VurbTester` runs the **real** execution pipeline — the exact same code path as your production MCP server:
218
+
219
+ ```
220
+ ToolRegistry.routeCall()
221
+ → Concurrency Semaphore
222
+ → Discriminator Parsing
223
+ → Zod Input Validation
224
+ → Compiled Middleware Chain
225
+ → Handler Execution
226
+ → PostProcessor (Presenter auto-application)
227
+ → Egress Guard
228
+ ```
229
+
230
+ The key insight: `ResponseBuilder.build()` attaches structured MVA metadata via a **global Symbol** (`MVA_META_SYMBOL`). Symbols are ignored by `JSON.stringify`, so the MCP transport never sees them — but the `VurbTester` reads them in RAM.
231
+
232
+ **No XML regex. No string parsing. Zero coupling to response formatting.**
233
+
234
+ ## Installation
235
+
236
+ ```bash
237
+ npm install @vurb/testing
238
+ ```
239
+
240
+ ### Peer Dependencies
241
+
242
+ | Package | Version |
243
+ |---------|---------|
244
+ | `vurb` | `^2.0.0` |
245
+ | `zod` | `^3.25.1 \|\| ^4.0.0` |
246
+
247
+ ## Requirements
248
+
249
+ - **Node.js** ≥ 18.0.0
250
+ - **TypeScript** 5.7+
251
+ - **Vurb.ts** ≥ 2.0.0 (peer dependency)
252
+
253
+ ## License
254
+
255
+ [Apache-2.0](https://github.com/vinkius-labs/vurb.ts/blob/main/LICENSE)
@@ -0,0 +1,98 @@
1
+ /**
2
+ * VurbTester — In-Memory MVA Lifecycle Emulator
3
+ *
4
+ * Runs the **real** Vurb execution pipeline in RAM:
5
+ * Zod Input Validation → Middleware Chain → Handler → PostProcessor → Egress Firewall
6
+ *
7
+ * Decomposes the `ToolResponse` into structured `MvaTestResult` objects
8
+ * using the Symbol Backdoor (`MVA_META_SYMBOL`) — zero XML parsing, zero regex.
9
+ *
10
+ * **Zero coupling to test runners.** Returns plain JS objects. Use with
11
+ * Vitest, Jest, Mocha, or Node's native `node:test`.
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import { createVurbTester } from '@vurb/testing';
16
+ * import { registry } from '../src/server/registry.js';
17
+ *
18
+ * const tester = createVurbTester(registry, {
19
+ * contextFactory: () => ({
20
+ * prisma: mockPrisma,
21
+ * tenantId: 't_777',
22
+ * }),
23
+ * });
24
+ *
25
+ * const result = await tester.callAction('db_user', 'find_many', { take: 10 });
26
+ *
27
+ * expect(result.data[0]).not.toHaveProperty('passwordHash');
28
+ * expect(result.systemRules).toContain('Data originates from the database via Prisma ORM.');
29
+ * ```
30
+ *
31
+ * @module
32
+ */
33
+ import type { ToolRegistry } from 'vurb';
34
+ import type { TesterOptions, MvaTestResult } from './types.js';
35
+ /**
36
+ * In-memory MVA lifecycle emulator.
37
+ *
38
+ * Delegates to `ToolRegistry.routeCall()` for full pipeline fidelity,
39
+ * then extracts structured MVA layers via the Symbol Backdoor.
40
+ *
41
+ * @typeParam TContext - Application context type (matches your ToolRegistry)
42
+ */
43
+ export declare class VurbTester<TContext> {
44
+ private readonly registry;
45
+ private readonly options;
46
+ constructor(registry: ToolRegistry<TContext>, options: TesterOptions<TContext>);
47
+ /**
48
+ * Execute a tool action through the full MVA pipeline in-memory.
49
+ *
50
+ * @param toolName - The registered tool name (e.g. `'db_user'`)
51
+ * @param actionName - The action discriminator (e.g. `'find_many'`)
52
+ * @param args - Arguments for the action (excluding the discriminator)
53
+ * @param overrideContext - Partial context overrides for this specific test
54
+ * (e.g. `{ role: 'GUEST' }` to simulate a different JWT)
55
+ * @returns Decomposed MVA result with `data`, `systemRules`, `uiBlocks`, `isError`
56
+ *
57
+ * @throws {Error} If Zod input validation rejects the args (the ZodError propagates)
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * // Egress Firewall test
62
+ * const result = await tester.callAction('db_user', 'find_many', { take: 10 });
63
+ * expect(result.data[0]).not.toHaveProperty('passwordHash');
64
+ *
65
+ * // OOM Guard test — Zod rejects take > 50
66
+ * await expect(
67
+ * tester.callAction('db_user', 'find_many', { take: 10000 })
68
+ * ).rejects.toThrow();
69
+ *
70
+ * // Middleware test via overrideContext
71
+ * const result = await tester.callAction('db_user', 'create',
72
+ * { email: 'test@co.com' },
73
+ * { role: 'GUEST' }
74
+ * );
75
+ * expect(result.isError).toBe(true);
76
+ * ```
77
+ */
78
+ callAction<TArgs = Record<string, unknown>>(toolName: string, actionName: string, args?: TArgs, overrideContext?: Partial<TContext>): Promise<MvaTestResult>;
79
+ }
80
+ /**
81
+ * Create a VurbTester for the given registry.
82
+ *
83
+ * @param registry - The application's ToolRegistry instance
84
+ * @param options - Context factory and configuration
85
+ * @returns A new VurbTester instance
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * const tester = createVurbTester(registry, {
90
+ * contextFactory: () => ({
91
+ * prisma: mockPrisma,
92
+ * tenantId: 't_enterprise_42',
93
+ * }),
94
+ * });
95
+ * ```
96
+ */
97
+ export declare function createVurbTester<TContext>(registry: ToolRegistry<TContext>, options: TesterOptions<TContext>): VurbTester<TContext>;
98
+ //# sourceMappingURL=VurbTester.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VurbTester.d.ts","sourceRoot":"","sources":["../src/VurbTester.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAGzC,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAI/D;;;;;;;GAOG;AACH,qBAAa,UAAU,CAAC,QAAQ;IAExB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,QAAQ,EAAE,YAAY,CAAC,QAAQ,CAAC,EAChC,OAAO,EAAE,aAAa,CAAC,QAAQ,CAAC;IAGrD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACG,UAAU,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5C,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,IAAI,CAAC,EAAE,KAAK,EACZ,eAAe,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,GACpC,OAAO,CAAC,aAAa,CAAC;CAsD5B;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EACrC,QAAQ,EAAE,YAAY,CAAC,QAAQ,CAAC,EAChC,OAAO,EAAE,aAAa,CAAC,QAAQ,CAAC,GACjC,UAAU,CAAC,QAAQ,CAAC,CAEtB"}
@@ -0,0 +1,123 @@
1
+ import { MVA_META_SYMBOL } from 'vurb';
2
+ // ── VurbTester Class ───────────────────────────────────
3
+ /**
4
+ * In-memory MVA lifecycle emulator.
5
+ *
6
+ * Delegates to `ToolRegistry.routeCall()` for full pipeline fidelity,
7
+ * then extracts structured MVA layers via the Symbol Backdoor.
8
+ *
9
+ * @typeParam TContext - Application context type (matches your ToolRegistry)
10
+ */
11
+ export class VurbTester {
12
+ registry;
13
+ options;
14
+ constructor(registry, options) {
15
+ this.registry = registry;
16
+ this.options = options;
17
+ }
18
+ /**
19
+ * Execute a tool action through the full MVA pipeline in-memory.
20
+ *
21
+ * @param toolName - The registered tool name (e.g. `'db_user'`)
22
+ * @param actionName - The action discriminator (e.g. `'find_many'`)
23
+ * @param args - Arguments for the action (excluding the discriminator)
24
+ * @param overrideContext - Partial context overrides for this specific test
25
+ * (e.g. `{ role: 'GUEST' }` to simulate a different JWT)
26
+ * @returns Decomposed MVA result with `data`, `systemRules`, `uiBlocks`, `isError`
27
+ *
28
+ * @throws {Error} If Zod input validation rejects the args (the ZodError propagates)
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * // Egress Firewall test
33
+ * const result = await tester.callAction('db_user', 'find_many', { take: 10 });
34
+ * expect(result.data[0]).not.toHaveProperty('passwordHash');
35
+ *
36
+ * // OOM Guard test — Zod rejects take > 50
37
+ * await expect(
38
+ * tester.callAction('db_user', 'find_many', { take: 10000 })
39
+ * ).rejects.toThrow();
40
+ *
41
+ * // Middleware test via overrideContext
42
+ * const result = await tester.callAction('db_user', 'create',
43
+ * { email: 'test@co.com' },
44
+ * { role: 'GUEST' }
45
+ * );
46
+ * expect(result.isError).toBe(true);
47
+ * ```
48
+ */
49
+ async callAction(toolName, actionName, args, overrideContext) {
50
+ // 1. Context Hydration
51
+ const baseContext = await this.options.contextFactory();
52
+ const ctx = overrideContext
53
+ ? { ...baseContext, ...overrideContext }
54
+ : baseContext;
55
+ // 2. Build args with discriminator (action AFTER spread to prevent override)
56
+ const builtArgs = {
57
+ ...(args || {}),
58
+ action: actionName,
59
+ };
60
+ // 3. Run the REAL pipeline (validation → middleware → handler → presenter → egress)
61
+ const rawResponse = await this.registry.routeCall(ctx, toolName, builtArgs);
62
+ // 4. Error path — no MVA meta on error responses
63
+ if (rawResponse.isError) {
64
+ const errorText = rawResponse.content?.[0]?.text ?? 'Unknown error';
65
+ return {
66
+ data: errorText,
67
+ systemRules: [],
68
+ uiBlocks: [],
69
+ isError: true,
70
+ rawResponse,
71
+ };
72
+ }
73
+ // 5. Extract MVA Meta via Symbol Backdoor
74
+ const meta = rawResponse[MVA_META_SYMBOL];
75
+ if (meta) {
76
+ return {
77
+ data: meta.data,
78
+ systemRules: [...meta.systemRules],
79
+ uiBlocks: [...meta.uiBlocks],
80
+ isError: false,
81
+ rawResponse,
82
+ };
83
+ }
84
+ // 6. Fallback — tool without Presenter (raw data, no MVA layers)
85
+ const rawText = rawResponse.content?.[0]?.text ?? '';
86
+ let parsedData;
87
+ try {
88
+ parsedData = JSON.parse(rawText);
89
+ }
90
+ catch {
91
+ parsedData = rawText;
92
+ }
93
+ return {
94
+ data: parsedData,
95
+ systemRules: [],
96
+ uiBlocks: [],
97
+ isError: false,
98
+ rawResponse,
99
+ };
100
+ }
101
+ }
102
+ // ── Factory ──────────────────────────────────────────────
103
+ /**
104
+ * Create a VurbTester for the given registry.
105
+ *
106
+ * @param registry - The application's ToolRegistry instance
107
+ * @param options - Context factory and configuration
108
+ * @returns A new VurbTester instance
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * const tester = createVurbTester(registry, {
113
+ * contextFactory: () => ({
114
+ * prisma: mockPrisma,
115
+ * tenantId: 't_enterprise_42',
116
+ * }),
117
+ * });
118
+ * ```
119
+ */
120
+ export function createVurbTester(registry, options) {
121
+ return new VurbTester(registry, options);
122
+ }
123
+ //# sourceMappingURL=VurbTester.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VurbTester.js","sourceRoot":"","sources":["../src/VurbTester.ts"],"names":[],"mappings":"AAiCA,OAAO,EAAE,eAAe,EAAE,MAAM,MAAM,CAAC;AAIvC,0DAA0D;AAE1D;;;;;;;GAOG;AACH,MAAM,OAAO,UAAU;IAEE;IACA;IAFrB,YACqB,QAAgC,EAChC,OAAgC;QADhC,aAAQ,GAAR,QAAQ,CAAwB;QAChC,YAAO,GAAP,OAAO,CAAyB;IAClD,CAAC;IAEJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACH,KAAK,CAAC,UAAU,CACZ,QAAgB,EAChB,UAAkB,EAClB,IAAY,EACZ,eAAmC;QAEnC,uBAAuB;QACvB,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;QACxD,MAAM,GAAG,GAAG,eAAe;YACvB,CAAC,CAAC,EAAE,GAAG,WAAW,EAAE,GAAG,eAAe,EAAc;YACpD,CAAC,CAAC,WAAW,CAAC;QAElB,6EAA6E;QAC7E,MAAM,SAAS,GAA4B;YACvC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;YACf,MAAM,EAAE,UAAU;SACrB,CAAC;QAEF,oFAAoF;QACpF,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;QAE5E,iDAAiD;QACjD,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC;YACtB,MAAM,SAAS,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,eAAe,CAAC;YACpE,OAAO;gBACH,IAAI,EAAE,SAAS;gBACf,WAAW,EAAE,EAAE;gBACf,QAAQ,EAAE,EAAE;gBACZ,OAAO,EAAE,IAAI;gBACb,WAAW;aACd,CAAC;QACN,CAAC;QAED,0CAA0C;QAC1C,MAAM,IAAI,GAAI,WAAkD,CAAC,eAAe,CAAwB,CAAC;QAEzG,IAAI,IAAI,EAAE,CAAC;YACP,OAAO;gBACH,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,WAAW,EAAE,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC;gBAClC,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;gBAC5B,OAAO,EAAE,KAAK;gBACd,WAAW;aACd,CAAC;QACN,CAAC;QAED,iEAAiE;QACjE,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;QACrD,IAAI,UAAmB,CAAC;QACxB,IAAI,CAAC;YAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,UAAU,GAAG,OAAO,CAAC;QAAC,CAAC;QAEzE,OAAO;YACH,IAAI,EAAE,UAAU;YAChB,WAAW,EAAE,EAAE;YACf,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,KAAK;YACd,WAAW;SACd,CAAC;IACN,CAAC;CACJ;AAED,4DAA4D;AAE5D;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,gBAAgB,CAC5B,QAAgC,EAChC,OAAgC;IAEhC,OAAO,IAAI,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @vurb/testing — Barrel Export
3
+ *
4
+ * Public API for the in-memory MVA lifecycle emulator.
5
+ *
6
+ * @module
7
+ */
8
+ export { VurbTester, createVurbTester } from './VurbTester.js';
9
+ export type { TesterOptions, MvaTestResult } from './types.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC/D,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @vurb/testing — Barrel Export
3
+ *
4
+ * Public API for the in-memory MVA lifecycle emulator.
5
+ *
6
+ * @module
7
+ */
8
+ export { VurbTester, createVurbTester } from './VurbTester.js';
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * MVA Test Result Types — Structured Response Decomposition
3
+ *
4
+ * Zero coupling to any test runner. Returns plain JS/TS objects
5
+ * that any framework (Vitest, Jest, Mocha, node:test) can assert against.
6
+ *
7
+ * @module
8
+ */
9
+ /**
10
+ * Configuration for the VurbTester.
11
+ *
12
+ * @typeParam TContext - Application context type (same as your ToolRegistry)
13
+ */
14
+ export interface TesterOptions<TContext> {
15
+ /**
16
+ * Factory that produces the mock context for each test invocation.
17
+ * Inject fake Prisma, fake JWT, fake tenantId here.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * contextFactory: () => ({
22
+ * prisma: mockPrisma,
23
+ * tenantId: 't_777',
24
+ * auth: { role: 'ADMIN' },
25
+ * })
26
+ * ```
27
+ */
28
+ contextFactory: () => TContext | Promise<TContext>;
29
+ }
30
+ /**
31
+ * Decomposed MVA response from the VurbTester.
32
+ *
33
+ * Each field maps to a specific MVA layer, allowing QA to assert
34
+ * each pillar independently without parsing XML or JSON strings.
35
+ *
36
+ * @typeParam TData - The validated data type (post-Egress Firewall)
37
+ */
38
+ export interface MvaTestResult<TData = unknown> {
39
+ /**
40
+ * Validated data AFTER the Egress Firewall (Presenter Zod schema).
41
+ * Hidden fields (`@vurb.hide`) are physically absent here.
42
+ */
43
+ data: TData;
44
+ /**
45
+ * JIT system rules from the Presenter's `.systemRules()`.
46
+ * The LLM reads these as domain-level directives.
47
+ */
48
+ systemRules: readonly string[];
49
+ /**
50
+ * SSR UI blocks from the Presenter's `.uiBlocks()` / `.collectionUiBlocks()`.
51
+ * Contains echarts configs, markdown blocks, summary strings, etc.
52
+ */
53
+ uiBlocks: readonly unknown[];
54
+ /**
55
+ * `true` if the pipeline returned an error response (`isError: true`).
56
+ * Useful for asserting OOM guard rejections, middleware blocks, and handler errors.
57
+ */
58
+ isError: boolean;
59
+ /**
60
+ * The raw MCP `ToolResponse` from the pipeline.
61
+ * For protocol-level inspection (content blocks, XML formatting, etc.)
62
+ */
63
+ rawResponse: unknown;
64
+ }
65
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;GAIG;AACH,MAAM,WAAW,aAAa,CAAC,QAAQ;IACnC;;;;;;;;;;;;OAYG;IACH,cAAc,EAAE,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACtD;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,GAAG,OAAO;IAC1C;;;OAGG;IACH,IAAI,EAAE,KAAK,CAAC;IAEZ;;;OAGG;IACH,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAE/B;;;OAGG;IACH,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IAE7B;;;OAGG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,WAAW,EAAE,OAAO,CAAC;CACxB"}
package/dist/types.js ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * MVA Test Result Types — Structured Response Decomposition
3
+ *
4
+ * Zero coupling to any test runner. Returns plain JS/TS objects
5
+ * that any framework (Vitest, Jest, Mocha, node:test) can assert against.
6
+ *
7
+ * @module
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@vurb/testing",
3
+ "version": "3.1.31",
4
+ "description": "In-memory MVA lifecycle emulator for Vurb. Runs the full pipeline (Zod Input → Middlewares → Handler → Egress Firewall) without network transport. Returns structured MvaTestResult objects — zero coupling to Jest/Vitest.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "test": "vitest run",
17
+ "prepublishOnly": "npm run build"
18
+ },
19
+ "keywords": [
20
+ "mcp",
21
+ "vurb",
22
+ "testing",
23
+ "mva",
24
+ "emulator",
25
+ "ai",
26
+ "llm",
27
+ "soc2",
28
+ "compliance"
29
+ ],
30
+ "author": "Renato Marinho",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/vinkius-labs/vurb.ts.git",
34
+ "directory": "packages/testing"
35
+ },
36
+ "bugs": {
37
+ "url": "https://github.com/vinkius-labs/vurb.ts/issues"
38
+ },
39
+ "homepage": "https://vurb.vinkius.com/",
40
+ "files": [
41
+ "dist",
42
+ "README.md"
43
+ ],
44
+ "engines": {
45
+ "node": ">=18.0.0"
46
+ },
47
+ "publishConfig": {
48
+ "access": "public"
49
+ },
50
+ "peerDependencies": {
51
+ "@vurb/core": "^3.0.0",
52
+ "zod": "^3.25.1 || ^4.0.0"
53
+ },
54
+ "license": "Apache-2.0",
55
+ "devDependencies": {
56
+ "@vurb/core": ">=3.0.0"
57
+ }
58
+ }