@kb-labs/shared-testing-platform 2.96.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/README.md +20 -0
- package/dist/index.d.ts +270 -0
- package/dist/index.js +1175 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# @kb-labs/shared-testing-platform
|
|
2
|
+
|
|
3
|
+
Platform setup utilities for testing KB Labs plugins.
|
|
4
|
+
|
|
5
|
+
Requires `@kb-labs/core-runtime` (concrete implementation). For pure mocks only, use `@kb-labs/shared-testing`.
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { createTestContext, testCommand, mockLLM } from '@kb-labs/sdk/testing';
|
|
11
|
+
|
|
12
|
+
const llm = mockLLM().onAnyComplete().respondWith('hello');
|
|
13
|
+
const { ctx, cleanup } = createTestContext({ platform: { llm } });
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Exports
|
|
17
|
+
|
|
18
|
+
- `setupTestPlatform` — sets test mocks into the global platform singleton
|
|
19
|
+
- `createTestContext` — factory for `PluginContextV3` with injected mocks
|
|
20
|
+
- `testCommand` — single-function runner for plugin command handlers
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { platform } from '@kb-labs/core-runtime';
|
|
2
|
+
import { ILLM, ICache, IEmbeddings, IVectorStore, IStorage, IAnalytics, ILogger, IEventBus } from '@kb-labs/core-platform';
|
|
3
|
+
import { HostContext, PlatformServices, UIFacade, PluginContextV3, PluginAPI, EnvironmentAPI, RuntimeAPI, SnapshotAPI, TraceContext, WorkspaceAPI } from '@kb-labs/plugin-contracts';
|
|
4
|
+
import { IDocumentDatabase, EnsureCollectionOpts, BaseDocument, DocumentFilter, FindOptions, ProjectOpts, SignalOpts, DocumentUpdate, BulkOp, BulkResult, IDocumentTransaction, IKVStore, SetOpts } from '@kb-labs/core-platform/adapters';
|
|
5
|
+
export { LLMCall, LLMToolCallRecord, LogEntry, MockCacheInstance, MockEmbeddings, MockLLM, MockLLMInstance, MockLoggerInstance, MockStorageInstance, mockCache, mockLLM, mockLogger, mockStorage } from '@kb-labs/shared-testing';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @module @kb-labs/shared-testing-platform/setup-platform
|
|
9
|
+
*
|
|
10
|
+
* Solves the "singleton gap" problem: composables (useLLM, useCache, etc.)
|
|
11
|
+
* read from the global platform singleton, but createTestContext() only
|
|
12
|
+
* populates ctx.platform. This module bridges the gap by setting test mocks
|
|
13
|
+
* directly into the global singleton.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Options for setting up the test platform.
|
|
18
|
+
* Only adapters that are provided will be registered.
|
|
19
|
+
* Omitted adapters will use the PlatformContainer's built-in fallbacks.
|
|
20
|
+
*/
|
|
21
|
+
interface TestPlatformOptions {
|
|
22
|
+
llm?: ILLM;
|
|
23
|
+
cache?: ICache;
|
|
24
|
+
embeddings?: IEmbeddings;
|
|
25
|
+
vectorStore?: IVectorStore;
|
|
26
|
+
storage?: IStorage;
|
|
27
|
+
analytics?: IAnalytics;
|
|
28
|
+
logger?: ILogger;
|
|
29
|
+
eventBus?: IEventBus;
|
|
30
|
+
}
|
|
31
|
+
interface TestPlatformResult {
|
|
32
|
+
/** The global platform singleton (with test mocks applied) */
|
|
33
|
+
platform: typeof platform;
|
|
34
|
+
/** Call in afterEach() to reset the singleton to a clean state */
|
|
35
|
+
cleanup: () => void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Setup the global platform singleton with test mocks.
|
|
39
|
+
*
|
|
40
|
+
* This ensures that useLLM(), useCache() and other composables
|
|
41
|
+
* return the test mocks instead of uninitialized/stale adapters.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* import { setupTestPlatform, mockLLM } from '@kb-labs/shared-testing-platform';
|
|
46
|
+
*
|
|
47
|
+
* describe('my handler', () => {
|
|
48
|
+
* let cleanup: () => void;
|
|
49
|
+
*
|
|
50
|
+
* beforeEach(() => {
|
|
51
|
+
* const result = setupTestPlatform({
|
|
52
|
+
* llm: mockLLM().onAnyComplete().respondWith('hello'),
|
|
53
|
+
* });
|
|
54
|
+
* cleanup = result.cleanup;
|
|
55
|
+
* });
|
|
56
|
+
*
|
|
57
|
+
* afterEach(() => cleanup());
|
|
58
|
+
* });
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
declare function setupTestPlatform(options?: TestPlatformOptions): TestPlatformResult;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @module @kb-labs/shared-testing-platform/create-test-context
|
|
65
|
+
*
|
|
66
|
+
* Enhanced test context factory that bridges ctx.platform and the global singleton.
|
|
67
|
+
*
|
|
68
|
+
* Unlike the original createTestContext() from SDK, this version:
|
|
69
|
+
* - Uses mockLLM/mockCache/mockLogger with vi.fn() spies (not noop functions)
|
|
70
|
+
* - Syncs ctx.platform adapters with the global singleton via setupTestPlatform()
|
|
71
|
+
* - Provides a cleanup function to reset the singleton in afterEach()
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```typescript
|
|
75
|
+
* import { createTestContext, mockLLM } from '@kb-labs/shared-testing-platform';
|
|
76
|
+
*
|
|
77
|
+
* const llm = mockLLM().onAnyComplete().respondWith('hello');
|
|
78
|
+
* const { ctx, cleanup } = createTestContext({ platform: { llm } });
|
|
79
|
+
*
|
|
80
|
+
* // Both work — ctx.platform and useLLM() return the same mock
|
|
81
|
+
* await handler.execute(ctx, args);
|
|
82
|
+
* expect(llm.complete).toHaveBeenCalled();
|
|
83
|
+
*
|
|
84
|
+
* cleanup(); // Reset singleton in afterEach
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
|
|
88
|
+
interface CreateTestContextOptions {
|
|
89
|
+
pluginId?: string;
|
|
90
|
+
pluginVersion?: string;
|
|
91
|
+
host?: 'cli' | 'rest' | 'workflow' | 'webhook';
|
|
92
|
+
hostContext?: HostContext;
|
|
93
|
+
config?: unknown;
|
|
94
|
+
cwd?: string;
|
|
95
|
+
outdir?: string;
|
|
96
|
+
tenantId?: string;
|
|
97
|
+
signal?: AbortSignal;
|
|
98
|
+
/** Override platform services. Also synced to global singleton. */
|
|
99
|
+
platform?: Partial<PlatformServices>;
|
|
100
|
+
/** Override UI facade */
|
|
101
|
+
ui?: Partial<UIFacade>;
|
|
102
|
+
/**
|
|
103
|
+
* If true, sync platform adapters to the global singleton
|
|
104
|
+
* so that useLLM(), useCache(), etc. return the test mocks.
|
|
105
|
+
* @default true
|
|
106
|
+
*/
|
|
107
|
+
syncSingleton?: boolean;
|
|
108
|
+
}
|
|
109
|
+
interface TestContextResult<TConfig = unknown> {
|
|
110
|
+
/** The plugin context with test mocks */
|
|
111
|
+
ctx: PluginContextV3<TConfig>;
|
|
112
|
+
/** Call in afterEach() to reset the global singleton */
|
|
113
|
+
cleanup: () => void;
|
|
114
|
+
}
|
|
115
|
+
declare function createMockTrace(): TraceContext;
|
|
116
|
+
declare function createMockUI(): UIFacade;
|
|
117
|
+
declare function createMockRuntime(): RuntimeAPI;
|
|
118
|
+
declare function createMockEnvironmentAPI(): EnvironmentAPI;
|
|
119
|
+
declare function createMockWorkspaceAPI(): WorkspaceAPI;
|
|
120
|
+
declare function createMockSnapshotAPI(): SnapshotAPI;
|
|
121
|
+
declare function createInfraApiMocks(): Pick<PluginAPI, 'environment' | 'workspace' | 'snapshot'>;
|
|
122
|
+
declare function createMockPluginAPI(): PluginAPI;
|
|
123
|
+
declare const createMockPlatformApi: typeof createMockPluginAPI;
|
|
124
|
+
declare function createMockPluginContextV3<TConfig = unknown>(options?: CreateTestContextOptions): TestContextResult<TConfig>;
|
|
125
|
+
/**
|
|
126
|
+
* Create a test context for plugin development.
|
|
127
|
+
*
|
|
128
|
+
* Uses mock builders with vi.fn() spies and syncs platform adapters
|
|
129
|
+
* to the global singleton by default so that composables work in tests.
|
|
130
|
+
*/
|
|
131
|
+
declare function createTestContext<TConfig = unknown>(options?: CreateTestContextOptions): TestContextResult<TConfig>;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @module @kb-labs/shared-testing-platform/test-command
|
|
135
|
+
*
|
|
136
|
+
* Single-function test runner for plugin command handlers.
|
|
137
|
+
*/
|
|
138
|
+
|
|
139
|
+
interface TestableHandler<TConfig = unknown, TInput = unknown, TResult = unknown> {
|
|
140
|
+
execute(context: PluginContextV3<TConfig>, input: TInput): Promise<TResult> | TResult;
|
|
141
|
+
cleanup?(): Promise<void> | void;
|
|
142
|
+
}
|
|
143
|
+
interface TestCommandOptions<TConfig = unknown> {
|
|
144
|
+
flags?: Record<string, unknown>;
|
|
145
|
+
argv?: string[];
|
|
146
|
+
query?: Record<string, unknown>;
|
|
147
|
+
body?: unknown;
|
|
148
|
+
params?: Record<string, unknown>;
|
|
149
|
+
input?: unknown;
|
|
150
|
+
host?: 'cli' | 'rest' | 'workflow' | 'webhook';
|
|
151
|
+
config?: TConfig;
|
|
152
|
+
cwd?: string;
|
|
153
|
+
tenantId?: string;
|
|
154
|
+
signal?: AbortSignal;
|
|
155
|
+
platform?: Partial<PlatformServices>;
|
|
156
|
+
ui?: Partial<UIFacade>;
|
|
157
|
+
syncSingleton?: boolean;
|
|
158
|
+
}
|
|
159
|
+
interface TestCommandResult<TResult = unknown> {
|
|
160
|
+
exitCode: number;
|
|
161
|
+
result: TResult | undefined;
|
|
162
|
+
meta: Record<string, unknown> | undefined;
|
|
163
|
+
raw: unknown;
|
|
164
|
+
ui: UIFacade;
|
|
165
|
+
ctx: PluginContextV3;
|
|
166
|
+
cleanup: () => void;
|
|
167
|
+
}
|
|
168
|
+
declare function testCommand<TResult = unknown, TConfig = unknown>(handler: TestableHandler<TConfig, any, any>, options?: TestCommandOptions<TConfig>): Promise<TestCommandResult<TResult>>;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* In-memory `IDocumentDatabase` for tests.
|
|
172
|
+
*
|
|
173
|
+
* Scope: behavioural fidelity sufficient for governance / wrapper tests —
|
|
174
|
+
* CRUD, filters, updates, atomic bulkWrite, transactions, ensureCollection,
|
|
175
|
+
* unique indexes. Not optimised, not for production. Sweep-based TTL is
|
|
176
|
+
* intentionally absent (not exercised by the governance suite).
|
|
177
|
+
*/
|
|
178
|
+
|
|
179
|
+
interface InMemoryDocumentDatabaseOptions {
|
|
180
|
+
/** Seed clock value for new documents. Defaults to `Date.now()` at call site. */
|
|
181
|
+
now?: () => number;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* In-memory `IDocumentDatabase` for tests.
|
|
185
|
+
*
|
|
186
|
+
* Storage layout: `Map<collectionName, Collection>`. Each `Collection` holds
|
|
187
|
+
* a `Map<id, doc>` and a list of declared indexes (used for uniqueness checks).
|
|
188
|
+
*/
|
|
189
|
+
declare class InMemoryDocumentDatabase implements IDocumentDatabase {
|
|
190
|
+
private readonly collections;
|
|
191
|
+
private readonly now;
|
|
192
|
+
private closed;
|
|
193
|
+
constructor(opts?: InMemoryDocumentDatabaseOptions);
|
|
194
|
+
private getCollection;
|
|
195
|
+
private throwIfClosed;
|
|
196
|
+
ensureCollection(name: string, options?: EnsureCollectionOpts): Promise<void>;
|
|
197
|
+
find<T extends BaseDocument, P = T>(collection: string, filter: DocumentFilter<T>, options?: FindOptions & ProjectOpts<T, P> & SignalOpts): Promise<P[]>;
|
|
198
|
+
findStream<T extends BaseDocument, P = T>(collection: string, filter: DocumentFilter<T>, options?: FindOptions & ProjectOpts<T, P> & SignalOpts & {
|
|
199
|
+
batchSize?: number;
|
|
200
|
+
}): AsyncIterable<P>;
|
|
201
|
+
findById<T extends BaseDocument>(collection: string, id: string): Promise<T | null>;
|
|
202
|
+
count<T extends BaseDocument>(collection: string, filter: DocumentFilter<T>): Promise<number>;
|
|
203
|
+
insertOne<T extends BaseDocument>(collection: string, doc: Omit<T, 'id' | 'createdAt' | 'updatedAt'>): Promise<T>;
|
|
204
|
+
insertMany<T extends BaseDocument>(collection: string, docs: Array<Omit<T, 'id' | 'createdAt' | 'updatedAt'>>): Promise<T[]>;
|
|
205
|
+
updateOne<T extends BaseDocument>(collection: string, filter: DocumentFilter<T>, update: DocumentUpdate<T>, options?: SignalOpts & {
|
|
206
|
+
upsert?: boolean;
|
|
207
|
+
}): Promise<T | null>;
|
|
208
|
+
updateMany<T extends BaseDocument>(collection: string, filter: DocumentFilter<T>, update: DocumentUpdate<T>): Promise<number>;
|
|
209
|
+
updateById<T extends BaseDocument>(collection: string, id: string, update: DocumentUpdate<T>): Promise<T | null>;
|
|
210
|
+
deleteMany<T extends BaseDocument>(collection: string, filter: DocumentFilter<T>): Promise<number>;
|
|
211
|
+
deleteById(collection: string, id: string): Promise<boolean>;
|
|
212
|
+
bulkWrite<T extends BaseDocument>(collection: string, ops: Array<BulkOp<T>>): Promise<BulkResult>;
|
|
213
|
+
transaction<T>(fn: (tx: IDocumentTransaction) => Promise<T>): Promise<T>;
|
|
214
|
+
ping(): Promise<{
|
|
215
|
+
ok: boolean;
|
|
216
|
+
latencyMs: number;
|
|
217
|
+
}>;
|
|
218
|
+
close(): Promise<void>;
|
|
219
|
+
}
|
|
220
|
+
declare function createInMemoryDocumentDatabase(opts?: InMemoryDocumentDatabaseOptions): InMemoryDocumentDatabase;
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* In-memory `IKVStore` for tests. Sufficient for governance / wrapper tests:
|
|
224
|
+
* full method surface, TTL respected on read (lazy expiry), atomic CAS / incr
|
|
225
|
+
* via the single-threaded event loop. No background sweeper.
|
|
226
|
+
*/
|
|
227
|
+
|
|
228
|
+
declare class InMemoryKVStore implements IKVStore {
|
|
229
|
+
private readonly map;
|
|
230
|
+
private closed;
|
|
231
|
+
private throwIfClosed;
|
|
232
|
+
private isExpired;
|
|
233
|
+
private getLive;
|
|
234
|
+
get<T = unknown>(key: string): Promise<T | null>;
|
|
235
|
+
getMany<T = unknown>(keys: string[]): Promise<Array<T | null>>;
|
|
236
|
+
set<T = unknown>(key: string, value: T, options?: SetOpts): Promise<boolean>;
|
|
237
|
+
setMany<T = unknown>(entries: Array<{
|
|
238
|
+
key: string;
|
|
239
|
+
value: T;
|
|
240
|
+
ttlMs?: number;
|
|
241
|
+
}>): Promise<void>;
|
|
242
|
+
setIfNotExists<T = unknown>(key: string, value: T, options?: {
|
|
243
|
+
ttlMs?: number;
|
|
244
|
+
} & SignalOpts): Promise<boolean>;
|
|
245
|
+
delete(key: string): Promise<boolean>;
|
|
246
|
+
exists(key: string): Promise<boolean>;
|
|
247
|
+
cas<T = unknown>(key: string, expected: T, next: T, options?: {
|
|
248
|
+
ttlMs?: number;
|
|
249
|
+
} & SignalOpts): Promise<boolean>;
|
|
250
|
+
incr(key: string, delta?: number, options?: {
|
|
251
|
+
ttlMs?: number;
|
|
252
|
+
} & SignalOpts): Promise<number>;
|
|
253
|
+
ttl(key: string): Promise<number | null>;
|
|
254
|
+
expire(key: string, ttlMs: number): Promise<boolean>;
|
|
255
|
+
persist(key: string): Promise<boolean>;
|
|
256
|
+
scan(prefix?: string, _options?: {
|
|
257
|
+
batchSize?: number;
|
|
258
|
+
} & SignalOpts): AsyncIterable<{
|
|
259
|
+
key: string;
|
|
260
|
+
value: unknown;
|
|
261
|
+
}>;
|
|
262
|
+
ping(): Promise<{
|
|
263
|
+
ok: boolean;
|
|
264
|
+
latencyMs: number;
|
|
265
|
+
}>;
|
|
266
|
+
close(): Promise<void>;
|
|
267
|
+
}
|
|
268
|
+
declare function createInMemoryKVStore(): InMemoryKVStore;
|
|
269
|
+
|
|
270
|
+
export { type CreateTestContextOptions, InMemoryDocumentDatabase, type InMemoryDocumentDatabaseOptions, InMemoryKVStore, type TestCommandOptions, type TestCommandResult, type TestContextResult, type TestPlatformOptions, type TestPlatformResult, type TestableHandler, createInMemoryDocumentDatabase, createInMemoryKVStore, createInfraApiMocks, createMockEnvironmentAPI, createMockPlatformApi, createMockPluginAPI, createMockPluginContextV3, createMockRuntime, createMockSnapshotAPI, createMockTrace, createMockUI, createMockWorkspaceAPI, createTestContext, setupTestPlatform, testCommand };
|