Skip to main content
Glama
flow-editor.test.disabled8.32 kB
import { describe, it, expect, beforeEach, afterEach, vi, SpyInstance } from 'vitest'; import fs from 'fs'; import path from 'path'; import { serveFlowEditor } from '../server/flow-editor'; import chalk from 'chalk'; import http from 'http'; import express from 'express'; // Mock modules vi.mock('fs'); vi.mock('http'); vi.mock('express', () => { const mockExpress = vi.fn(() => ({ use: vi.fn(), get: vi.fn(), post: vi.fn(), listen: vi.fn() })); mockExpress.json = vi.fn(() => 'mock-json-middleware'); mockExpress.static = vi.fn(() => 'mock-static-middleware'); return { default: mockExpress }; }); vi.mock('chalk', () => ({ default: { green: vi.fn((str) => `GREEN: ${str}`), blue: vi.fn((str) => `BLUE: ${str}`), yellow: vi.fn((str) => `YELLOW: ${str}`), red: vi.fn((str) => `RED: ${str}`) } })); describe('Flow Editor Server', () => { let mockApp: any; let mockServer: any; let consoleLogSpy: SpyInstance; let consoleErrorSpy: SpyInstance; // Mock data const testFlows = [ { id: 'flow_1', name: 'Test Flow', nodes: [{ id: 'node1', type: 'start', position: { x: 0, y: 0 }, data: {} }], edges: [] } ]; const testBlahManifest = { name: "test-manifest", version: "1.0.0", tools: [], flows: testFlows }; const testBlahJsonPath = path.resolve(process.cwd(), 'blah.json'); beforeEach(() => { // Reset mocks vi.resetAllMocks(); // Setup console spies consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {}); consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); // Setup express mock mockApp = { use: vi.fn(), get: vi.fn(), post: vi.fn(), listen: vi.fn() }; (express as any).mockReturnValue(mockApp); // Setup http mock mockServer = { listen: vi.fn() }; (http.createServer as any).mockReturnValue(mockServer); // Mock process.cwd vi.spyOn(process, 'cwd').mockReturnValue('/mock/cwd'); }); afterEach(() => { vi.clearAllMocks(); }); it('should setup express app with middleware', () => { serveFlowEditor(); expect(express).toHaveBeenCalled(); expect(mockApp.use).toHaveBeenCalledWith(expect.anything()); expect(express.json).toHaveBeenCalledWith({ limit: '10mb' }); expect(express.static).toHaveBeenCalled(); }); it('should check for existing blah.json file and load flows', () => { // Mock fs.existsSync to return true (fs.existsSync as any).mockReturnValue(true); // Mock fs.readFileSync to return test manifest (fs.readFileSync as any).mockReturnValue(JSON.stringify(testBlahManifest)); serveFlowEditor(); expect(fs.existsSync).toHaveBeenCalledWith(expect.stringContaining('blah.json')); expect(fs.readFileSync).toHaveBeenCalledWith(expect.stringContaining('blah.json'), 'utf8'); expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Loaded')); }); it('should create empty flows array if not present in manifest', () => { // Mock fs.existsSync to return true (fs.existsSync as any).mockReturnValue(true); // Mock fs.readFileSync to return manifest without flows (fs.readFileSync as any).mockReturnValue(JSON.stringify({ name: "test-manifest", version: "1.0.0", tools: [] })); serveFlowEditor(); expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('No flows found')); }); it('should handle missing blah.json', () => { // Mock fs.existsSync to return false (fs.existsSync as any).mockReturnValue(false); serveFlowEditor(); expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('not found')); expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Will create a new blah.json')); }); it('should handle API endpoints for flows', () => { // Setup mock app with proper methods mockApp.get.mockImplementation((path, handler) => { // Store the handler for testing mockApp.getHandler = handler; return mockApp; }); mockApp.post.mockImplementation((path, handler) => { // Store the handler for testing mockApp.postHandler = handler; return mockApp; }); serveFlowEditor(); // Check that the endpoints are set up expect(mockApp.get).toHaveBeenCalledWith('/api/flows', expect.any(Function)); expect(mockApp.post).toHaveBeenCalledWith('/api/flows', expect.any(Function)); }); it('should save flows to blah.json', () => { // Mock fs.existsSync to return false first (file doesn't exist), then true for directory check (fs.existsSync as any).mockImplementation((path) => { if (path === testBlahJsonPath) return false; return true; // Directory exists }); // Setup mock app with proper methods mockApp.post.mockImplementation((path, handler) => { // Store the handler for testing mockApp.postHandler = handler; return mockApp; }); // Call serveFlowEditor to set up the handlers serveFlowEditor(); // Mock request and response const req = { body: { flows: testFlows } }; const res = { status: vi.fn().mockReturnThis(), json: vi.fn() }; // Call the handler directly using the stored reference mockApp.postHandler(req, res); // Verify the file is written expect(fs.writeFileSync).toHaveBeenCalledWith( expect.stringContaining('blah.json'), expect.stringContaining('test-manifest'), 'utf8' ); expect(res.json).toHaveBeenCalledWith(expect.objectContaining({ success: true })); }); it('should create directory if it does not exist', () => { // Mock fs.existsSync to return false for both file and directory (fs.existsSync as any).mockReturnValue(false); // Setup mock app with proper methods mockApp.post.mockImplementation((path, handler) => { // Store the handler for testing mockApp.postHandler = handler; return mockApp; }); // Call serveFlowEditor to set up the handlers serveFlowEditor(); // Mock request and response const req = { body: { flows: testFlows } }; const res = { status: vi.fn().mockReturnThis(), json: vi.fn() }; // Call the handler directly using the stored reference mockApp.postHandler(req, res); // Verify directory is created expect(fs.mkdirSync).toHaveBeenCalledWith(expect.any(String), { recursive: true }); // Verify the file is written expect(fs.writeFileSync).toHaveBeenCalled(); }); it('should handle invalid flow data', () => { serveFlowEditor(); const postHandler = mockApp.post.mock.calls[0][1]; // Mock request with invalid data and response const req = { body: { flows: 'not-an-array' } }; const res = { status: vi.fn().mockReturnThis(), json: vi.fn() }; // Call the handler postHandler(req, res); // Verify error response expect(res.status).toHaveBeenCalledWith(400); expect(res.json).toHaveBeenCalledWith(expect.objectContaining({ error: expect.any(String) })); }); it('should handle errors when saving flows', () => { // Mock fs.existsSync to return true (fs.existsSync as any).mockReturnValue(true); // Mock fs.writeFileSync to throw an error (fs.writeFileSync as any).mockImplementation(() => { throw new Error('Test error'); }); serveFlowEditor(); const postHandler = mockApp.post.mock.calls[0][1]; // Mock request and response const req = { body: { flows: testFlows } }; const res = { status: vi.fn().mockReturnThis(), json: vi.fn() }; // Call the handler postHandler(req, res); // Verify error handling expect(consoleErrorSpy).toHaveBeenCalled(); expect(res.status).toHaveBeenCalledWith(500); expect(res.json).toHaveBeenCalledWith(expect.objectContaining({ error: expect.any(String) })); }); it('should start the server on the specified port', () => { const testPort = 4444; serveFlowEditor(testPort); expect(mockServer.listen).toHaveBeenCalledWith(testPort, expect.any(Function)); }); });

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