mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-02-06 05:23:08 +00:00
test: add comprehensive test coverage for webhook autofixer and node similarity
- Add test suite for NodeSimilarityService (16 tests) - Tests for common mistake patterns and typo detection - Cache invalidation and expiry tests - Node suggestion scoring and auto-fixable detection - Add test suite for WorkflowAutoFixer (15 tests) - Tests for webhook path generation with UUID - Expression format fixing validation - TypeVersion correction tests - Node type correction tests - Confidence filtering tests - Add test suite for node-type-utils (29 tests) - Package prefix normalization tests - Edge case handling tests All tests passing with correct TypeScript types and interfaces. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
199
tests/unit/utils/node-type-utils.test.ts
Normal file
199
tests/unit/utils/node-type-utils.test.ts
Normal file
@@ -0,0 +1,199 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import {
|
||||
normalizeNodeType,
|
||||
denormalizeNodeType,
|
||||
extractNodeName,
|
||||
getNodePackage,
|
||||
isBaseNode,
|
||||
isLangChainNode,
|
||||
isValidNodeTypeFormat,
|
||||
getNodeTypeVariations
|
||||
} from '@/utils/node-type-utils';
|
||||
|
||||
describe('node-type-utils', () => {
|
||||
describe('normalizeNodeType', () => {
|
||||
it('should normalize n8n-nodes-base to nodes-base', () => {
|
||||
expect(normalizeNodeType('n8n-nodes-base.httpRequest')).toBe('nodes-base.httpRequest');
|
||||
expect(normalizeNodeType('n8n-nodes-base.webhook')).toBe('nodes-base.webhook');
|
||||
});
|
||||
|
||||
it('should normalize @n8n/n8n-nodes-langchain to nodes-langchain', () => {
|
||||
expect(normalizeNodeType('@n8n/n8n-nodes-langchain.openAi')).toBe('nodes-langchain.openAi');
|
||||
expect(normalizeNodeType('@n8n/n8n-nodes-langchain.chatOpenAi')).toBe('nodes-langchain.chatOpenAi');
|
||||
});
|
||||
|
||||
it('should leave already normalized types unchanged', () => {
|
||||
expect(normalizeNodeType('nodes-base.httpRequest')).toBe('nodes-base.httpRequest');
|
||||
expect(normalizeNodeType('nodes-langchain.openAi')).toBe('nodes-langchain.openAi');
|
||||
});
|
||||
|
||||
it('should handle empty or null inputs', () => {
|
||||
expect(normalizeNodeType('')).toBe('');
|
||||
expect(normalizeNodeType(null as any)).toBe(null);
|
||||
expect(normalizeNodeType(undefined as any)).toBe(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('denormalizeNodeType', () => {
|
||||
it('should denormalize nodes-base to n8n-nodes-base', () => {
|
||||
expect(denormalizeNodeType('nodes-base.httpRequest', 'base')).toBe('n8n-nodes-base.httpRequest');
|
||||
expect(denormalizeNodeType('nodes-base.webhook', 'base')).toBe('n8n-nodes-base.webhook');
|
||||
});
|
||||
|
||||
it('should denormalize nodes-langchain to @n8n/n8n-nodes-langchain', () => {
|
||||
expect(denormalizeNodeType('nodes-langchain.openAi', 'langchain')).toBe('@n8n/n8n-nodes-langchain.openAi');
|
||||
expect(denormalizeNodeType('nodes-langchain.chatOpenAi', 'langchain')).toBe('@n8n/n8n-nodes-langchain.chatOpenAi');
|
||||
});
|
||||
|
||||
it('should handle already denormalized types', () => {
|
||||
expect(denormalizeNodeType('n8n-nodes-base.httpRequest', 'base')).toBe('n8n-nodes-base.httpRequest');
|
||||
expect(denormalizeNodeType('@n8n/n8n-nodes-langchain.openAi', 'langchain')).toBe('@n8n/n8n-nodes-langchain.openAi');
|
||||
});
|
||||
|
||||
it('should handle empty or null inputs', () => {
|
||||
expect(denormalizeNodeType('', 'base')).toBe('');
|
||||
expect(denormalizeNodeType(null as any, 'base')).toBe(null);
|
||||
expect(denormalizeNodeType(undefined as any, 'base')).toBe(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('extractNodeName', () => {
|
||||
it('should extract node name from normalized types', () => {
|
||||
expect(extractNodeName('nodes-base.httpRequest')).toBe('httpRequest');
|
||||
expect(extractNodeName('nodes-langchain.openAi')).toBe('openAi');
|
||||
});
|
||||
|
||||
it('should extract node name from denormalized types', () => {
|
||||
expect(extractNodeName('n8n-nodes-base.httpRequest')).toBe('httpRequest');
|
||||
expect(extractNodeName('@n8n/n8n-nodes-langchain.openAi')).toBe('openAi');
|
||||
});
|
||||
|
||||
it('should handle types without package prefix', () => {
|
||||
expect(extractNodeName('httpRequest')).toBe('httpRequest');
|
||||
});
|
||||
|
||||
it('should handle empty or null inputs', () => {
|
||||
expect(extractNodeName('')).toBe('');
|
||||
expect(extractNodeName(null as any)).toBe('');
|
||||
expect(extractNodeName(undefined as any)).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getNodePackage', () => {
|
||||
it('should extract package from normalized types', () => {
|
||||
expect(getNodePackage('nodes-base.httpRequest')).toBe('nodes-base');
|
||||
expect(getNodePackage('nodes-langchain.openAi')).toBe('nodes-langchain');
|
||||
});
|
||||
|
||||
it('should extract package from denormalized types', () => {
|
||||
expect(getNodePackage('n8n-nodes-base.httpRequest')).toBe('nodes-base');
|
||||
expect(getNodePackage('@n8n/n8n-nodes-langchain.openAi')).toBe('nodes-langchain');
|
||||
});
|
||||
|
||||
it('should return null for types without package', () => {
|
||||
expect(getNodePackage('httpRequest')).toBeNull();
|
||||
expect(getNodePackage('')).toBeNull();
|
||||
});
|
||||
|
||||
it('should handle null inputs', () => {
|
||||
expect(getNodePackage(null as any)).toBeNull();
|
||||
expect(getNodePackage(undefined as any)).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isBaseNode', () => {
|
||||
it('should identify base nodes correctly', () => {
|
||||
expect(isBaseNode('nodes-base.httpRequest')).toBe(true);
|
||||
expect(isBaseNode('n8n-nodes-base.webhook')).toBe(true);
|
||||
expect(isBaseNode('nodes-base.slack')).toBe(true);
|
||||
});
|
||||
|
||||
it('should reject non-base nodes', () => {
|
||||
expect(isBaseNode('nodes-langchain.openAi')).toBe(false);
|
||||
expect(isBaseNode('@n8n/n8n-nodes-langchain.chatOpenAi')).toBe(false);
|
||||
expect(isBaseNode('httpRequest')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isLangChainNode', () => {
|
||||
it('should identify langchain nodes correctly', () => {
|
||||
expect(isLangChainNode('nodes-langchain.openAi')).toBe(true);
|
||||
expect(isLangChainNode('@n8n/n8n-nodes-langchain.chatOpenAi')).toBe(true);
|
||||
expect(isLangChainNode('nodes-langchain.vectorStore')).toBe(true);
|
||||
});
|
||||
|
||||
it('should reject non-langchain nodes', () => {
|
||||
expect(isLangChainNode('nodes-base.httpRequest')).toBe(false);
|
||||
expect(isLangChainNode('n8n-nodes-base.webhook')).toBe(false);
|
||||
expect(isLangChainNode('openAi')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isValidNodeTypeFormat', () => {
|
||||
it('should validate correct node type formats', () => {
|
||||
expect(isValidNodeTypeFormat('nodes-base.httpRequest')).toBe(true);
|
||||
expect(isValidNodeTypeFormat('n8n-nodes-base.webhook')).toBe(true);
|
||||
expect(isValidNodeTypeFormat('nodes-langchain.openAi')).toBe(true);
|
||||
// @n8n/n8n-nodes-langchain.chatOpenAi actually has a slash in the first part, so it appears as 2 parts when split by dot
|
||||
expect(isValidNodeTypeFormat('@n8n/n8n-nodes-langchain.chatOpenAi')).toBe(true);
|
||||
});
|
||||
|
||||
it('should reject invalid formats', () => {
|
||||
expect(isValidNodeTypeFormat('httpRequest')).toBe(false); // No package
|
||||
expect(isValidNodeTypeFormat('nodes-base.')).toBe(false); // No node name
|
||||
expect(isValidNodeTypeFormat('.httpRequest')).toBe(false); // No package
|
||||
expect(isValidNodeTypeFormat('nodes.base.httpRequest')).toBe(false); // Too many parts
|
||||
expect(isValidNodeTypeFormat('')).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle invalid types', () => {
|
||||
expect(isValidNodeTypeFormat(null as any)).toBe(false);
|
||||
expect(isValidNodeTypeFormat(undefined as any)).toBe(false);
|
||||
expect(isValidNodeTypeFormat(123 as any)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getNodeTypeVariations', () => {
|
||||
it('should generate variations for node name without package', () => {
|
||||
const variations = getNodeTypeVariations('httpRequest');
|
||||
expect(variations).toContain('nodes-base.httpRequest');
|
||||
expect(variations).toContain('n8n-nodes-base.httpRequest');
|
||||
expect(variations).toContain('nodes-langchain.httpRequest');
|
||||
expect(variations).toContain('@n8n/n8n-nodes-langchain.httpRequest');
|
||||
});
|
||||
|
||||
it('should generate variations for normalized base node', () => {
|
||||
const variations = getNodeTypeVariations('nodes-base.httpRequest');
|
||||
expect(variations).toContain('nodes-base.httpRequest');
|
||||
expect(variations).toContain('n8n-nodes-base.httpRequest');
|
||||
expect(variations.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should generate variations for denormalized base node', () => {
|
||||
const variations = getNodeTypeVariations('n8n-nodes-base.webhook');
|
||||
expect(variations).toContain('nodes-base.webhook');
|
||||
expect(variations).toContain('n8n-nodes-base.webhook');
|
||||
expect(variations.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should generate variations for normalized langchain node', () => {
|
||||
const variations = getNodeTypeVariations('nodes-langchain.openAi');
|
||||
expect(variations).toContain('nodes-langchain.openAi');
|
||||
expect(variations).toContain('@n8n/n8n-nodes-langchain.openAi');
|
||||
expect(variations.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should generate variations for denormalized langchain node', () => {
|
||||
const variations = getNodeTypeVariations('@n8n/n8n-nodes-langchain.chatOpenAi');
|
||||
expect(variations).toContain('nodes-langchain.chatOpenAi');
|
||||
expect(variations).toContain('@n8n/n8n-nodes-langchain.chatOpenAi');
|
||||
expect(variations.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should remove duplicates from variations', () => {
|
||||
const variations = getNodeTypeVariations('nodes-base.httpRequest');
|
||||
const uniqueVariations = [...new Set(variations)];
|
||||
expect(variations.length).toBe(uniqueVariations.length);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user