mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-09 23:17:59 -05:00
fix(conditional): don't error in condition blocks when no conditions are satisfied (#2243)
* fix(conditional): don't error in condition blocks when no conditions are satisfied * updated docs
This commit is contained in:
@@ -135,7 +135,7 @@ Function (Process) → Condition (account_type === 'enterprise') → Advanced or
|
||||
## Best Practices
|
||||
|
||||
- **Order conditions correctly**: Place more specific conditions before general ones to ensure specific logic takes precedence over fallbacks
|
||||
- **Include a default condition**: Add a catch-all condition (`true`) as the last condition to handle unmatched cases and prevent workflow execution from getting stuck
|
||||
- **Use the else branch when needed**: If no conditions match and the else branch is not connected, the workflow branch will end gracefully. Connect the else branch if you need a fallback path for unmatched cases
|
||||
- **Keep expressions simple**: Use clear, straightforward boolean expressions for better readability and easier debugging
|
||||
- **Document your conditions**: Add descriptions to explain the purpose of each condition for better team collaboration and maintenance
|
||||
- **Test edge cases**: Verify conditions handle boundary values correctly by testing with values at the edges of your condition ranges
|
||||
|
||||
@@ -365,7 +365,7 @@ describe('ConditionBlockHandler', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('should throw error if no condition matches and no else exists', async () => {
|
||||
it('should return no-match result if no condition matches and no else exists', async () => {
|
||||
const conditions = [
|
||||
{ id: 'cond1', title: 'if', value: 'false' },
|
||||
{ id: 'cond2', title: 'else if', value: 'context.value === 99' },
|
||||
@@ -392,9 +392,15 @@ describe('ConditionBlockHandler', () => {
|
||||
.mockReturnValueOnce('false')
|
||||
.mockReturnValueOnce('context.value === 99')
|
||||
|
||||
await expect(handler.execute(mockContext, mockBlock, inputs)).rejects.toThrow(
|
||||
`No matching path found for condition block "${mockBlock.metadata?.name}", and no 'else' block exists.`
|
||||
)
|
||||
const result = await handler.execute(mockContext, mockBlock, inputs)
|
||||
|
||||
// Should return success with no path selected (branch ends gracefully)
|
||||
expect((result as any).conditionResult).toBe(false)
|
||||
expect((result as any).selectedPath).toBeNull()
|
||||
expect((result as any).selectedConditionId).toBeNull()
|
||||
expect((result as any).selectedOption).toBeNull()
|
||||
// Decision should not be set when no condition matches
|
||||
expect(mockContext.decisions.condition.has(mockBlock.id)).toBe(false)
|
||||
})
|
||||
|
||||
it('falls back to else path when loop context data is unavailable', async () => {
|
||||
|
||||
@@ -87,6 +87,17 @@ export class ConditionBlockHandler implements BlockHandler {
|
||||
block
|
||||
)
|
||||
|
||||
// Handle case where no condition matched and no else exists - branch ends gracefully
|
||||
if (!selectedConnection || !selectedCondition) {
|
||||
return {
|
||||
...((sourceOutput as any) || {}),
|
||||
conditionResult: false,
|
||||
selectedPath: null,
|
||||
selectedConditionId: null,
|
||||
selectedOption: null,
|
||||
}
|
||||
}
|
||||
|
||||
const targetBlock = ctx.workflow?.blocks.find((b) => b.id === selectedConnection?.target)
|
||||
if (!targetBlock) {
|
||||
throw new Error(`Target block ${selectedConnection?.target} not found`)
|
||||
@@ -145,8 +156,8 @@ export class ConditionBlockHandler implements BlockHandler {
|
||||
ctx: ExecutionContext,
|
||||
block: SerializedBlock
|
||||
): Promise<{
|
||||
selectedConnection: { target: string; sourceHandle?: string }
|
||||
selectedCondition: { id: string; title: string; value: string }
|
||||
selectedConnection: { target: string; sourceHandle?: string } | null
|
||||
selectedCondition: { id: string; title: string; value: string } | null
|
||||
}> {
|
||||
for (const condition of conditions) {
|
||||
if (condition.title === CONDITION.ELSE_TITLE) {
|
||||
@@ -185,14 +196,16 @@ export class ConditionBlockHandler implements BlockHandler {
|
||||
if (elseConnection) {
|
||||
return { selectedConnection: elseConnection, selectedCondition: elseCondition }
|
||||
}
|
||||
throw new Error(
|
||||
`No path found for condition block "${block.metadata?.name}", and 'else' connection missing.`
|
||||
)
|
||||
// Else exists but has no connection - treat as no match, branch ends
|
||||
logger.info(`No condition matched and else has no connection - branch ending`, {
|
||||
blockId: block.id,
|
||||
})
|
||||
return { selectedConnection: null, selectedCondition: null }
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`No matching path found for condition block "${block.metadata?.name}", and no 'else' block exists.`
|
||||
)
|
||||
// No condition matched and no else exists - branch ends gracefully
|
||||
logger.info(`No condition matched and no else block - branch ending`, { blockId: block.id })
|
||||
return { selectedConnection: null, selectedCondition: null }
|
||||
}
|
||||
|
||||
private findConnectionForCondition(
|
||||
|
||||
Reference in New Issue
Block a user