Skip to main content
Glama

n8n-MCP

by 88-888
test-helpers.tsβ€’6.61 kB
import { vi } from 'vitest'; import { WorkflowNode, Workflow } from '@/types/n8n-api'; // Use any type for INodeDefinition since it's from n8n-workflow package type INodeDefinition = any; /** * Common test utilities and helpers */ /** * Wait for a condition to be true */ export async function waitFor( condition: () => boolean | Promise<boolean>, options: { timeout?: number; interval?: number } = {} ): Promise<void> { const { timeout = 5000, interval = 50 } = options; const startTime = Date.now(); while (Date.now() - startTime < timeout) { if (await condition()) { return; } await new Promise(resolve => setTimeout(resolve, interval)); } throw new Error(`Timeout waiting for condition after ${timeout}ms`); } /** * Create a mock node definition with default values */ export function createMockNodeDefinition(overrides?: Partial<INodeDefinition>): INodeDefinition { return { displayName: 'Mock Node', name: 'mockNode', group: ['transform'], version: 1, description: 'A mock node for testing', defaults: { name: 'Mock Node', }, inputs: ['main'], outputs: ['main'], properties: [], ...overrides }; } /** * Create a mock workflow node */ export function createMockNode(overrides?: Partial<WorkflowNode>): WorkflowNode { return { id: 'mock-node-id', name: 'Mock Node', type: 'n8n-nodes-base.mockNode', typeVersion: 1, position: [0, 0], parameters: {}, ...overrides }; } /** * Create a mock workflow */ export function createMockWorkflow(overrides?: Partial<Workflow>): Workflow { return { id: 'mock-workflow-id', name: 'Mock Workflow', active: false, nodes: [], connections: {}, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), ...overrides }; } /** * Mock console methods for tests */ export function mockConsole() { const originalConsole = { ...console }; const mocks = { log: vi.spyOn(console, 'log').mockImplementation(() => {}), error: vi.spyOn(console, 'error').mockImplementation(() => {}), warn: vi.spyOn(console, 'warn').mockImplementation(() => {}), debug: vi.spyOn(console, 'debug').mockImplementation(() => {}), info: vi.spyOn(console, 'info').mockImplementation(() => {}) }; return { mocks, restore: () => { Object.entries(mocks).forEach(([key, mock]) => { mock.mockRestore(); }); } }; } /** * Create a deferred promise for testing async operations */ export function createDeferred<T>() { let resolve: (value: T) => void; let reject: (error: any) => void; const promise = new Promise<T>((res, rej) => { resolve = res; reject = rej; }); return { promise, resolve: resolve!, reject: reject! }; } /** * Helper to test error throwing */ export async function expectToThrowAsync( fn: () => Promise<any>, errorMatcher?: string | RegExp | Error ) { let thrown = false; let error: any; try { await fn(); } catch (e) { thrown = true; error = e; } if (!thrown) { throw new Error('Expected function to throw'); } if (errorMatcher) { if (typeof errorMatcher === 'string') { expect(error.message).toContain(errorMatcher); } else if (errorMatcher instanceof RegExp) { expect(error.message).toMatch(errorMatcher); } else if (errorMatcher instanceof Error) { expect(error).toEqual(errorMatcher); } } return error; } /** * Create a test database with initial data */ export function createTestDatabase(data: Record<string, any[]> = {}) { const db = new Map<string, any[]>(); // Initialize with default tables db.set('nodes', data.nodes || []); db.set('templates', data.templates || []); db.set('tools_documentation', data.tools_documentation || []); // Add any additional tables from data Object.entries(data).forEach(([table, rows]) => { if (!db.has(table)) { db.set(table, rows); } }); return { prepare: vi.fn((sql: string) => { const tableName = extractTableName(sql); const rows = db.get(tableName) || []; return { all: vi.fn(() => rows), get: vi.fn((params: any) => { if (typeof params === 'string') { return rows.find((r: any) => r.id === params); } return rows[0]; }), run: vi.fn((params: any) => { rows.push(params); return { changes: 1, lastInsertRowid: rows.length }; }) }; }), exec: vi.fn(), close: vi.fn(), transaction: vi.fn((fn: Function) => fn()), pragma: vi.fn() }; } /** * Extract table name from SQL query */ function extractTableName(sql: string): string { const patterns = [ /FROM\s+(\w+)/i, /INTO\s+(\w+)/i, /UPDATE\s+(\w+)/i, /TABLE\s+(\w+)/i ]; for (const pattern of patterns) { const match = sql.match(pattern); if (match) { return match[1]; } } return 'nodes'; } /** * Create a mock HTTP response */ export function createMockResponse(data: any, status = 200) { return { data, status, statusText: status === 200 ? 'OK' : 'Error', headers: {}, config: {} }; } /** * Create a mock HTTP error */ export function createMockHttpError(message: string, status = 500, data?: any) { const error: any = new Error(message); error.isAxiosError = true; error.response = { data: data || { message }, status, statusText: status === 500 ? 'Internal Server Error' : 'Error', headers: {}, config: {} }; return error; } /** * Helper to test MCP tool calls */ export async function testMCPToolCall( tool: any, args: any, expectedResult?: any ) { const result = await tool.handler(args); if (expectedResult !== undefined) { expect(result).toEqual(expectedResult); } return result; } /** * Create a mock MCP context */ export function createMockMCPContext() { return { request: vi.fn(), notify: vi.fn(), expose: vi.fn(), onClose: vi.fn() }; } /** * Snapshot serializer for dates */ export const dateSerializer = { test: (value: any) => value instanceof Date, serialize: (value: Date) => value.toISOString() }; /** * Snapshot serializer for functions */ export const functionSerializer = { test: (value: any) => typeof value === 'function', serialize: () => '[Function]' }; /** * Clean up test environment */ export function cleanupTestEnvironment() { vi.clearAllMocks(); vi.clearAllTimers(); vi.useRealTimers(); }

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/88-888/n8n-mcp'

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