mirror of
https://github.com/simstudioai/sim.git
synced 2026-02-01 18:25:01 -05:00
* fix(input): allow test value if no real value provided for inputs in deployed executions * ack PR comments
220 lines
5.7 KiB
TypeScript
220 lines
5.7 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { StartBlockPath } from '@/lib/workflows/triggers/triggers'
|
|
import type { UserFile } from '@/executor/types'
|
|
import {
|
|
buildResolutionFromBlock,
|
|
buildStartBlockOutput,
|
|
resolveExecutorStartBlock,
|
|
} from '@/executor/utils/start-block'
|
|
import type { SerializedBlock } from '@/serializer/types'
|
|
|
|
function createBlock(
|
|
type: string,
|
|
id = type,
|
|
options?: { subBlocks?: Record<string, unknown> }
|
|
): SerializedBlock {
|
|
return {
|
|
id,
|
|
position: { x: 0, y: 0 },
|
|
config: {
|
|
tool: type,
|
|
params: options?.subBlocks?.inputFormat ? { inputFormat: options.subBlocks.inputFormat } : {},
|
|
},
|
|
inputs: {},
|
|
outputs: {},
|
|
metadata: {
|
|
id: type,
|
|
name: `block-${type}`,
|
|
category: 'triggers',
|
|
...(options?.subBlocks ? { subBlocks: options.subBlocks } : {}),
|
|
} as SerializedBlock['metadata'] & { subBlocks?: Record<string, unknown> },
|
|
enabled: true,
|
|
}
|
|
}
|
|
|
|
describe('start-block utilities', () => {
|
|
it.concurrent('buildResolutionFromBlock returns null when metadata id missing', () => {
|
|
const block = createBlock('api_trigger')
|
|
;(block.metadata as Record<string, unknown>).id = undefined
|
|
|
|
expect(buildResolutionFromBlock(block)).toBeNull()
|
|
})
|
|
|
|
it.concurrent('resolveExecutorStartBlock prefers unified start block', () => {
|
|
const blocks = [
|
|
createBlock('api_trigger', 'api'),
|
|
createBlock('starter', 'starter'),
|
|
createBlock('start_trigger', 'start'),
|
|
]
|
|
|
|
const resolution = resolveExecutorStartBlock(blocks, {
|
|
execution: 'api',
|
|
isChildWorkflow: false,
|
|
})
|
|
|
|
expect(resolution?.blockId).toBe('start')
|
|
expect(resolution?.path).toBe(StartBlockPath.UNIFIED)
|
|
})
|
|
|
|
it.concurrent('buildStartBlockOutput normalizes unified start payload', () => {
|
|
const block = createBlock('start_trigger', 'start')
|
|
const resolution = {
|
|
blockId: 'start',
|
|
block,
|
|
path: StartBlockPath.UNIFIED,
|
|
} as const
|
|
|
|
const output = buildStartBlockOutput({
|
|
resolution,
|
|
workflowInput: { payload: 'value' },
|
|
})
|
|
|
|
expect(output.payload).toBe('value')
|
|
expect(output.input).toBeUndefined()
|
|
expect(output.conversationId).toBeUndefined()
|
|
})
|
|
|
|
it.concurrent('buildStartBlockOutput uses trigger schema for API triggers', () => {
|
|
const apiBlock = createBlock('api_trigger', 'api', {
|
|
subBlocks: {
|
|
inputFormat: {
|
|
value: [
|
|
{ name: 'name', type: 'string' },
|
|
{ name: 'count', type: 'number' },
|
|
],
|
|
},
|
|
},
|
|
})
|
|
|
|
const resolution = {
|
|
blockId: 'api',
|
|
block: apiBlock,
|
|
path: StartBlockPath.SPLIT_API,
|
|
} as const
|
|
|
|
const files: UserFile[] = [
|
|
{
|
|
id: 'file-1',
|
|
name: 'document.txt',
|
|
url: 'https://example.com/document.txt',
|
|
size: 42,
|
|
type: 'text/plain',
|
|
key: 'file-key',
|
|
},
|
|
]
|
|
|
|
const output = buildStartBlockOutput({
|
|
resolution,
|
|
workflowInput: {
|
|
input: {
|
|
name: 'Ada',
|
|
count: '5',
|
|
},
|
|
files,
|
|
},
|
|
})
|
|
|
|
expect(output.name).toBe('Ada')
|
|
expect(output.input).toEqual({ name: 'Ada', count: 5 })
|
|
expect(output.files).toEqual(files)
|
|
})
|
|
|
|
describe('inputFormat default values', () => {
|
|
it.concurrent('uses default value when runtime does not provide the field', () => {
|
|
const block = createBlock('start_trigger', 'start', {
|
|
subBlocks: {
|
|
inputFormat: {
|
|
value: [
|
|
{ name: 'input', type: 'string' },
|
|
{ name: 'customField', type: 'string', value: 'defaultValue' },
|
|
],
|
|
},
|
|
},
|
|
})
|
|
|
|
const resolution = {
|
|
blockId: 'start',
|
|
block,
|
|
path: StartBlockPath.UNIFIED,
|
|
} as const
|
|
|
|
const output = buildStartBlockOutput({
|
|
resolution,
|
|
workflowInput: { input: 'hello' },
|
|
})
|
|
|
|
expect(output.input).toBe('hello')
|
|
expect(output.customField).toBe('defaultValue')
|
|
})
|
|
|
|
it.concurrent('runtime value overrides default value', () => {
|
|
const block = createBlock('start_trigger', 'start', {
|
|
subBlocks: {
|
|
inputFormat: {
|
|
value: [{ name: 'customField', type: 'string', value: 'defaultValue' }],
|
|
},
|
|
},
|
|
})
|
|
|
|
const resolution = {
|
|
blockId: 'start',
|
|
block,
|
|
path: StartBlockPath.UNIFIED,
|
|
} as const
|
|
|
|
const output = buildStartBlockOutput({
|
|
resolution,
|
|
workflowInput: { customField: 'runtimeValue' },
|
|
})
|
|
|
|
expect(output.customField).toBe('runtimeValue')
|
|
})
|
|
|
|
it.concurrent('empty string from runtime overrides default value', () => {
|
|
const block = createBlock('start_trigger', 'start', {
|
|
subBlocks: {
|
|
inputFormat: {
|
|
value: [{ name: 'customField', type: 'string', value: 'defaultValue' }],
|
|
},
|
|
},
|
|
})
|
|
|
|
const resolution = {
|
|
blockId: 'start',
|
|
block,
|
|
path: StartBlockPath.UNIFIED,
|
|
} as const
|
|
|
|
const output = buildStartBlockOutput({
|
|
resolution,
|
|
workflowInput: { customField: '' },
|
|
})
|
|
|
|
expect(output.customField).toBe('')
|
|
})
|
|
|
|
it.concurrent('null from runtime does not override default value', () => {
|
|
const block = createBlock('start_trigger', 'start', {
|
|
subBlocks: {
|
|
inputFormat: {
|
|
value: [{ name: 'customField', type: 'string', value: 'defaultValue' }],
|
|
},
|
|
},
|
|
})
|
|
|
|
const resolution = {
|
|
blockId: 'start',
|
|
block,
|
|
path: StartBlockPath.UNIFIED,
|
|
} as const
|
|
|
|
const output = buildStartBlockOutput({
|
|
resolution,
|
|
workflowInput: { customField: null },
|
|
})
|
|
|
|
expect(output.customField).toBe('defaultValue')
|
|
})
|
|
})
|
|
})
|