@ai.ntellect/core 0.7.5 → 0.7.7
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/graph/controller.d.ts +8 -10
- package/dist/graph/controller.d.ts.map +1 -1
- package/dist/graph/controller.js +25 -27
- package/dist/graph/controller.js.map +1 -1
- package/dist/graph/index.d.ts +5 -3
- package/dist/graph/index.d.ts.map +1 -1
- package/dist/graph/index.js +13 -9
- package/dist/graph/index.js.map +1 -1
- package/dist/graph/node.d.ts +15 -26
- package/dist/graph/node.d.ts.map +1 -1
- package/dist/graph/node.js +66 -101
- package/dist/graph/node.js.map +1 -1
- package/dist/graph/observer.d.ts.map +1 -1
- package/dist/graph/observer.js +0 -1
- package/dist/graph/observer.js.map +1 -1
- package/dist/types/index.d.ts +5 -5
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/generate-action-schema.js +2 -2
- package/graph/controller.ts +36 -40
- package/graph/index.ts +17 -13
- package/graph/node.ts +79 -134
- package/graph/observer.ts +0 -1
- package/package.json +1 -1
- package/test/graph/controller.test.ts +187 -0
- package/test/graph/index.test.ts +138 -97
- package/test/graph/node.test.ts +319 -6
- package/types/index.ts +5 -8
- package/utils/generate-action-schema.ts +2 -2
package/test/graph/index.test.ts
CHANGED
@@ -1,19 +1,27 @@
|
|
1
|
-
import { expect } from "chai";
|
1
|
+
import { expect, use } from "chai";
|
2
|
+
import chaiAsPromised from "chai-as-promised";
|
2
3
|
import EventEmitter from "events";
|
3
4
|
import sinon from "sinon";
|
4
5
|
import { z } from "zod";
|
5
6
|
import { GraphController } from "../../graph/controller";
|
6
7
|
import { GraphFlow } from "../../graph/index";
|
8
|
+
import { NodeParams } from "../../graph/node";
|
7
9
|
import { GraphContext, GraphDefinition, Node } from "../../types";
|
8
10
|
|
11
|
+
use(chaiAsPromised);
|
12
|
+
|
9
13
|
/**
|
10
14
|
* Test schema definition using Zod for graph context validation
|
11
15
|
* Defines a schema with:
|
12
16
|
* - value: numeric value for tracking state changes
|
17
|
+
* - counter: numeric value for tracking state changes
|
18
|
+
* - message: string for tracking state changes
|
13
19
|
* - eventPayload: optional object containing transaction metadata
|
14
20
|
*/
|
15
21
|
const TestSchema = z.object({
|
16
22
|
value: z.number().default(0),
|
23
|
+
counter: z.number().default(0),
|
24
|
+
message: z.string().default(""),
|
17
25
|
eventPayload: z
|
18
26
|
.object({
|
19
27
|
transactionId: z.string().optional(),
|
@@ -172,17 +180,15 @@ describe("GraphFlow", function () {
|
|
172
180
|
* - Integration between node execution and validation
|
173
181
|
* Ensures type safety and data consistency in node interactions
|
174
182
|
*/
|
175
|
-
it("should execute a node with validated
|
183
|
+
it("should execute a node with validated params and outputs", async function () {
|
176
184
|
const paramNode: Node<TestSchema, { increment: number }> = {
|
177
185
|
name: "paramNode",
|
178
|
-
|
186
|
+
params: z.object({
|
179
187
|
increment: z.number(),
|
180
188
|
}),
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
execute: async (context, inputs: { increment: number }) => {
|
185
|
-
context.value = (context.value ?? 0) + inputs.increment;
|
189
|
+
execute: async (context, params?: { increment: number }) => {
|
190
|
+
if (!params) throw new Error("params required");
|
191
|
+
context.value = (context.value ?? 0) + params.increment;
|
186
192
|
},
|
187
193
|
next: [],
|
188
194
|
};
|
@@ -230,30 +236,31 @@ describe("GraphFlow", function () {
|
|
230
236
|
*/
|
231
237
|
it("should retry a node execution when it fails", async () => {
|
232
238
|
let attempts = 0;
|
233
|
-
const
|
234
|
-
|
235
|
-
|
236
|
-
execute: async () => {
|
239
|
+
const retryNode: Node<TestSchema> = {
|
240
|
+
name: "retryNode",
|
241
|
+
execute: async (context) => {
|
237
242
|
attempts++;
|
238
243
|
if (attempts < 3) {
|
239
244
|
throw new Error("Temporary failure");
|
240
245
|
}
|
246
|
+
context.value = 42;
|
241
247
|
},
|
242
248
|
retry: {
|
243
249
|
maxAttempts: 3,
|
244
250
|
delay: 100,
|
245
251
|
},
|
246
|
-
}
|
252
|
+
};
|
247
253
|
|
248
254
|
const graph = new GraphFlow("test", {
|
249
255
|
name: "test",
|
250
256
|
schema: TestSchema,
|
251
257
|
context: { value: 0 },
|
252
|
-
nodes:
|
258
|
+
nodes: [retryNode],
|
253
259
|
});
|
254
260
|
|
255
|
-
await graph.execute("
|
261
|
+
await graph.execute("retryNode");
|
256
262
|
expect(attempts).to.equal(3);
|
263
|
+
expect(graph.getContext().value).to.equal(42);
|
257
264
|
});
|
258
265
|
|
259
266
|
/**
|
@@ -300,21 +307,22 @@ describe("GraphFlow", function () {
|
|
300
307
|
* Tests input validation error handling
|
301
308
|
*/
|
302
309
|
it("should throw error when node input validation fails", async () => {
|
303
|
-
const
|
304
|
-
|
305
|
-
|
310
|
+
const node: Node<TestSchema> = {
|
311
|
+
name: "test",
|
312
|
+
params: z.object({
|
313
|
+
value: z.number().min(0),
|
314
|
+
}),
|
315
|
+
execute: async (context, params) => {
|
316
|
+
if (!params) throw new Error("params required");
|
317
|
+
context.value = params.value;
|
318
|
+
},
|
319
|
+
};
|
306
320
|
|
307
321
|
const graph = new GraphFlow("test", {
|
308
322
|
name: "test",
|
309
323
|
schema: TestSchema,
|
310
324
|
context: { value: 0 },
|
311
|
-
nodes: [
|
312
|
-
{
|
313
|
-
name: "test",
|
314
|
-
inputs: InputSchema,
|
315
|
-
execute: async () => {},
|
316
|
-
},
|
317
|
-
],
|
325
|
+
nodes: [node],
|
318
326
|
});
|
319
327
|
|
320
328
|
try {
|
@@ -324,90 +332,68 @@ describe("GraphFlow", function () {
|
|
324
332
|
expect(error.message).to.include("Number must be greater than or equal");
|
325
333
|
}
|
326
334
|
});
|
327
|
-
|
328
|
-
/**
|
329
|
-
* Tests output validation error handling
|
330
|
-
*/
|
331
|
-
it("should throw error when node output validation fails", async function () {
|
332
|
-
const nodeWithOutput: Node<TestSchema> = {
|
333
|
-
name: "outputNode",
|
334
|
-
outputs: z.object({
|
335
|
-
value: z.number().max(10),
|
336
|
-
}),
|
337
|
-
execute: async (context) => {
|
338
|
-
context.value = 20; // This will fail output validation
|
339
|
-
},
|
340
|
-
next: [],
|
341
|
-
};
|
342
|
-
|
343
|
-
graph.addNode(nodeWithOutput);
|
344
|
-
|
345
|
-
try {
|
346
|
-
await graph.execute("outputNode");
|
347
|
-
expect.fail("Should have thrown an error");
|
348
|
-
} catch (error) {
|
349
|
-
expect((error as Error).message).to.include(
|
350
|
-
"Number must be less than or equal to 10"
|
351
|
-
);
|
352
|
-
}
|
353
|
-
});
|
354
|
-
|
355
335
|
/**
|
356
336
|
* Tests successful input/output validation flow
|
357
337
|
*/
|
358
|
-
it("should successfully validate both
|
359
|
-
const
|
360
|
-
name: "
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
338
|
+
it("should successfully validate both params and outputs", async function () {
|
339
|
+
const graph = new GraphFlow("test", {
|
340
|
+
name: "test",
|
341
|
+
nodes: [
|
342
|
+
{
|
343
|
+
name: "validatedNode",
|
344
|
+
params: z.object({
|
345
|
+
increment: z.number().min(0).max(5),
|
346
|
+
}),
|
347
|
+
execute: async (
|
348
|
+
context: GraphContext<TestSchema>,
|
349
|
+
params?: NodeParams
|
350
|
+
) => {
|
351
|
+
if (!params) throw new Error("params required");
|
352
|
+
context.value = (context.value ?? 0) + params.increment;
|
353
|
+
},
|
354
|
+
},
|
355
|
+
],
|
356
|
+
schema: TestSchema,
|
357
|
+
context: { value: 0, counter: 0, message: "" },
|
358
|
+
});
|
374
359
|
|
375
|
-
// Test
|
360
|
+
// Test avec valeur valide
|
376
361
|
await graph.execute("validatedNode", { increment: 3 });
|
377
362
|
expect(graph.getContext().value).to.equal(3);
|
378
363
|
|
379
|
-
// Test
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
} catch (error) {
|
384
|
-
expect((error as Error).message).to.include(
|
385
|
-
"Number must be less than or equal to 10"
|
386
|
-
);
|
387
|
-
}
|
364
|
+
// Test avec valeur invalide
|
365
|
+
await expect(
|
366
|
+
graph.execute("validatedNode", { increment: 10 })
|
367
|
+
).to.be.rejectedWith("Number must be less than or equal to 5");
|
388
368
|
});
|
389
369
|
|
390
370
|
/**
|
391
|
-
* Tests handling of missing required
|
371
|
+
* Tests handling of missing required params
|
392
372
|
*/
|
393
|
-
it("should throw error when required
|
394
|
-
const
|
395
|
-
name: "
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
373
|
+
it("should throw error when required params are missing", async function () {
|
374
|
+
const graph = new GraphFlow("test", {
|
375
|
+
name: "test",
|
376
|
+
nodes: [
|
377
|
+
{
|
378
|
+
name: "requiredInputNode",
|
379
|
+
params: z.object({
|
380
|
+
value: z.number(),
|
381
|
+
}),
|
382
|
+
execute: async (
|
383
|
+
context: GraphContext<TestSchema>,
|
384
|
+
params?: NodeParams
|
385
|
+
) => {
|
386
|
+
context.counter = params?.value || 0;
|
387
|
+
},
|
388
|
+
},
|
389
|
+
],
|
390
|
+
schema: TestSchema,
|
391
|
+
context: { value: 0, counter: 0, message: "" },
|
392
|
+
});
|
404
393
|
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
} catch (error) {
|
409
|
-
expect((error as Error).message).to.include("Inputs required for node");
|
410
|
-
}
|
394
|
+
await expect(graph.execute("requiredInputNode")).to.be.rejectedWith(
|
395
|
+
"Params required for node"
|
396
|
+
);
|
411
397
|
});
|
412
398
|
|
413
399
|
/**
|
@@ -724,4 +710,59 @@ describe("GraphFlow", function () {
|
|
724
710
|
const result = await resultPromise;
|
725
711
|
expect(result.value).to.equal(6); // 1 (waitingNode) + 5 (finalNode)
|
726
712
|
});
|
713
|
+
|
714
|
+
// Test de validation des paramètres
|
715
|
+
it("should successfully validate params", async () => {
|
716
|
+
const graph = new GraphFlow("test", {
|
717
|
+
name: "test",
|
718
|
+
nodes: [
|
719
|
+
{
|
720
|
+
name: "validationNode",
|
721
|
+
params: z.object({
|
722
|
+
value: z.number().max(10),
|
723
|
+
}),
|
724
|
+
execute: async (
|
725
|
+
context: GraphContext<TestSchema>,
|
726
|
+
params?: NodeParams
|
727
|
+
) => {
|
728
|
+
context.counter = params?.value || 0;
|
729
|
+
},
|
730
|
+
},
|
731
|
+
],
|
732
|
+
schema: TestSchema,
|
733
|
+
context: { value: 0, counter: 0, message: "" },
|
734
|
+
});
|
735
|
+
|
736
|
+
// Test avec valeur invalide
|
737
|
+
await expect(
|
738
|
+
graph.execute("validationNode", { value: 20 })
|
739
|
+
).to.be.rejectedWith("Number must be less than or equal to 10");
|
740
|
+
});
|
741
|
+
|
742
|
+
// Test des paramètres requis
|
743
|
+
it("should throw error when required params are missing", async () => {
|
744
|
+
const graph = new GraphFlow("test", {
|
745
|
+
name: "test",
|
746
|
+
nodes: [
|
747
|
+
{
|
748
|
+
name: "requiredInputNode",
|
749
|
+
params: z.object({
|
750
|
+
value: z.number(),
|
751
|
+
}),
|
752
|
+
execute: async (
|
753
|
+
context: GraphContext<TestSchema>,
|
754
|
+
params?: NodeParams
|
755
|
+
) => {
|
756
|
+
context.counter = params?.value || 0;
|
757
|
+
},
|
758
|
+
},
|
759
|
+
],
|
760
|
+
schema: TestSchema,
|
761
|
+
context: { value: 0, counter: 0, message: "" },
|
762
|
+
});
|
763
|
+
|
764
|
+
await expect(graph.execute("requiredInputNode")).to.be.rejectedWith(
|
765
|
+
"Params required for node"
|
766
|
+
);
|
767
|
+
});
|
727
768
|
});
|
package/test/graph/node.test.ts
CHANGED
@@ -5,7 +5,7 @@ import { BehaviorSubject, Subject } from "rxjs";
|
|
5
5
|
import { z } from "zod";
|
6
6
|
import { GraphEventManager } from "../../graph/event-manager";
|
7
7
|
import { GraphLogger } from "../../graph/logger";
|
8
|
-
import { GraphNode } from "../../graph/node";
|
8
|
+
import { GraphNode, NodeParams } from "../../graph/node";
|
9
9
|
import { GraphContext } from "../../types";
|
10
10
|
|
11
11
|
use(chaiAsPromised);
|
@@ -107,7 +107,7 @@ describe("GraphNode", () => {
|
|
107
107
|
const nodes = new Map();
|
108
108
|
nodes.set("test", {
|
109
109
|
name: "test",
|
110
|
-
execute: async (
|
110
|
+
execute: async () => {
|
111
111
|
throw new Error("Test error");
|
112
112
|
},
|
113
113
|
});
|
@@ -121,13 +121,17 @@ describe("GraphNode", () => {
|
|
121
121
|
);
|
122
122
|
|
123
123
|
try {
|
124
|
-
await node.executeNode(
|
125
|
-
|
124
|
+
await node.executeNode(
|
125
|
+
"test",
|
126
|
+
{ counter: 0, message: "Hello" },
|
127
|
+
null,
|
128
|
+
false
|
129
|
+
);
|
130
|
+
expect.fail("Test error");
|
126
131
|
} catch (error: any) {
|
127
132
|
expect(error.message).to.equal("Test error");
|
128
133
|
const errorEvents = events.filter((e) => e.type === "nodeError");
|
129
134
|
expect(errorEvents).to.have.lengthOf(1);
|
130
|
-
expect(errorEvents[0].payload.error.message).to.equal("Test error");
|
131
135
|
}
|
132
136
|
});
|
133
137
|
|
@@ -175,7 +179,7 @@ describe("GraphNode", () => {
|
|
175
179
|
const nodes = new Map();
|
176
180
|
nodes.set("test", {
|
177
181
|
name: "test",
|
178
|
-
execute: async (context: TestContext) => {
|
182
|
+
execute: async (context: TestContext, inputs?: any) => {
|
179
183
|
context.counter = context.counter; // Même valeur
|
180
184
|
context.message = "New"; // Nouvelle valeur
|
181
185
|
},
|
@@ -194,4 +198,313 @@ describe("GraphNode", () => {
|
|
194
198
|
expect(stateChanges).to.have.lengthOf(1); // Seulement pour message
|
195
199
|
expect(stateChanges[0].payload.property).to.equal("message");
|
196
200
|
});
|
201
|
+
|
202
|
+
it("should execute node with parameters", async () => {
|
203
|
+
const nodes = new Map();
|
204
|
+
nodes.set("test", {
|
205
|
+
name: "test",
|
206
|
+
execute: async (context: TestContext, inputs?: any) => {
|
207
|
+
context.counter = inputs?.value ?? 0;
|
208
|
+
context.message = inputs?.message ?? "Default";
|
209
|
+
},
|
210
|
+
});
|
211
|
+
|
212
|
+
node = new GraphNode(
|
213
|
+
nodes,
|
214
|
+
logger,
|
215
|
+
eventManager,
|
216
|
+
eventSubject,
|
217
|
+
stateSubject
|
218
|
+
);
|
219
|
+
|
220
|
+
await node.executeNode(
|
221
|
+
"test",
|
222
|
+
{ counter: 0, message: "Hello" },
|
223
|
+
{ value: 5, message: "Custom" },
|
224
|
+
false
|
225
|
+
);
|
226
|
+
|
227
|
+
const stateChanges = events.filter((e) => e.type === "nodeStateChanged");
|
228
|
+
expect(stateChanges).to.have.lengthOf(2);
|
229
|
+
expect(stateChanges[0].payload.newValue).to.equal(5);
|
230
|
+
expect(stateChanges[1].payload.newValue).to.equal("Custom");
|
231
|
+
});
|
232
|
+
|
233
|
+
it("should use default values when no parameters provided", async () => {
|
234
|
+
const nodes = new Map();
|
235
|
+
nodes.set("test", {
|
236
|
+
name: "test",
|
237
|
+
execute: async (
|
238
|
+
context: TestContext,
|
239
|
+
_inputs: any,
|
240
|
+
params?: NodeParams
|
241
|
+
) => {
|
242
|
+
context.counter = params?.increment || 1;
|
243
|
+
context.message = params?.message || "Default";
|
244
|
+
},
|
245
|
+
});
|
246
|
+
|
247
|
+
node = new GraphNode(
|
248
|
+
nodes,
|
249
|
+
logger,
|
250
|
+
eventManager,
|
251
|
+
eventSubject,
|
252
|
+
stateSubject
|
253
|
+
);
|
254
|
+
|
255
|
+
await node.executeNode("test", { counter: 0, message: "Hello" }, null);
|
256
|
+
|
257
|
+
const stateChanges = events.filter((e) => e.type === "nodeStateChanged");
|
258
|
+
expect(stateChanges).to.have.lengthOf(2);
|
259
|
+
expect(stateChanges[0].payload.newValue).to.equal(1); // counter (default)
|
260
|
+
expect(stateChanges[1].payload.newValue).to.equal("Default"); // message (default)
|
261
|
+
});
|
262
|
+
|
263
|
+
it("should properly handle node inputs", async () => {
|
264
|
+
const nodes = new Map();
|
265
|
+
nodes.set("test", {
|
266
|
+
name: "test",
|
267
|
+
execute: async (context: TestContext, inputs: any) => {
|
268
|
+
context.counter = inputs.value;
|
269
|
+
context.message = inputs.message;
|
270
|
+
},
|
271
|
+
});
|
272
|
+
|
273
|
+
node = new GraphNode(
|
274
|
+
nodes,
|
275
|
+
logger,
|
276
|
+
eventManager,
|
277
|
+
eventSubject,
|
278
|
+
stateSubject
|
279
|
+
);
|
280
|
+
|
281
|
+
const testInputs = {
|
282
|
+
value: 42,
|
283
|
+
message: "Test Input",
|
284
|
+
};
|
285
|
+
|
286
|
+
await node.executeNode(
|
287
|
+
"test",
|
288
|
+
{ counter: 0, message: "Hello" },
|
289
|
+
testInputs
|
290
|
+
);
|
291
|
+
|
292
|
+
const stateChanges = events.filter((e) => e.type === "nodeStateChanged");
|
293
|
+
expect(stateChanges).to.have.lengthOf(2);
|
294
|
+
expect(stateChanges[0].payload.newValue).to.equal(42); // counter from input
|
295
|
+
expect(stateChanges[1].payload.newValue).to.equal("Test Input"); // message from input
|
296
|
+
});
|
297
|
+
|
298
|
+
it("should not emit duplicate state changes", async () => {
|
299
|
+
const nodes = new Map();
|
300
|
+
nodes.set("test", {
|
301
|
+
name: "test",
|
302
|
+
execute: async (context: TestContext) => {
|
303
|
+
context.counter = 1; // Valeur fixe au lieu d'incrémentations
|
304
|
+
context.counter = 1; // Même valeur
|
305
|
+
context.message = "New";
|
306
|
+
context.message = "New"; // Même valeur
|
307
|
+
},
|
308
|
+
});
|
309
|
+
|
310
|
+
node = new GraphNode(
|
311
|
+
nodes,
|
312
|
+
logger,
|
313
|
+
eventManager,
|
314
|
+
eventSubject,
|
315
|
+
stateSubject
|
316
|
+
);
|
317
|
+
|
318
|
+
await node.executeNode("test", { counter: 0, message: "Hello" }, null);
|
319
|
+
|
320
|
+
// Vérifier qu'il n'y a pas de doublons dans les événements
|
321
|
+
const stateChanges = events.filter((e) => e.type === "nodeStateChanged");
|
322
|
+
const uniqueChanges = new Set(
|
323
|
+
stateChanges.map(
|
324
|
+
(e) =>
|
325
|
+
`${e.payload.property}-${e.payload.oldValue}-${e.payload.newValue}`
|
326
|
+
)
|
327
|
+
);
|
328
|
+
|
329
|
+
expect(stateChanges.length).to.equal(uniqueChanges.size);
|
330
|
+
expect(stateChanges).to.have.lengthOf(2); // Un pour counter, un pour message
|
331
|
+
});
|
332
|
+
|
333
|
+
it("should validate node parameters with Zod schema", async () => {
|
334
|
+
const paramSchema = z.object({
|
335
|
+
increment: z.number().min(1),
|
336
|
+
message: z.string().min(1),
|
337
|
+
});
|
338
|
+
|
339
|
+
const nodes = new Map();
|
340
|
+
nodes.set("test", {
|
341
|
+
name: "test",
|
342
|
+
params: paramSchema,
|
343
|
+
execute: async (context: TestContext, params?: NodeParams) => {
|
344
|
+
context.counter += params?.increment || 0;
|
345
|
+
context.message = params?.message || "";
|
346
|
+
},
|
347
|
+
});
|
348
|
+
|
349
|
+
node = new GraphNode(
|
350
|
+
nodes,
|
351
|
+
logger,
|
352
|
+
eventManager,
|
353
|
+
eventSubject,
|
354
|
+
stateSubject
|
355
|
+
);
|
356
|
+
|
357
|
+
// Test avec des paramètres valides
|
358
|
+
await node.executeNode(
|
359
|
+
"test",
|
360
|
+
{ counter: 0, message: "Hello" },
|
361
|
+
{ increment: 5, message: "Valid" }
|
362
|
+
);
|
363
|
+
|
364
|
+
// Test avec des paramètres invalides
|
365
|
+
await expect(
|
366
|
+
node.executeNode(
|
367
|
+
"test",
|
368
|
+
{ counter: 0, message: "Hello" },
|
369
|
+
{ increment: 0, message: "" }
|
370
|
+
)
|
371
|
+
).to.be.rejected; // Enlever le .with() car le message d'erreur vient directement de Zod
|
372
|
+
});
|
373
|
+
|
374
|
+
it("should work without params schema", async () => {
|
375
|
+
const nodes = new Map();
|
376
|
+
nodes.set("test", {
|
377
|
+
name: "test",
|
378
|
+
execute: async (context: TestContext) => {
|
379
|
+
context.counter++;
|
380
|
+
},
|
381
|
+
});
|
382
|
+
|
383
|
+
node = new GraphNode(
|
384
|
+
nodes,
|
385
|
+
logger,
|
386
|
+
eventManager,
|
387
|
+
eventSubject,
|
388
|
+
stateSubject
|
389
|
+
);
|
390
|
+
|
391
|
+
// Devrait fonctionner sans erreur même sans schema de params
|
392
|
+
await node.executeNode("test", { counter: 0, message: "Hello" }, null);
|
393
|
+
});
|
394
|
+
|
395
|
+
it("should not require params when node has no params schema", async () => {
|
396
|
+
const nodes = new Map();
|
397
|
+
nodes.set("test", {
|
398
|
+
name: "test",
|
399
|
+
// Pas de schéma de params défini
|
400
|
+
execute: async (context: TestContext) => {
|
401
|
+
context.counter++;
|
402
|
+
},
|
403
|
+
});
|
404
|
+
|
405
|
+
node = new GraphNode(
|
406
|
+
nodes,
|
407
|
+
logger,
|
408
|
+
eventManager,
|
409
|
+
eventSubject,
|
410
|
+
stateSubject
|
411
|
+
);
|
412
|
+
|
413
|
+
await node.executeNode("test", { counter: 0, message: "Hello" }, null);
|
414
|
+
|
415
|
+
const stateChanges = events.filter((e) => e.type === "nodeStateChanged");
|
416
|
+
expect(stateChanges).to.have.lengthOf(1);
|
417
|
+
expect(stateChanges[0].payload.newValue).to.equal(1);
|
418
|
+
});
|
419
|
+
|
420
|
+
it("should require params only when node has params schema", async () => {
|
421
|
+
const nodes = new Map();
|
422
|
+
nodes.set("test", {
|
423
|
+
name: "test",
|
424
|
+
params: z.object({
|
425
|
+
// Avec un schéma de params
|
426
|
+
value: z.number(),
|
427
|
+
}),
|
428
|
+
execute: async (context: TestContext, params?: NodeParams) => {
|
429
|
+
context.counter = params?.value || 0;
|
430
|
+
},
|
431
|
+
});
|
432
|
+
|
433
|
+
node = new GraphNode(
|
434
|
+
nodes,
|
435
|
+
logger,
|
436
|
+
eventManager,
|
437
|
+
eventSubject,
|
438
|
+
stateSubject
|
439
|
+
);
|
440
|
+
|
441
|
+
// Devrait échouer sans params
|
442
|
+
await expect(
|
443
|
+
node.executeNode("test", { counter: 0, message: "Hello" }, null)
|
444
|
+
).to.be.rejectedWith("Params required for node");
|
445
|
+
});
|
446
|
+
|
447
|
+
it("should execute node without params when no schema is defined (real world scenario)", async () => {
|
448
|
+
const nodes = new Map();
|
449
|
+
nodes.set("incrementCounter", {
|
450
|
+
name: "incrementCounter",
|
451
|
+
execute: async (context: TestContext) => {
|
452
|
+
context.counter++;
|
453
|
+
},
|
454
|
+
});
|
455
|
+
|
456
|
+
node = new GraphNode(
|
457
|
+
nodes,
|
458
|
+
logger,
|
459
|
+
eventManager,
|
460
|
+
eventSubject,
|
461
|
+
stateSubject
|
462
|
+
);
|
463
|
+
|
464
|
+
// Simuler l'appel comme dans examples/t2.ts
|
465
|
+
await node.executeNode(
|
466
|
+
"incrementCounter",
|
467
|
+
{ message: "Hello", counter: 0 },
|
468
|
+
{ test: "test" } // Passer des params même si non requis
|
469
|
+
);
|
470
|
+
|
471
|
+
const stateChanges = events.filter((e) => e.type === "nodeStateChanged");
|
472
|
+
expect(stateChanges).to.have.lengthOf(1);
|
473
|
+
expect(stateChanges[0].payload.newValue).to.equal(1);
|
474
|
+
});
|
475
|
+
|
476
|
+
it("should handle optional params schema", async () => {
|
477
|
+
const nodes = new Map();
|
478
|
+
nodes.set("test", {
|
479
|
+
name: "test",
|
480
|
+
params: z
|
481
|
+
.object({
|
482
|
+
test: z.string(),
|
483
|
+
})
|
484
|
+
.optional(),
|
485
|
+
execute: async (context: TestContext, params?: NodeParams) => {
|
486
|
+
context.counter++;
|
487
|
+
},
|
488
|
+
});
|
489
|
+
|
490
|
+
node = new GraphNode(
|
491
|
+
nodes,
|
492
|
+
logger,
|
493
|
+
eventManager,
|
494
|
+
eventSubject,
|
495
|
+
stateSubject
|
496
|
+
);
|
497
|
+
|
498
|
+
// Devrait fonctionner avec ou sans params
|
499
|
+
await node.executeNode(
|
500
|
+
"test",
|
501
|
+
{ counter: 0, message: "Hello" },
|
502
|
+
{ test: "test" }
|
503
|
+
);
|
504
|
+
await node.executeNode("test", { counter: 1, message: "Hello" }, null);
|
505
|
+
|
506
|
+
const stateChanges = events.filter((e) => e.type === "nodeStateChanged");
|
507
|
+
expect(stateChanges).to.have.lengthOf(2);
|
508
|
+
expect(stateChanges[1].payload.newValue).to.equal(2);
|
509
|
+
});
|
197
510
|
});
|