@olane/o-test 0.7.12
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/LICENSE +33 -0
- package/README.md +400 -0
- package/dist/src/builders/index.d.ts +7 -0
- package/dist/src/builders/index.d.ts.map +1 -0
- package/dist/src/builders/index.js +6 -0
- package/dist/src/builders/leader-child-builder.d.ts +50 -0
- package/dist/src/builders/leader-child-builder.d.ts.map +1 -0
- package/dist/src/builders/leader-child-builder.js +59 -0
- package/dist/src/builders/manager-worker-builder.d.ts +49 -0
- package/dist/src/builders/manager-worker-builder.d.ts.map +1 -0
- package/dist/src/builders/manager-worker-builder.js +79 -0
- package/dist/src/builders/simple-node-builder.d.ts +49 -0
- package/dist/src/builders/simple-node-builder.d.ts.map +1 -0
- package/dist/src/builders/simple-node-builder.js +66 -0
- package/dist/src/example-tool.tool.d.ts +58 -0
- package/dist/src/example-tool.tool.d.ts.map +1 -0
- package/dist/src/example-tool.tool.js +89 -0
- package/dist/src/fixtures/index.d.ts +6 -0
- package/dist/src/fixtures/index.d.ts.map +1 -0
- package/dist/src/fixtures/index.js +5 -0
- package/dist/src/fixtures/mock-data.d.ts +201 -0
- package/dist/src/fixtures/mock-data.d.ts.map +1 -0
- package/dist/src/fixtures/mock-data.js +180 -0
- package/dist/src/fixtures/test-methods.d.ts +33 -0
- package/dist/src/fixtures/test-methods.d.ts.map +1 -0
- package/dist/src/fixtures/test-methods.js +185 -0
- package/dist/src/index.d.ts +18 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +25 -0
- package/dist/src/methods/example.methods.d.ts +9 -0
- package/dist/src/methods/example.methods.d.ts.map +1 -0
- package/dist/src/methods/example.methods.js +50 -0
- package/dist/src/test-environment.d.ts +185 -0
- package/dist/src/test-environment.d.ts.map +1 -0
- package/dist/src/test-environment.js +260 -0
- package/dist/src/utils/assertions.d.ts +159 -0
- package/dist/src/utils/assertions.d.ts.map +1 -0
- package/dist/src/utils/assertions.js +201 -0
- package/dist/src/utils/chunk-capture.d.ts +108 -0
- package/dist/src/utils/chunk-capture.d.ts.map +1 -0
- package/dist/src/utils/chunk-capture.js +156 -0
- package/dist/src/utils/index.d.ts +8 -0
- package/dist/src/utils/index.d.ts.map +1 -0
- package/dist/src/utils/index.js +7 -0
- package/dist/src/utils/mock-factories.d.ts +211 -0
- package/dist/src/utils/mock-factories.d.ts.map +1 -0
- package/dist/src/utils/mock-factories.js +181 -0
- package/dist/src/utils/wait-for.d.ts +42 -0
- package/dist/src/utils/wait-for.d.ts.map +1 -0
- package/dist/src/utils/wait-for.js +59 -0
- package/dist/test/example.spec.d.ts +1 -0
- package/dist/test/example.spec.d.ts.map +1 -0
- package/dist/test/example.spec.js +240 -0
- package/dist/test/fixtures/mock-data.d.ts +1 -0
- package/dist/test/fixtures/mock-data.d.ts.map +1 -0
- package/dist/test/fixtures/mock-data.js +90 -0
- package/dist/test/test-environment.spec.d.ts +8 -0
- package/dist/test/test-environment.spec.d.ts.map +1 -0
- package/dist/test/test-environment.spec.js +393 -0
- package/package.json +87 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TestEnvironment - Core test setup and lifecycle management for O-Network nodes
|
|
3
|
+
*
|
|
4
|
+
* Provides automatic cleanup, node factories, and common test utilities
|
|
5
|
+
* to eliminate boilerplate in O-Network package tests.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* describe('MyTool', () => {
|
|
10
|
+
* const env = new TestEnvironment();
|
|
11
|
+
*
|
|
12
|
+
* afterEach(async () => {
|
|
13
|
+
* await env.cleanup();
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* it('should work', async () => {
|
|
17
|
+
* const { leader, tool } = await env.createToolWithLeader(MyTool);
|
|
18
|
+
* expect(tool.state).to.equal(NodeState.RUNNING);
|
|
19
|
+
* });
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
import { NodeState } from '@olane/o-core';
|
|
24
|
+
/**
|
|
25
|
+
* Core test environment class for O-Network testing
|
|
26
|
+
*
|
|
27
|
+
* Manages node lifecycle, automatic cleanup, and provides
|
|
28
|
+
* factory methods for common test scenarios.
|
|
29
|
+
*/
|
|
30
|
+
export class TestEnvironment {
|
|
31
|
+
constructor() {
|
|
32
|
+
this.nodes = [];
|
|
33
|
+
this.cleanupCallbacks = [];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Create a leader node for testing
|
|
37
|
+
*
|
|
38
|
+
* @param LeaderClass - Leader node class (e.g., oLeaderNode)
|
|
39
|
+
* @param options - Configuration options
|
|
40
|
+
* @returns Started leader node instance
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* const leader = await env.createLeader(oLeaderNode);
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
async createLeader(LeaderClass, options = {}) {
|
|
48
|
+
const { autoStart = true, ...config } = options;
|
|
49
|
+
const leader = new LeaderClass({
|
|
50
|
+
parent: null,
|
|
51
|
+
leader: null,
|
|
52
|
+
...config,
|
|
53
|
+
});
|
|
54
|
+
this.track(leader);
|
|
55
|
+
if (autoStart) {
|
|
56
|
+
await leader.start();
|
|
57
|
+
}
|
|
58
|
+
return leader;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Create a tool with a leader node
|
|
62
|
+
*
|
|
63
|
+
* Automatically handles:
|
|
64
|
+
* - Leader creation and startup
|
|
65
|
+
* - Tool creation with parent/leader references
|
|
66
|
+
* - Hook injection for child registration
|
|
67
|
+
* - Lifecycle tracking for cleanup
|
|
68
|
+
*
|
|
69
|
+
* @param ToolClass - Tool class to instantiate
|
|
70
|
+
* @param config - Tool configuration
|
|
71
|
+
* @param LeaderClass - Leader class (defaults to oLeaderNode if available)
|
|
72
|
+
* @returns Object with leader and tool instances
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const { leader, tool } = await env.createToolWithLeader(MyTool, {
|
|
77
|
+
* apiKey: 'test-key'
|
|
78
|
+
* });
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
async createToolWithLeader(ToolClass, config = {}, LeaderClass) {
|
|
82
|
+
// Dynamic import to avoid circular dependency
|
|
83
|
+
let leader;
|
|
84
|
+
if (LeaderClass) {
|
|
85
|
+
leader = await this.createLeader(LeaderClass);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
// Try to import oLeaderNode dynamically
|
|
89
|
+
try {
|
|
90
|
+
const { oLeaderNode } = await import('@olane/o-leader');
|
|
91
|
+
leader = await this.createLeader(oLeaderNode);
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
throw new Error('LeaderClass not provided and @olane/o-leader not available. ' +
|
|
95
|
+
'Please provide LeaderClass explicitly.');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const tool = new ToolClass({
|
|
99
|
+
...config,
|
|
100
|
+
parent: leader.address,
|
|
101
|
+
leader: leader.address,
|
|
102
|
+
});
|
|
103
|
+
// Inject hook for parent-child registration
|
|
104
|
+
const originalHook = tool.hookInitializeFinished?.bind(tool);
|
|
105
|
+
tool.hookInitializeFinished = async () => {
|
|
106
|
+
leader.addChildNode(tool);
|
|
107
|
+
if (originalHook) {
|
|
108
|
+
await originalHook();
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
this.track(tool);
|
|
112
|
+
await tool.start();
|
|
113
|
+
return { leader, tool };
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Create a simple node without leader
|
|
117
|
+
*
|
|
118
|
+
* @param NodeClass - Node class to instantiate
|
|
119
|
+
* @param config - Node configuration
|
|
120
|
+
* @param autoStart - Whether to start node automatically (default: true)
|
|
121
|
+
* @returns Node instance
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```typescript
|
|
125
|
+
* const node = await env.createNode(MyTool, {
|
|
126
|
+
* address: new oNodeAddress('o://test')
|
|
127
|
+
* });
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
async createNode(NodeClass, config = {}, autoStart = true) {
|
|
131
|
+
const node = new NodeClass({
|
|
132
|
+
parent: null,
|
|
133
|
+
leader: null,
|
|
134
|
+
...config,
|
|
135
|
+
});
|
|
136
|
+
this.track(node);
|
|
137
|
+
if (autoStart) {
|
|
138
|
+
await node.start();
|
|
139
|
+
}
|
|
140
|
+
return node;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Track a node for automatic cleanup
|
|
144
|
+
*
|
|
145
|
+
* @param node - Node instance to track
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```typescript
|
|
149
|
+
* const node = new MyNode({});
|
|
150
|
+
* env.track(node);
|
|
151
|
+
* await node.start();
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
track(node) {
|
|
155
|
+
this.nodes.push(node);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Register a cleanup callback
|
|
159
|
+
*
|
|
160
|
+
* Useful for cleaning up external resources (databases, files, etc.)
|
|
161
|
+
*
|
|
162
|
+
* @param callback - Async cleanup function
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* const db = await createTestDB();
|
|
167
|
+
* env.onCleanup(async () => {
|
|
168
|
+
* await db.close();
|
|
169
|
+
* });
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
onCleanup(callback) {
|
|
173
|
+
this.cleanupCallbacks.push(callback);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Stop all tracked nodes and execute cleanup callbacks
|
|
177
|
+
*
|
|
178
|
+
* Stops nodes in reverse order (children before parents)
|
|
179
|
+
* Call this in afterEach hooks.
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```typescript
|
|
183
|
+
* afterEach(async () => {
|
|
184
|
+
* await env.cleanup();
|
|
185
|
+
* });
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
async cleanup() {
|
|
189
|
+
// Stop nodes in reverse order (children first)
|
|
190
|
+
const nodesToStop = [...this.nodes].reverse();
|
|
191
|
+
for (const node of nodesToStop) {
|
|
192
|
+
try {
|
|
193
|
+
if (node.state === NodeState.RUNNING) {
|
|
194
|
+
await node.stop();
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
console.error('Error stopping node:', error);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// Execute cleanup callbacks
|
|
202
|
+
for (const callback of this.cleanupCallbacks) {
|
|
203
|
+
try {
|
|
204
|
+
await callback();
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
console.error('Error in cleanup callback:', error);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Clear tracking
|
|
211
|
+
this.nodes = [];
|
|
212
|
+
this.cleanupCallbacks = [];
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Get all tracked nodes
|
|
216
|
+
*
|
|
217
|
+
* @returns Array of tracked node instances
|
|
218
|
+
*/
|
|
219
|
+
getNodes() {
|
|
220
|
+
return [...this.nodes];
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Get count of tracked nodes
|
|
224
|
+
*
|
|
225
|
+
* @returns Number of tracked nodes
|
|
226
|
+
*/
|
|
227
|
+
getNodeCount() {
|
|
228
|
+
return this.nodes.length;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Check if all tracked nodes are stopped
|
|
232
|
+
*
|
|
233
|
+
* @returns True if all nodes are stopped
|
|
234
|
+
*/
|
|
235
|
+
allNodesStopped() {
|
|
236
|
+
return this.nodes.every(node => node.state === NodeState.STOPPED);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Wait for a condition to be true
|
|
240
|
+
*
|
|
241
|
+
* @param condition - Function that returns true when condition is met
|
|
242
|
+
* @param timeoutMs - Maximum time to wait in milliseconds (default: 5000)
|
|
243
|
+
* @param intervalMs - Check interval in milliseconds (default: 100)
|
|
244
|
+
* @returns Promise that resolves when condition is met or rejects on timeout
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* ```typescript
|
|
248
|
+
* await env.waitFor(() => tool.isReady, 10000);
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
async waitFor(condition, timeoutMs = 5000, intervalMs = 100) {
|
|
252
|
+
const startTime = Date.now();
|
|
253
|
+
while (!condition()) {
|
|
254
|
+
if (Date.now() - startTime > timeoutMs) {
|
|
255
|
+
throw new Error(`Timeout waiting for condition after ${timeoutMs}ms`);
|
|
256
|
+
}
|
|
257
|
+
await new Promise(resolve => setTimeout(resolve, intervalMs));
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assertion helpers for O-Network testing
|
|
3
|
+
*
|
|
4
|
+
* Provides type-safe, expressive assertions for common test scenarios
|
|
5
|
+
*/
|
|
6
|
+
import { oResponse } from '@olane/o-core';
|
|
7
|
+
import type { oNode } from '@olane/o-node';
|
|
8
|
+
/**
|
|
9
|
+
* Assert that a tool response indicates success
|
|
10
|
+
*
|
|
11
|
+
* @param response - Tool method response (oResponse)
|
|
12
|
+
* @param message - Optional custom error message
|
|
13
|
+
* @throws Error if response is not successful
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const response = await tool.use(address, { method: 'test', params: {} });
|
|
18
|
+
* assertSuccess(response);
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function assertSuccess(response: oResponse, message?: string): asserts response is oResponse & {
|
|
22
|
+
result: {
|
|
23
|
+
success: true;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Assert that a tool response indicates failure
|
|
28
|
+
*
|
|
29
|
+
* @param response - Tool method response (oResponse)
|
|
30
|
+
* @param expectedError - Optional substring to match in error message
|
|
31
|
+
* @throws Error if response is successful or error doesn't match
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const response = await tool.use(address, { method: 'test', params: {} });
|
|
36
|
+
* assertError(response, 'required');
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function assertError(response: oResponse, expectedError?: string): asserts response is oResponse & {
|
|
40
|
+
result: {
|
|
41
|
+
success: false;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Assert that a node is in running state
|
|
46
|
+
*
|
|
47
|
+
* @param node - Node instance
|
|
48
|
+
* @param message - Optional custom error message
|
|
49
|
+
* @throws Error if node is not running
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* assertRunning(tool);
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare function assertRunning(node: oNode, message?: string): void;
|
|
57
|
+
/**
|
|
58
|
+
* Assert that a node is in stopped state
|
|
59
|
+
*
|
|
60
|
+
* @param node - Node instance
|
|
61
|
+
* @param message - Optional custom error message
|
|
62
|
+
* @throws Error if node is not stopped
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* await tool.stop();
|
|
67
|
+
* assertStopped(tool);
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare function assertStopped(node: oNode, message?: string): void;
|
|
71
|
+
/**
|
|
72
|
+
* Assert that response has data
|
|
73
|
+
*
|
|
74
|
+
* @param response - Tool method response (oResponse)
|
|
75
|
+
* @param message - Optional custom error message
|
|
76
|
+
* @throws Error if response doesn't have data
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```typescript
|
|
80
|
+
* const response = await tool.use(address, { method: 'get_data', params: {} });
|
|
81
|
+
* assertHasData(response);
|
|
82
|
+
* const data = response.result.data;
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export declare function assertHasData(response: oResponse, message?: string): asserts response is oResponse & {
|
|
86
|
+
result: {
|
|
87
|
+
data: any;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Assert that a value is defined (not null or undefined)
|
|
92
|
+
*
|
|
93
|
+
* @param value - Value to check
|
|
94
|
+
* @param name - Name of the value for error message
|
|
95
|
+
* @throws Error if value is null or undefined
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* assertDefined(user, 'user');
|
|
100
|
+
* // Now TypeScript knows user is not null/undefined
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export declare function assertDefined<T>(value: T, name?: string): asserts value is NonNullable<T>;
|
|
104
|
+
/**
|
|
105
|
+
* Assert that an array has expected length
|
|
106
|
+
*
|
|
107
|
+
* @param array - Array to check
|
|
108
|
+
* @param expectedLength - Expected length
|
|
109
|
+
* @param message - Optional custom error message
|
|
110
|
+
* @throws Error if length doesn't match
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* assertArrayLength(items, 5);
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export declare function assertArrayLength(array: any[], expectedLength: number, message?: string): void;
|
|
118
|
+
/**
|
|
119
|
+
* Assert that an object has a property
|
|
120
|
+
*
|
|
121
|
+
* @param obj - Object to check
|
|
122
|
+
* @param property - Property name
|
|
123
|
+
* @param message - Optional custom error message
|
|
124
|
+
* @throws Error if property doesn't exist
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* assertHasProperty(response.result.data, 'userId');
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
export declare function assertHasProperty<T extends object, K extends PropertyKey>(obj: T, property: K, message?: string): asserts obj is T & Record<K, unknown>;
|
|
132
|
+
/**
|
|
133
|
+
* Assert that a value matches one of the expected values
|
|
134
|
+
*
|
|
135
|
+
* @param value - Value to check
|
|
136
|
+
* @param expectedValues - Array of expected values
|
|
137
|
+
* @param message - Optional custom error message
|
|
138
|
+
* @throws Error if value doesn't match any expected value
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```typescript
|
|
142
|
+
* assertOneOf(status, ['pending', 'active', 'completed']);
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
export declare function assertOneOf<T>(value: T, expectedValues: T[], message?: string): void;
|
|
146
|
+
/**
|
|
147
|
+
* Create a custom assertion
|
|
148
|
+
*
|
|
149
|
+
* @param condition - Condition to check
|
|
150
|
+
* @param message - Error message if condition is false
|
|
151
|
+
* @throws Error if condition is false
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* assert(user.age >= 18, 'User must be 18 or older');
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
export declare function assert(condition: boolean, message: string): asserts condition;
|
|
159
|
+
//# sourceMappingURL=assertions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assertions.d.ts","sourceRoot":"","sources":["../../../src/utils/assertions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAa,SAAS,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAE3C;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,SAAS,EACnB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,QAAQ,IAAI,SAAS,GAAG;IAAE,MAAM,EAAE;QAAE,OAAO,EAAE,IAAI,CAAA;KAAE,CAAA;CAAE,CAK/D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,SAAS,EACnB,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,QAAQ,IAAI,SAAS,GAAG;IAAE,MAAM,EAAE;QAAE,OAAO,EAAE,KAAK,CAAA;KAAE,CAAA;CAAE,CAchE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,KAAK,EACX,OAAO,CAAC,EAAE,MAAM,GACf,IAAI,CAKN;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,KAAK,EACX,OAAO,CAAC,EAAE,MAAM,GACf,IAAI,CAKN;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,SAAS,EACnB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,QAAQ,IAAI,SAAS,GAAG;IAAE,MAAM,EAAE;QAAE,IAAI,EAAE,GAAG,CAAA;KAAE,CAAA;CAAE,CAK3D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,KAAK,EAAE,CAAC,EACR,IAAI,GAAE,MAAgB,GACrB,OAAO,CAAC,KAAK,IAAI,WAAW,CAAC,CAAC,CAAC,CAIjC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,GAAG,EAAE,EACZ,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,MAAM,GACf,IAAI,CAMN;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,WAAW,EACvE,GAAG,EAAE,CAAC,EACN,QAAQ,EAAE,CAAC,EACX,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAMvC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,KAAK,EAAE,CAAC,EACR,cAAc,EAAE,CAAC,EAAE,EACnB,OAAO,CAAC,EAAE,MAAM,GACf,IAAI,CAMN;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,MAAM,CACpB,SAAS,EAAE,OAAO,EAClB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,SAAS,CAInB"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assertion helpers for O-Network testing
|
|
3
|
+
*
|
|
4
|
+
* Provides type-safe, expressive assertions for common test scenarios
|
|
5
|
+
*/
|
|
6
|
+
import { NodeState } from '@olane/o-core';
|
|
7
|
+
/**
|
|
8
|
+
* Assert that a tool response indicates success
|
|
9
|
+
*
|
|
10
|
+
* @param response - Tool method response (oResponse)
|
|
11
|
+
* @param message - Optional custom error message
|
|
12
|
+
* @throws Error if response is not successful
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const response = await tool.use(address, { method: 'test', params: {} });
|
|
17
|
+
* assertSuccess(response);
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export function assertSuccess(response, message) {
|
|
21
|
+
if (!response.result.success) {
|
|
22
|
+
const errorMsg = message || `Expected success but got error: ${response.result.error}`;
|
|
23
|
+
throw new Error(errorMsg);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Assert that a tool response indicates failure
|
|
28
|
+
*
|
|
29
|
+
* @param response - Tool method response (oResponse)
|
|
30
|
+
* @param expectedError - Optional substring to match in error message
|
|
31
|
+
* @throws Error if response is successful or error doesn't match
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const response = await tool.use(address, { method: 'test', params: {} });
|
|
36
|
+
* assertError(response, 'required');
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export function assertError(response, expectedError) {
|
|
40
|
+
if (response.result.success) {
|
|
41
|
+
throw new Error('Expected error but got success');
|
|
42
|
+
}
|
|
43
|
+
const errorMessage = typeof response.result.error === 'string'
|
|
44
|
+
? response.result.error
|
|
45
|
+
: response.result.error?.message || JSON.stringify(response.result.error);
|
|
46
|
+
if (expectedError && !errorMessage?.includes(expectedError)) {
|
|
47
|
+
throw new Error(`Expected error to include "${expectedError}" but got: ${errorMessage}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Assert that a node is in running state
|
|
52
|
+
*
|
|
53
|
+
* @param node - Node instance
|
|
54
|
+
* @param message - Optional custom error message
|
|
55
|
+
* @throws Error if node is not running
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* assertRunning(tool);
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export function assertRunning(node, message) {
|
|
63
|
+
if (node.state !== NodeState.RUNNING) {
|
|
64
|
+
const errorMsg = message || `Expected node to be RUNNING but got ${node.state}`;
|
|
65
|
+
throw new Error(errorMsg);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Assert that a node is in stopped state
|
|
70
|
+
*
|
|
71
|
+
* @param node - Node instance
|
|
72
|
+
* @param message - Optional custom error message
|
|
73
|
+
* @throws Error if node is not stopped
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* await tool.stop();
|
|
78
|
+
* assertStopped(tool);
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export function assertStopped(node, message) {
|
|
82
|
+
if (node.state !== NodeState.STOPPED) {
|
|
83
|
+
const errorMsg = message || `Expected node to be STOPPED but got ${node.state}`;
|
|
84
|
+
throw new Error(errorMsg);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Assert that response has data
|
|
89
|
+
*
|
|
90
|
+
* @param response - Tool method response (oResponse)
|
|
91
|
+
* @param message - Optional custom error message
|
|
92
|
+
* @throws Error if response doesn't have data
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* const response = await tool.use(address, { method: 'get_data', params: {} });
|
|
97
|
+
* assertHasData(response);
|
|
98
|
+
* const data = response.result.data;
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export function assertHasData(response, message) {
|
|
102
|
+
if (!response.result?.data) {
|
|
103
|
+
const errorMsg = message || 'Expected response to have result.data';
|
|
104
|
+
throw new Error(errorMsg);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Assert that a value is defined (not null or undefined)
|
|
109
|
+
*
|
|
110
|
+
* @param value - Value to check
|
|
111
|
+
* @param name - Name of the value for error message
|
|
112
|
+
* @throws Error if value is null or undefined
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* assertDefined(user, 'user');
|
|
117
|
+
* // Now TypeScript knows user is not null/undefined
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
export function assertDefined(value, name = 'value') {
|
|
121
|
+
if (value === null || value === undefined) {
|
|
122
|
+
throw new Error(`Expected ${name} to be defined but got ${value}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Assert that an array has expected length
|
|
127
|
+
*
|
|
128
|
+
* @param array - Array to check
|
|
129
|
+
* @param expectedLength - Expected length
|
|
130
|
+
* @param message - Optional custom error message
|
|
131
|
+
* @throws Error if length doesn't match
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```typescript
|
|
135
|
+
* assertArrayLength(items, 5);
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
export function assertArrayLength(array, expectedLength, message) {
|
|
139
|
+
if (array.length !== expectedLength) {
|
|
140
|
+
const errorMsg = message ||
|
|
141
|
+
`Expected array length ${expectedLength} but got ${array.length}`;
|
|
142
|
+
throw new Error(errorMsg);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Assert that an object has a property
|
|
147
|
+
*
|
|
148
|
+
* @param obj - Object to check
|
|
149
|
+
* @param property - Property name
|
|
150
|
+
* @param message - Optional custom error message
|
|
151
|
+
* @throws Error if property doesn't exist
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* assertHasProperty(response.result.data, 'userId');
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
export function assertHasProperty(obj, property, message) {
|
|
159
|
+
if (!(property in obj)) {
|
|
160
|
+
const errorMsg = message ||
|
|
161
|
+
`Expected object to have property "${String(property)}"`;
|
|
162
|
+
throw new Error(errorMsg);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Assert that a value matches one of the expected values
|
|
167
|
+
*
|
|
168
|
+
* @param value - Value to check
|
|
169
|
+
* @param expectedValues - Array of expected values
|
|
170
|
+
* @param message - Optional custom error message
|
|
171
|
+
* @throws Error if value doesn't match any expected value
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* assertOneOf(status, ['pending', 'active', 'completed']);
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
export function assertOneOf(value, expectedValues, message) {
|
|
179
|
+
if (!expectedValues.includes(value)) {
|
|
180
|
+
const errorMsg = message ||
|
|
181
|
+
`Expected one of [${expectedValues.join(', ')}] but got ${value}`;
|
|
182
|
+
throw new Error(errorMsg);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Create a custom assertion
|
|
187
|
+
*
|
|
188
|
+
* @param condition - Condition to check
|
|
189
|
+
* @param message - Error message if condition is false
|
|
190
|
+
* @throws Error if condition is false
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```typescript
|
|
194
|
+
* assert(user.age >= 18, 'User must be 18 or older');
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
export function assert(condition, message) {
|
|
198
|
+
if (!condition) {
|
|
199
|
+
throw new Error(message);
|
|
200
|
+
}
|
|
201
|
+
}
|