/** * Mock block configurations for serializer and related tests. * * @example * ```ts * import { blocksMock, mockBlockConfigs } from '@sim/testing/mocks' * * vi.mock('@/blocks', () => blocksMock) * * // Or use individual configs * const starterConfig = mockBlockConfigs.starter * ``` */ /* eslint-disable @typescript-eslint/no-explicit-any */ /** * Mock block configurations that mirror the real block registry. * Used for testing serialization, deserialization, and validation. */ export const mockBlockConfigs: Record = { starter: { name: 'Starter', description: 'Start of the workflow', category: 'flow', bgColor: '#4CAF50', tools: { access: ['starter'], config: { tool: () => 'starter' }, }, subBlocks: [ { id: 'description', type: 'long-input', label: 'Description' }, { id: 'inputFormat', type: 'table', label: 'Input Format' }, ], inputs: {}, }, agent: { name: 'Agent', description: 'AI Agent', category: 'ai', bgColor: '#2196F3', tools: { access: ['anthropic_chat', 'openai_chat', 'google_chat'], config: { tool: (params: Record) => { const model = params.model || 'gpt-4o' if (model.includes('claude')) return 'anthropic' if (model.includes('gpt') || model.includes('o1')) return 'openai' if (model.includes('gemini')) return 'google' return 'openai' }, }, }, subBlocks: [ { id: 'provider', type: 'dropdown', label: 'Provider' }, { id: 'model', type: 'dropdown', label: 'Model' }, { id: 'prompt', type: 'long-input', label: 'Prompt' }, { id: 'system', type: 'long-input', label: 'System Message' }, { id: 'tools', type: 'tool-input', label: 'Tools' }, { id: 'responseFormat', type: 'code', label: 'Response Format' }, { id: 'messages', type: 'messages-input', label: 'Messages' }, ], inputs: { input: { type: 'string' }, tools: { type: 'array' }, }, }, function: { name: 'Function', description: 'Execute custom code', category: 'code', bgColor: '#9C27B0', tools: { access: ['function'], config: { tool: () => 'function' }, }, subBlocks: [ { id: 'code', type: 'code', label: 'Code' }, { id: 'language', type: 'dropdown', label: 'Language' }, ], inputs: { input: { type: 'any' } }, }, condition: { name: 'Condition', description: 'Branch based on condition', category: 'flow', bgColor: '#FF9800', tools: { access: ['condition'], config: { tool: () => 'condition' }, }, subBlocks: [{ id: 'condition', type: 'long-input', label: 'Condition' }], inputs: { input: { type: 'any' } }, }, api: { name: 'API', description: 'Make API request', category: 'data', bgColor: '#E91E63', tools: { access: ['api'], config: { tool: () => 'api' }, }, subBlocks: [ { id: 'url', type: 'short-input', label: 'URL' }, { id: 'method', type: 'dropdown', label: 'Method' }, { id: 'headers', type: 'table', label: 'Headers' }, { id: 'body', type: 'long-input', label: 'Body' }, ], inputs: {}, }, webhook: { name: 'Webhook', description: 'Webhook trigger', category: 'triggers', bgColor: '#4CAF50', tools: { access: ['webhook'], config: { tool: () => 'webhook' }, }, subBlocks: [{ id: 'path', type: 'short-input', label: 'Path' }], inputs: {}, }, jina: { name: 'Jina', description: 'Convert website content into text', category: 'tools', bgColor: '#333333', tools: { access: ['jina_read_url'], config: { tool: () => 'jina_read_url' }, }, subBlocks: [ { id: 'url', type: 'short-input', title: 'URL', required: true }, { id: 'apiKey', type: 'short-input', title: 'API Key', required: true }, ], inputs: { url: { type: 'string' }, apiKey: { type: 'string' }, }, }, reddit: { name: 'Reddit', description: 'Access Reddit data and content', category: 'tools', bgColor: '#FF5700', tools: { access: ['reddit_get_posts', 'reddit_get_comments'], config: { tool: () => 'reddit_get_posts' }, }, subBlocks: [ { id: 'operation', type: 'dropdown', title: 'Operation', required: true }, { id: 'credential', type: 'oauth-input', title: 'Reddit Account', required: true }, { id: 'subreddit', type: 'short-input', title: 'Subreddit', required: true }, ], inputs: { operation: { type: 'string' }, credential: { type: 'string' }, subreddit: { type: 'string' }, }, }, slack: { name: 'Slack', description: 'Send messages to Slack', category: 'tools', bgColor: '#611f69', tools: { access: ['slack_send_message'], config: { tool: () => 'slack_send_message' }, }, subBlocks: [ { id: 'channel', type: 'dropdown', title: 'Channel', mode: 'basic', canonicalParamId: 'channel', }, { id: 'manualChannel', type: 'short-input', title: 'Channel ID', mode: 'advanced', canonicalParamId: 'channel', }, { id: 'text', type: 'long-input', title: 'Message' }, { id: 'username', type: 'short-input', title: 'Username', mode: 'both' }, ], inputs: { channel: { type: 'string' }, manualChannel: { type: 'string' }, text: { type: 'string' }, username: { type: 'string' }, }, }, agentWithMemories: { name: 'Agent with Memories', description: 'AI Agent with memory support', category: 'ai', bgColor: '#2196F3', tools: { access: ['anthropic_chat'], config: { tool: () => 'anthropic_chat' }, }, subBlocks: [ { id: 'systemPrompt', type: 'long-input', title: 'System Prompt' }, { id: 'userPrompt', type: 'long-input', title: 'User Prompt' }, { id: 'memories', type: 'short-input', title: 'Memories', mode: 'advanced' }, { id: 'model', type: 'dropdown', title: 'Model' }, ], inputs: { systemPrompt: { type: 'string' }, userPrompt: { type: 'string' }, memories: { type: 'array' }, model: { type: 'string' }, }, }, conditional_block: { name: 'Conditional Block', description: 'Block with conditional fields', category: 'tools', bgColor: '#FF5700', tools: { access: ['conditional_tool'], config: { tool: () => 'conditional_tool' }, }, subBlocks: [ { id: 'mode', type: 'dropdown', label: 'Mode' }, { id: 'optionA', type: 'short-input', label: 'Option A', condition: { field: 'mode', value: 'a' }, }, { id: 'optionB', type: 'short-input', label: 'Option B', condition: { field: 'mode', value: 'b' }, }, { id: 'notModeC', type: 'short-input', label: 'Not Mode C', condition: { field: 'mode', value: 'c', not: true }, }, { id: 'complexCondition', type: 'short-input', label: 'Complex', condition: { field: 'mode', value: 'a', and: { field: 'optionA', value: 'special' } }, }, { id: 'arrayCondition', type: 'short-input', label: 'Array Condition', condition: { field: 'mode', value: ['a', 'b'] }, }, ], inputs: {}, }, wait: { name: 'Wait', description: 'Pause workflow execution for a specified time delay', category: 'blocks', bgColor: '#F59E0B', tools: { access: [], }, subBlocks: [ { id: 'timeValue', title: 'Wait Amount', type: 'short-input', placeholder: '10', required: true, }, { id: 'timeUnit', title: 'Unit', type: 'dropdown', required: true, }, ], inputs: { timeValue: { type: 'string' }, timeUnit: { type: 'string' }, }, outputs: { waitDuration: { type: 'number' }, status: { type: 'string' }, }, }, } /** * Creates a getBlock function that returns mock block configs. * Can be extended with additional block types. */ export function createMockGetBlock(extraConfigs: Record = {}) { const configs = { ...mockBlockConfigs, ...extraConfigs } return (type: string) => configs[type] || null } /** * Mock tool configurations for validation tests. */ export const mockToolConfigs: Record = { jina_read_url: { params: { url: { visibility: 'user-or-llm', required: true }, apiKey: { visibility: 'user-only', required: true }, }, }, reddit_get_posts: { params: { subreddit: { visibility: 'user-or-llm', required: true }, credential: { visibility: 'user-only', required: true }, }, }, } /** * Creates a getTool function that returns mock tool configs. */ export function createMockGetTool(extraConfigs: Record = {}) { const configs = { ...mockToolConfigs, ...extraConfigs } return (toolId: string) => configs[toolId] || null } /** * Pre-configured blocks mock for use with vi.mock('@/blocks', () => blocksMock). */ export const blocksMock = { getBlock: createMockGetBlock(), getAllBlocks: () => Object.values(mockBlockConfigs), } /** * Pre-configured tools/utils mock for use with vi.mock('@/tools/utils', () => toolsUtilsMock). */ export const toolsUtilsMock = { getTool: createMockGetTool(), }