Skip to main content
Glama

n8n-MCP

by 88-888
using-n8n-nodes-base-mock.test.tsβ€’7.78 kB
import { describe, it, expect, beforeEach, vi } from 'vitest'; import { getNodeTypes, mockNodeBehavior, resetAllMocks } from '../__mocks__/n8n-nodes-base'; // Example service that uses n8n-nodes-base class WorkflowService { async getNodeDescription(nodeName: string) { const nodeTypes = getNodeTypes(); const node = nodeTypes.getByName(nodeName); return node?.description; } async executeNode(nodeName: string, context: any) { const nodeTypes = getNodeTypes(); const node = nodeTypes.getByName(nodeName); if (!node?.execute) { throw new Error(`Node ${nodeName} does not have an execute method`); } return node.execute.call(context); } async validateSlackMessage(channel: string, text: string) { if (!channel || !text) { throw new Error('Channel and text are required'); } const nodeTypes = getNodeTypes(); const slackNode = nodeTypes.getByName('slack'); if (!slackNode) { throw new Error('Slack node not found'); } // Check if required properties exist const channelProp = slackNode.description.properties.find(p => p.name === 'channel'); const textProp = slackNode.description.properties.find(p => p.name === 'text'); return !!(channelProp && textProp); } } // Mock the module at the top level vi.mock('n8n-nodes-base', () => { const { getNodeTypes: mockGetNodeTypes } = require('../__mocks__/n8n-nodes-base'); return { getNodeTypes: mockGetNodeTypes }; }); describe('WorkflowService with n8n-nodes-base mock', () => { let service: WorkflowService; beforeEach(() => { resetAllMocks(); service = new WorkflowService(); }); describe('getNodeDescription', () => { it('should get webhook node description', async () => { const description = await service.getNodeDescription('webhook'); expect(description).toBeDefined(); expect(description?.name).toBe('webhook'); expect(description?.group).toContain('trigger'); expect(description?.webhooks).toBeDefined(); }); it('should get httpRequest node description', async () => { const description = await service.getNodeDescription('httpRequest'); expect(description).toBeDefined(); expect(description?.name).toBe('httpRequest'); expect(description?.version).toBe(3); const methodProp = description?.properties.find(p => p.name === 'method'); expect(methodProp).toBeDefined(); expect(methodProp?.options).toHaveLength(6); }); }); describe('executeNode', () => { it('should execute httpRequest node with custom response', async () => { // Override the httpRequest node behavior for this test mockNodeBehavior('httpRequest', { execute: vi.fn(async function(this: any) { const url = this.getNodeParameter('url', 0); return [[{ json: { statusCode: 200, url, customData: 'mocked response' } }]]; }) }); const mockContext = { getInputData: vi.fn(() => [{ json: { input: 'data' } }]), getNodeParameter: vi.fn((name: string) => { if (name === 'url') return 'https://test.com/api'; return ''; }) }; const result = await service.executeNode('httpRequest', mockContext); expect(result).toBeDefined(); expect(result[0][0].json).toMatchObject({ statusCode: 200, url: 'https://test.com/api', customData: 'mocked response' }); }); it('should execute slack node and track calls', async () => { const mockContext = { getInputData: vi.fn(() => [{ json: { message: 'test' } }]), getNodeParameter: vi.fn((name: string, index: number) => { const params: Record<string, string> = { resource: 'message', operation: 'post', channel: '#general', text: 'Hello from test!' }; return params[name] || ''; }), getCredentials: vi.fn(async () => ({ token: 'mock-token' })) }; const result = await service.executeNode('slack', mockContext); expect(result).toBeDefined(); expect(result[0][0].json).toMatchObject({ ok: true, channel: '#general', message: { text: 'Hello from test!' } }); // Verify the mock was called expect(mockContext.getNodeParameter).toHaveBeenCalledWith('channel', 0, ''); expect(mockContext.getNodeParameter).toHaveBeenCalledWith('text', 0, ''); }); it('should throw error for non-executable node', async () => { // Create a trigger-only node mockNodeBehavior('webhook', { execute: undefined // Remove execute method }); await expect( service.executeNode('webhook', {}) ).rejects.toThrow('Node webhook does not have an execute method'); }); }); describe('validateSlackMessage', () => { it('should validate slack message parameters', async () => { const isValid = await service.validateSlackMessage('#general', 'Hello'); expect(isValid).toBe(true); }); it('should throw error for missing parameters', async () => { await expect( service.validateSlackMessage('', 'Hello') ).rejects.toThrow('Channel and text are required'); await expect( service.validateSlackMessage('#general', '') ).rejects.toThrow('Channel and text are required'); }); it('should handle missing slack node', async () => { // Save the original mock implementation const originalImplementation = vi.mocked(getNodeTypes).getMockImplementation(); // Override getNodeTypes to return undefined for slack vi.mocked(getNodeTypes).mockImplementation(() => ({ getByName: vi.fn((name: string) => { if (name === 'slack') return undefined; // Return the actual mock implementation for other nodes const actualRegistry = originalImplementation ? originalImplementation() : getNodeTypes(); return actualRegistry.getByName(name); }), getByNameAndVersion: vi.fn() })); await expect( service.validateSlackMessage('#general', 'Hello') ).rejects.toThrow('Slack node not found'); // Restore the original implementation if (originalImplementation) { vi.mocked(getNodeTypes).mockImplementation(originalImplementation); } }); }); describe('complex workflow scenarios', () => { it('should handle if node branching', async () => { const mockContext = { getInputData: vi.fn(() => [ { json: { status: 'active' } }, { json: { status: 'inactive' } }, { json: { status: 'active' } }, ]), getNodeParameter: vi.fn() }; const result = await service.executeNode('if', mockContext); expect(result).toHaveLength(2); // true and false branches expect(result[0]).toHaveLength(2); // items at index 0 and 2 expect(result[1]).toHaveLength(1); // item at index 1 }); it('should handle merge node combining inputs', async () => { const mockContext = { getInputData: vi.fn((inputIndex?: number) => { if (inputIndex === 0) return [{ json: { source: 'input1' } }]; if (inputIndex === 1) return [{ json: { source: 'input2' } }]; return [{ json: { source: 'input1' } }]; }), getNodeParameter: vi.fn(() => 'append') }; const result = await service.executeNode('merge', mockContext); expect(result).toBeDefined(); expect(result[0]).toHaveLength(1); }); }); });

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