1- import '@/executor/__test-utils__/mock-dependencies'
2-
31import { beforeEach , describe , expect , it , vi } from 'vitest'
42import { BlockType } from '@/executor/constants'
53import { ConditionBlockHandler } from '@/executor/handlers/condition/condition-handler'
64import type { BlockState , ExecutionContext } from '@/executor/types'
75import type { SerializedBlock , SerializedWorkflow } from '@/serializer/types'
86
7+ vi . mock ( '@/lib/logs/console/logger' , ( ) => ( {
8+ createLogger : vi . fn ( ( ) => ( {
9+ info : vi . fn ( ) ,
10+ error : vi . fn ( ) ,
11+ warn : vi . fn ( ) ,
12+ debug : vi . fn ( ) ,
13+ } ) ) ,
14+ } ) )
15+
16+ vi . mock ( '@/lib/core/utils/request' , ( ) => ( {
17+ generateRequestId : vi . fn ( ( ) => 'test-request-id' ) ,
18+ } ) )
19+
20+ vi . mock ( '@/lib/execution/isolated-vm' , ( ) => ( {
21+ executeInIsolatedVM : vi . fn ( ) ,
22+ } ) )
23+
24+ import { executeInIsolatedVM } from '@/lib/execution/isolated-vm'
25+
26+ const mockExecuteInIsolatedVM = executeInIsolatedVM as ReturnType < typeof vi . fn >
27+
28+ /**
29+ * Helper to simulate isolated VM execution behavior
30+ * This evaluates the code using the contextVariables, mimicking real isolated VM behavior
31+ */
32+ function simulateIsolatedVMExecution (
33+ code : string ,
34+ contextVariables : Record < string , unknown >
35+ ) : { result : unknown ; stdout : string ; error ?: { message : string ; name : string } } {
36+ try {
37+ const fn = new Function ( ...Object . keys ( contextVariables ) , code )
38+ const result = fn ( ...Object . values ( contextVariables ) )
39+ return { result, stdout : '' }
40+ } catch ( error : any ) {
41+ return {
42+ result : null ,
43+ stdout : '' ,
44+ error : { message : error . message , name : error . name || 'Error' } ,
45+ }
46+ }
47+ }
48+
949describe ( 'ConditionBlockHandler' , ( ) => {
1050 let handler : ConditionBlockHandler
1151 let mockBlock : SerializedBlock
@@ -18,7 +58,6 @@ describe('ConditionBlockHandler', () => {
1858 let mockPathTracker : any
1959
2060 beforeEach ( ( ) => {
21- // Define blocks first
2261 mockSourceBlock = {
2362 id : 'source-block-1' ,
2463 metadata : { id : 'source' , name : 'Source Block' } ,
@@ -33,7 +72,7 @@ describe('ConditionBlockHandler', () => {
3372 metadata : { id : BlockType . CONDITION , name : 'Test Condition' } ,
3473 position : { x : 50 , y : 50 } ,
3574 config : { tool : BlockType . CONDITION , params : { } } ,
36- inputs : { conditions : 'json' } , // Corrected based on previous step
75+ inputs : { conditions : 'json' } ,
3776 outputs : { } ,
3877 enabled : true ,
3978 }
@@ -56,7 +95,6 @@ describe('ConditionBlockHandler', () => {
5695 enabled : true ,
5796 }
5897
59- // Then define workflow using the block objects
6098 mockWorkflow = {
6199 blocks : [ mockSourceBlock , mockBlock , mockTargetBlock1 , mockTargetBlock2 ] ,
62100 connections : [
@@ -84,7 +122,6 @@ describe('ConditionBlockHandler', () => {
84122
85123 handler = new ConditionBlockHandler ( mockPathTracker , mockResolver )
86124
87- // Define mock context *after* workflow and blocks are set up
88125 mockContext = {
89126 workflowId : 'test-workflow-id' ,
90127 blockStates : new Map < string , BlockState > ( [
@@ -99,7 +136,7 @@ describe('ConditionBlockHandler', () => {
99136 ] ) ,
100137 blockLogs : [ ] ,
101138 metadata : { duration : 0 } ,
102- environmentVariables : { } , // Now set the context's env vars
139+ environmentVariables : { } ,
103140 decisions : { router : new Map ( ) , condition : new Map ( ) } ,
104141 loopExecutions : new Map ( ) ,
105142 executedBlocks : new Set ( [ mockSourceBlock . id ] ) ,
@@ -108,11 +145,11 @@ describe('ConditionBlockHandler', () => {
108145 completedLoops : new Set ( ) ,
109146 }
110147
111- // Reset mocks using vi
112148 vi . clearAllMocks ( )
113149
114- // Default mock implementations - Removed as it's in the shared mock now
115- // mockResolver.resolveBlockReferences.mockImplementation((value) => value)
150+ mockExecuteInIsolatedVM . mockImplementation ( async ( { code, contextVariables } ) => {
151+ return simulateIsolatedVMExecution ( code , contextVariables )
152+ } )
116153 } )
117154
118155 it ( 'should handle condition blocks' , ( ) => {
@@ -141,7 +178,6 @@ describe('ConditionBlockHandler', () => {
141178 selectedOption : 'cond1' ,
142179 }
143180
144- // Mock the full resolution pipeline
145181 mockResolver . resolveVariableReferences . mockReturnValue ( 'context.value > 5' )
146182 mockResolver . resolveBlockReferences . mockReturnValue ( 'context.value > 5' )
147183 mockResolver . resolveEnvVariables . mockReturnValue ( 'context.value > 5' )
@@ -182,7 +218,6 @@ describe('ConditionBlockHandler', () => {
182218 selectedOption : 'else1' ,
183219 }
184220
185- // Mock the full resolution pipeline
186221 mockResolver . resolveVariableReferences . mockReturnValue ( 'context.value < 0' )
187222 mockResolver . resolveBlockReferences . mockReturnValue ( 'context.value < 0' )
188223 mockResolver . resolveEnvVariables . mockReturnValue ( 'context.value < 0' )
@@ -207,7 +242,7 @@ describe('ConditionBlockHandler', () => {
207242 const inputs = { conditions : '{ "invalid json ' }
208243
209244 await expect ( handler . execute ( mockContext , mockBlock , inputs ) ) . rejects . toThrow (
210- / ^ I n v a l i d c o n d i t i o n s f o r m a t : U n t e r m i n a t e d s t r i n g . * /
245+ / ^ I n v a l i d c o n d i t i o n s f o r m a t : /
211246 )
212247 } )
213248
@@ -218,7 +253,6 @@ describe('ConditionBlockHandler', () => {
218253 ]
219254 const inputs = { conditions : JSON . stringify ( conditions ) }
220255
221- // Mock the full resolution pipeline
222256 mockResolver . resolveVariableReferences . mockReturnValue ( '{{source-block-1.value}} > 5' )
223257 mockResolver . resolveBlockReferences . mockReturnValue ( '10 > 5' )
224258 mockResolver . resolveEnvVariables . mockReturnValue ( '10 > 5' )
@@ -245,7 +279,6 @@ describe('ConditionBlockHandler', () => {
245279 ]
246280 const inputs = { conditions : JSON . stringify ( conditions ) }
247281
248- // Mock the full resolution pipeline for variable resolution
249282 mockResolver . resolveVariableReferences . mockReturnValue ( '"john" !== null' )
250283 mockResolver . resolveBlockReferences . mockReturnValue ( '"john" !== null' )
251284 mockResolver . resolveEnvVariables . mockReturnValue ( '"john" !== null' )
@@ -272,7 +305,6 @@ describe('ConditionBlockHandler', () => {
272305 ]
273306 const inputs = { conditions : JSON . stringify ( conditions ) }
274307
275- // Mock the full resolution pipeline for env variable resolution
276308 mockResolver . resolveVariableReferences . mockReturnValue ( '{{POOP}} === "hi"' )
277309 mockResolver . resolveBlockReferences . mockReturnValue ( '{{POOP}} === "hi"' )
278310 mockResolver . resolveEnvVariables . mockReturnValue ( '"hi" === "hi"' )
@@ -300,7 +332,6 @@ describe('ConditionBlockHandler', () => {
300332 const inputs = { conditions : JSON . stringify ( conditions ) }
301333
302334 const resolutionError = new Error ( 'Could not resolve reference: invalid-ref' )
303- // Mock the pipeline to throw at the variable resolution stage
304335 mockResolver . resolveVariableReferences . mockImplementation ( ( ) => {
305336 throw resolutionError
306337 } )
@@ -317,23 +348,21 @@ describe('ConditionBlockHandler', () => {
317348 ]
318349 const inputs = { conditions : JSON . stringify ( conditions ) }
319350
320- // Mock the full resolution pipeline
321351 mockResolver . resolveVariableReferences . mockReturnValue (
322352 'context.nonExistentProperty.doSomething()'
323353 )
324354 mockResolver . resolveBlockReferences . mockReturnValue ( 'context.nonExistentProperty.doSomething()' )
325355 mockResolver . resolveEnvVariables . mockReturnValue ( 'context.nonExistentProperty.doSomething()' )
326356
327357 await expect ( handler . execute ( mockContext , mockBlock , inputs ) ) . rejects . toThrow (
328- / ^ E v a l u a t i o n e r r o r i n c o n d i t i o n " i f " : E v a l u a t i o n e r r o r i n c o n d i t i o n : C a n n o t r e a d p r o p e r t i e s o f u n d e f i n e d \( r e a d i n g ' d o S o m e t h i n g ' \) \. \( R e s o l v e d : c o n t e x t \. n o n E x i s t e n t P r o p e r t y \. d o S o m e t h i n g \( \) \) $ /
358+ / E v a l u a t i o n e r r o r i n c o n d i t i o n " i f " . * d o S o m e t h i n g /
329359 )
330360 } )
331361
332362 it ( 'should handle missing source block output gracefully' , async ( ) => {
333363 const conditions = [ { id : 'cond1' , title : 'if' , value : 'true' } ]
334364 const inputs = { conditions : JSON . stringify ( conditions ) }
335365
336- // Create a new context with empty blockStates instead of trying to delete from readonly map
337366 const contextWithoutSource = {
338367 ...mockContext ,
339368 blockStates : new Map < string , BlockState > ( ) ,
@@ -355,7 +384,6 @@ describe('ConditionBlockHandler', () => {
355384
356385 mockContext . workflow ! . blocks = [ mockSourceBlock , mockBlock , mockTargetBlock2 ]
357386
358- // Mock the full resolution pipeline
359387 mockResolver . resolveVariableReferences . mockReturnValue ( 'true' )
360388 mockResolver . resolveBlockReferences . mockReturnValue ( 'true' )
361389 mockResolver . resolveEnvVariables . mockReturnValue ( 'true' )
@@ -381,7 +409,6 @@ describe('ConditionBlockHandler', () => {
381409 } ,
382410 ]
383411
384- // Mock the full resolution pipeline
385412 mockResolver . resolveVariableReferences
386413 . mockReturnValueOnce ( 'false' )
387414 . mockReturnValueOnce ( 'context.value === 99' )
@@ -394,12 +421,10 @@ describe('ConditionBlockHandler', () => {
394421
395422 const result = await handler . execute ( mockContext , mockBlock , inputs )
396423
397- // Should return success with no path selected (branch ends gracefully)
398424 expect ( ( result as any ) . conditionResult ) . toBe ( false )
399425 expect ( ( result as any ) . selectedPath ) . toBeNull ( )
400426 expect ( ( result as any ) . selectedConditionId ) . toBeNull ( )
401427 expect ( ( result as any ) . selectedOption ) . toBeNull ( )
402- // Decision should not be set when no condition matches
403428 expect ( mockContext . decisions . condition . has ( mockBlock . id ) ) . toBe ( false )
404429 } )
405430
@@ -410,7 +435,6 @@ describe('ConditionBlockHandler', () => {
410435 ]
411436 const inputs = { conditions : JSON . stringify ( conditions ) }
412437
413- // Mock the full resolution pipeline
414438 mockResolver . resolveVariableReferences . mockReturnValue ( 'context.item === "apple"' )
415439 mockResolver . resolveBlockReferences . mockReturnValue ( 'context.item === "apple"' )
416440 mockResolver . resolveEnvVariables . mockReturnValue ( 'context.item === "apple"' )
0 commit comments