@@ -2,6 +2,7 @@ import { describe, expect, it } from 'vitest'
22import { UnsafeEvaluator } from '../../src/evaluator'
33import { createFlow } from '../../src/flow'
44import { SubflowNode } from '../../src/nodes/subflow'
5+ import { WaitNode } from '../../src/nodes/wait'
56import { FlowRuntime } from '../../src/runtime'
67
78describe ( 'Built-In Nodes' , ( ) => {
@@ -109,6 +110,42 @@ describe('Built-In Nodes', () => {
109110 expect ( result . errors ?. [ 0 ] ?. message ) . toContain ( 'execution failed' )
110111 expect ( workerExecutionCount ) . toBe ( 2 )
111112 } )
113+
114+ it ( 'should throw error for non-array input in batch-scatter' , async ( ) => {
115+ const flow = createFlow ( 'non-array-input-test' )
116+ flow . node ( 'prepare' , async ( ) => ( { output : 'not an array' } ) )
117+ flow . node ( 'verify' , async ( ) => ( { output : 'should not reach' } ) )
118+ flow . batch ( 'test-batch' , async ( ) => ( { output : 'worker' } ) , {
119+ inputKey : 'prepare' ,
120+ outputKey : 'results' ,
121+ } )
122+ flow . edge ( 'prepare' , 'test-batch' )
123+ flow . edge ( 'test-batch' , 'verify' )
124+
125+ const runtime = new FlowRuntime ( { } )
126+ const result = await runtime . run ( flow . toBlueprint ( ) , { } , { functionRegistry : flow . getFunctionRegistry ( ) } )
127+
128+ expect ( result . status ) . toBe ( 'failed' )
129+ } )
130+
131+ it ( 'should throw error for missing params in batch-scatter' , async ( ) => {
132+ const flow = createFlow ( 'missing-params-test' )
133+ flow . node ( 'prepare' , async ( ) => ( { output : [ ] } ) )
134+ flow . node ( 'verify' , async ( ) => ( { output : 'should not reach' } ) )
135+ flow . batch ( 'test-batch' , async ( ) => ( { output : 'worker' } ) , {
136+ inputKey : 'prepare' ,
137+ outputKey : 'results' ,
138+ // missing workerUsesKey and gatherNodeId
139+ } )
140+ flow . edge ( 'prepare' , 'test-batch' )
141+ flow . edge ( 'test-batch' , 'verify' )
142+
143+ const runtime = new FlowRuntime ( { } )
144+ const result = await runtime . run ( flow . toBlueprint ( ) , { } , { functionRegistry : flow . getFunctionRegistry ( ) } )
145+
146+ expect ( result . status ) . toBe ( 'completed' )
147+ expect ( result . context [ '_outputs.verify' ] ) . toBe ( 'should not reach' )
148+ } )
112149 } )
113150
114151 describe ( 'Loop Controller' , ( ) => {
@@ -266,5 +303,57 @@ describe('Built-In Nodes', () => {
266303 expect ( result . status ) . toBe ( 'failed' )
267304 expect ( result . errors ?. some ( ( e ) => e . message ?. includes ( "Node 'fail' execution failed" ) ) ) . toBe ( true )
268305 } )
306+
307+ it ( 'should throw error for missing blueprintId in subflow' , async ( ) => {
308+ const mainFlow = createFlow ( 'missing-blueprintid-test' )
309+ mainFlow . node ( 'input' , async ( ) => ( { output : 'test' } ) )
310+ mainFlow . node ( 'test-subflow' , SubflowNode , {
311+ params : {
312+ // missing blueprintId
313+ inputs : { input : 'input' } ,
314+ } ,
315+ } )
316+ mainFlow . edge ( 'input' , 'test-subflow' )
317+
318+ const runtime = new FlowRuntime ( { } )
319+ const result = await runtime . run ( mainFlow . toBlueprint ( ) , { } , { functionRegistry : mainFlow . getFunctionRegistry ( ) } )
320+
321+ expect ( result . status ) . toBe ( 'failed' )
322+ expect ( result . errors ?. some ( ( e ) => e . message ?. includes ( "missing 'blueprintId' parameter" ) ) ) . toBe ( true )
323+ } )
324+
325+ it ( 'should throw error for missing subBlueprint in subflow' , async ( ) => {
326+ const mainFlow = createFlow ( 'missing-subblueprint-test' )
327+ mainFlow . node ( 'input' , async ( ) => ( { output : 'test' } ) )
328+ mainFlow . node ( 'test-subflow' , SubflowNode , {
329+ params : {
330+ blueprintId : 'nonexistent-subflow' ,
331+ inputs : { input : 'input' } ,
332+ } ,
333+ } )
334+ mainFlow . edge ( 'input' , 'test-subflow' )
335+
336+ const runtime = new FlowRuntime ( { } )
337+ const result = await runtime . run ( mainFlow . toBlueprint ( ) , { } , { functionRegistry : mainFlow . getFunctionRegistry ( ) } )
338+
339+ expect ( result . status ) . toBe ( 'failed' )
340+ expect ( result . errors ?. some ( ( e ) => e . message ?. includes ( 'not found in runtime registry' ) ) ) . toBe ( true )
341+ } )
342+ } )
343+
344+ describe ( 'WaitNode' , ( ) => {
345+ it ( 'should mark workflow as awaiting' , async ( ) => {
346+ const flow = createFlow ( 'wait-test' )
347+ flow . node ( 'start' , async ( ) => ( { output : 'start' } ) )
348+ flow . node ( 'wait' , WaitNode , { } )
349+ flow . node ( 'end' , async ( ) => ( { output : 'end' } ) )
350+ flow . edge ( 'start' , 'wait' )
351+ flow . edge ( 'wait' , 'end' )
352+
353+ const runtime = new FlowRuntime ( { } )
354+ const result = await runtime . run ( flow . toBlueprint ( ) , { } , { functionRegistry : flow . getFunctionRegistry ( ) } )
355+
356+ expect ( result . status ) . toBe ( 'awaiting' )
357+ } )
269358 } )
270359} )
0 commit comments