Skip to main content
Glama
trigger-detector.test.tsβ€’10.1 kB
/** * Unit tests for trigger detection */ import { describe, it, expect } from 'vitest'; import { detectTriggerFromWorkflow, buildTriggerUrl, describeTrigger } from '../../../src/triggers/trigger-detector'; import type { Workflow } from '../../../src/types/n8n-api'; // Helper to create a workflow with a specific trigger node function createWorkflowWithTrigger(triggerType: string, params: Record<string, unknown> = {}): Workflow { return { id: 'test-workflow', name: 'Test Workflow', active: true, nodes: [ { id: 'trigger-node', name: 'Trigger', type: triggerType, typeVersion: 1, position: [0, 0], parameters: params, }, { id: 'action-node', name: 'Action', type: 'n8n-nodes-base.noOp', typeVersion: 1, position: [200, 0], parameters: {}, }, ], connections: {}, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), settings: {}, staticData: undefined, } as Workflow; } describe('Trigger Detector', () => { describe('detectTriggerFromWorkflow', () => { describe('webhook detection', () => { it('should detect n8n-nodes-base.webhook as webhook trigger', () => { const workflow = createWorkflowWithTrigger('n8n-nodes-base.webhook', { path: 'my-webhook', httpMethod: 'POST', }); const result = detectTriggerFromWorkflow(workflow); expect(result.detected).toBe(true); expect(result.trigger?.type).toBe('webhook'); expect(result.trigger?.webhookPath).toBe('my-webhook'); expect(result.trigger?.httpMethod).toBe('POST'); }); it('should detect webhook node with httpMethod from parameters', () => { const workflow = createWorkflowWithTrigger('n8n-nodes-base.webhook', { path: 'get-data', httpMethod: 'GET', }); const result = detectTriggerFromWorkflow(workflow); expect(result.detected).toBe(true); expect(result.trigger?.type).toBe('webhook'); expect(result.trigger?.httpMethod).toBe('GET'); }); it('should default httpMethod to POST when not specified', () => { const workflow = createWorkflowWithTrigger('n8n-nodes-base.webhook', { path: 'test-path', }); const result = detectTriggerFromWorkflow(workflow); expect(result.detected).toBe(true); expect(result.trigger?.type).toBe('webhook'); // Default is POST when not specified expect(result.trigger?.httpMethod).toBe('POST'); }); }); describe('form detection', () => { it('should detect n8n-nodes-base.formTrigger as form trigger', () => { const workflow = createWorkflowWithTrigger('n8n-nodes-base.formTrigger', { path: 'my-form', }); const result = detectTriggerFromWorkflow(workflow); expect(result.detected).toBe(true); expect(result.trigger?.type).toBe('form'); expect(result.trigger?.node?.parameters?.path).toBe('my-form'); }); }); describe('chat detection', () => { it('should detect @n8n/n8n-nodes-langchain.chatTrigger as chat trigger', () => { const workflow = createWorkflowWithTrigger('@n8n/n8n-nodes-langchain.chatTrigger', { path: 'chat-endpoint', }); const result = detectTriggerFromWorkflow(workflow); expect(result.detected).toBe(true); expect(result.trigger?.type).toBe('chat'); }); it('should detect n8n-nodes-langchain.chatTrigger as chat trigger', () => { const workflow = createWorkflowWithTrigger('n8n-nodes-langchain.chatTrigger', { webhookPath: 'ai-chat', }); const result = detectTriggerFromWorkflow(workflow); expect(result.detected).toBe(true); expect(result.trigger?.type).toBe('chat'); }); }); describe('non-triggerable workflows', () => { it('should return not detected for schedule trigger', () => { const workflow = createWorkflowWithTrigger('n8n-nodes-base.scheduleTrigger', { rule: { interval: [{ field: 'hours', value: 1 }] }, }); const result = detectTriggerFromWorkflow(workflow); expect(result.detected).toBe(false); // Fallback reason may be undefined for non-input triggers }); it('should return not detected for manual trigger', () => { const workflow = createWorkflowWithTrigger('n8n-nodes-base.manualTrigger', {}); const result = detectTriggerFromWorkflow(workflow); expect(result.detected).toBe(false); }); it('should return not detected for email trigger', () => { const workflow = createWorkflowWithTrigger('n8n-nodes-base.emailReadImap', { mailbox: 'INBOX', }); const result = detectTriggerFromWorkflow(workflow); expect(result.detected).toBe(false); }); }); describe('workflows without triggers', () => { it('should return not detected for workflow with no trigger node', () => { const workflow: Workflow = { id: 'test-workflow', name: 'Test Workflow', active: true, nodes: [ { id: 'action-node', name: 'Action', type: 'n8n-nodes-base.noOp', typeVersion: 1, position: [0, 0], parameters: {}, }, ], connections: {}, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), settings: {}, staticData: undefined, } as Workflow; const result = detectTriggerFromWorkflow(workflow); expect(result.detected).toBe(false); }); }); }); describe('buildTriggerUrl', () => { it('should build webhook URL correctly', () => { const baseUrl = 'https://n8n.example.com'; const trigger = { type: 'webhook' as const, node: { id: 'trigger', name: 'Webhook', type: 'n8n-nodes-base.webhook', typeVersion: 1, position: [0, 0] as [number, number], parameters: { path: 'my-webhook' }, }, webhookPath: 'my-webhook', }; const url = buildTriggerUrl(baseUrl, trigger, 'production'); expect(url).toBe('https://n8n.example.com/webhook/my-webhook'); }); it('should build test webhook URL correctly', () => { const baseUrl = 'https://n8n.example.com/'; const trigger = { type: 'webhook' as const, node: { id: 'trigger', name: 'Webhook', type: 'n8n-nodes-base.webhook', typeVersion: 1, position: [0, 0] as [number, number], parameters: { path: 'test-path' }, }, webhookPath: 'test-path', }; const url = buildTriggerUrl(baseUrl, trigger, 'test'); expect(url).toBe('https://n8n.example.com/webhook-test/test-path'); }); it('should build form URL with node ID when webhookPath not set', () => { const baseUrl = 'https://n8n.example.com'; const trigger = { type: 'form' as const, node: { id: 'trigger', name: 'Form', type: 'n8n-nodes-base.formTrigger', typeVersion: 1, position: [0, 0] as [number, number], parameters: { path: 'my-form' }, }, // webhookPath is undefined - should use node.id }; const url = buildTriggerUrl(baseUrl, trigger, 'production'); // When webhookPath is not set, uses node.id as fallback expect(url).toContain('/form/'); }); it('should build chat URL correctly', () => { const baseUrl = 'https://n8n.example.com'; const trigger = { type: 'chat' as const, node: { id: 'trigger', name: 'Chat', type: '@n8n/n8n-nodes-langchain.chatTrigger', typeVersion: 1, position: [0, 0] as [number, number], parameters: { path: 'ai-chat' }, }, webhookPath: 'ai-chat', }; const url = buildTriggerUrl(baseUrl, trigger, 'production'); expect(url).toBe('https://n8n.example.com/webhook/ai-chat'); }); }); describe('describeTrigger', () => { it('should describe webhook trigger', () => { const trigger = { type: 'webhook' as const, node: { id: 'trigger', name: 'My Webhook', type: 'n8n-nodes-base.webhook', typeVersion: 1, position: [0, 0] as [number, number], parameters: { path: 'my-webhook' }, }, webhookPath: 'my-webhook', httpMethod: 'POST' as const, }; const description = describeTrigger(trigger); // Case-insensitive check expect(description.toLowerCase()).toContain('webhook'); expect(description).toContain('POST'); expect(description).toContain('my-webhook'); }); it('should describe form trigger', () => { const trigger = { type: 'form' as const, node: { id: 'trigger', name: 'Contact Form', type: 'n8n-nodes-base.formTrigger', typeVersion: 1, position: [0, 0] as [number, number], parameters: { path: 'contact' }, }, webhookPath: 'contact', }; const description = describeTrigger(trigger); // Case-insensitive check expect(description.toLowerCase()).toContain('form'); }); it('should describe chat trigger', () => { const trigger = { type: 'chat' as const, node: { id: 'trigger', name: 'AI Chat', type: '@n8n/n8n-nodes-langchain.chatTrigger', typeVersion: 1, position: [0, 0] as [number, number], parameters: {}, }, }; const description = describeTrigger(trigger); // Case-insensitive check expect(description.toLowerCase()).toContain('chat'); }); }); });

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

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