Skip to main content
Glama
flow-executor.test.ts9.51 kB
import { describe, it, expect, vi } from 'vitest'; import { executeFlow } from '../utils/flow-executor.js'; import { BlahFlow } from '../utils/validator.js'; describe('Flow Executor', () => { // Mock console.log to avoid test output pollution vi.spyOn(console, 'log').mockImplementation(() => {}); it('should execute a simple flow', async () => { const simpleFlow: BlahFlow = { name: 'simple-flow', description: 'A simple test flow', nodes: [ { name: 'start-node', type: 'manual-trigger', category: 'trigger', parameters: {}, text: 'Start Workflow' }, { name: 'end-node', type: 'execute-javascript', category: 'utility', parameters: { code: 'return { result: "Done!" };' }, text: 'End Workflow' } ], edges: [ { name: 'edge-1', startNodeName: 'start-node', endNodeName: 'end-node' } ] }; const result = await executeFlow(simpleFlow, { trigger: true }); expect(result).toEqual({ result: 'Done!' }); }); it('should handle conditional branching (high path)', async () => { // Mock Math.random to always return 0.75 (75% of the range) const originalRandom = Math.random; Math.random = vi.fn().mockReturnValue(0.75); const conditionalFlow: BlahFlow = { name: 'conditional-flow', description: 'A flow with conditional branches', nodes: [ { name: 'start-node', type: 'manual-trigger', category: 'trigger', parameters: {}, text: 'Start Workflow' }, { name: 'random-generator', type: 'random-number', category: 'utility', parameters: { min: '1', max: '100' }, text: 'Generate Random Number' }, { name: 'high-number', type: 'execute-javascript', category: 'utility', parameters: { code: 'return { message: "High number: " + inputData.randomNumber };' }, text: 'High Number' }, { name: 'low-number', type: 'execute-javascript', category: 'utility', parameters: { code: 'return { message: "Low number: " + inputData.randomNumber };' }, text: 'Low Number' }, { name: 'end-node', type: 'execute-javascript', category: 'utility', parameters: { code: 'return { result: inputData.message };' }, text: 'End Workflow' } ], edges: [ { name: 'edge-1', startNodeName: 'start-node', endNodeName: 'random-generator' }, { name: 'edge-2', startNodeName: 'random-generator', endNodeName: 'high-number', condition: 'greater_than', if: '{{random-generator.randomNumber}}', value: '50' }, { name: 'edge-3', startNodeName: 'random-generator', endNodeName: 'low-number', condition: 'less_than_or_equal', if: '{{random-generator.randomNumber}}', value: '50' }, { name: 'edge-4', startNodeName: 'high-number', endNodeName: 'end-node' }, { name: 'edge-5', startNodeName: 'low-number', endNodeName: 'end-node' } ] }; const result = await executeFlow(conditionalFlow, { trigger: true }); // With Math.random mocked to 0.75, we expect the high path to be taken // The random number should be around 75-76 expect(result.result).toContain('High number: '); // Restore original Math.random Math.random = originalRandom; }); it('should handle conditional branching (low path)', async () => { // Mock Math.random to always return 0.25 (25% of the range) const originalRandom = Math.random; Math.random = vi.fn().mockReturnValue(0.25); const conditionalFlow: BlahFlow = { name: 'conditional-flow', description: 'A flow with conditional branches', nodes: [ { name: 'start-node', type: 'manual-trigger', category: 'trigger', parameters: {}, text: 'Start Workflow' }, { name: 'random-generator', type: 'random-number', category: 'utility', parameters: { min: '1', max: '100' }, text: 'Generate Random Number' }, { name: 'high-number', type: 'execute-javascript', category: 'utility', parameters: { code: 'return { message: "High number: " + inputData.randomNumber };' }, text: 'High Number' }, { name: 'low-number', type: 'execute-javascript', category: 'utility', parameters: { code: 'return { message: "Low number: " + inputData.randomNumber };' }, text: 'Low Number' }, { name: 'end-node', type: 'execute-javascript', category: 'utility', parameters: { code: 'return { result: inputData.message };' }, text: 'End Workflow' } ], edges: [ { name: 'edge-1', startNodeName: 'start-node', endNodeName: 'random-generator' }, { name: 'edge-2', startNodeName: 'random-generator', endNodeName: 'high-number', condition: 'greater_than', if: '{{random-generator.randomNumber}}', value: '50' }, { name: 'edge-3', startNodeName: 'random-generator', endNodeName: 'low-number', condition: 'less_than_or_equal', if: '{{random-generator.randomNumber}}', value: '50' }, { name: 'edge-4', startNodeName: 'high-number', endNodeName: 'end-node' }, { name: 'edge-5', startNodeName: 'low-number', endNodeName: 'end-node' } ] }; const result = await executeFlow(conditionalFlow, { trigger: true }); // With Math.random mocked to 0.25, we expect the low path to be taken // The random number should be around 25-26 expect(result.result).toContain('Low number: '); // Restore original Math.random Math.random = originalRandom; }); it('should detect circular paths', async () => { const circularFlow: BlahFlow = { name: 'circular-flow', description: 'A flow with a circular path', nodes: [ { name: 'start-node', type: 'manual-trigger', category: 'trigger', parameters: {}, text: 'Start Workflow' }, { name: 'node-a', type: 'execute-javascript', category: 'utility', parameters: { code: 'return { step: "A" };' }, text: 'Node A' }, { name: 'node-b', type: 'execute-javascript', category: 'utility', parameters: { code: 'return { step: "B" };' }, text: 'Node B' } ], edges: [ { name: 'edge-1', startNodeName: 'start-node', endNodeName: 'node-a' }, { name: 'edge-2', startNodeName: 'node-a', endNodeName: 'node-b' }, { name: 'edge-3', startNodeName: 'node-b', endNodeName: 'node-a' // Creates a cycle } ] }; // We expect an error to be thrown because of the circular path await expect(executeFlow(circularFlow, { trigger: true })) .rejects .toThrow('Circular path detected'); }); it('should pass data between nodes', async () => { const dataFlow: BlahFlow = { name: 'data-flow', description: 'A flow that passes data between nodes', nodes: [ { name: 'start-node', type: 'manual-trigger', category: 'trigger', parameters: { inputValue: 'Hello' }, text: 'Start Workflow' }, { name: 'transform-node', type: 'execute-javascript', category: 'utility', parameters: { code: 'return { transformed: inputData.inputValue + " World" };' }, text: 'Transform Data' }, { name: 'end-node', type: 'execute-javascript', category: 'utility', parameters: { code: 'return { result: inputData.transformed + "!" };' }, text: 'End Workflow' } ], edges: [ { name: 'edge-1', startNodeName: 'start-node', endNodeName: 'transform-node' }, { name: 'edge-2', startNodeName: 'transform-node', endNodeName: 'end-node' } ] }; const result = await executeFlow(dataFlow, { inputValue: 'Hello' }); expect(result).toEqual({ result: 'Hello World!' }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/thomasdavis/blah'

If you have feedback or need assistance with the MCP directory API, please join our Discord server