Major improvements based on comprehensive test suite review: Test Fixes: - Fix all 78 failing tests across logger, MSW, and validator tests - Fix console spy management in logger tests with proper DEBUG env handling - Fix MSW test environment restoration in session-management.test.ts - Fix workflow validator tests by adding proper node connections - Fix mock setup issues in edge case tests Test Organization: - Split large config-validator.test.ts (1,075 lines) into 4 focused files - Rename 63+ tests to follow "should X when Y" naming convention - Add comprehensive edge case test files for all major validators - Create tests/README.md with testing guidelines and best practices New Features: - Add ConfigValidator.validateBatch() method for bulk validation - Add edge case coverage for null/undefined, boundaries, invalid data - Add CI-aware performance test timeouts - Add JSDoc comments to test utilities and factories - Add workflow duplicate node name validation tests Results: - All tests passing: 1,356 passed, 19 skipped - Test coverage: 85.34% statements, 85.3% branches - From 78 failures to 0 failures 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
128 lines
3.9 KiB
TypeScript
128 lines
3.9 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { WorkflowValidator } from '@/services/workflow-validator';
|
|
|
|
// Mock dependencies - don't use vi.mock for complex mocks
|
|
vi.mock('@/services/expression-validator', () => ({
|
|
ExpressionValidator: {
|
|
validateNodeExpressions: () => ({
|
|
valid: true,
|
|
errors: [],
|
|
warnings: [],
|
|
variables: [],
|
|
expressions: []
|
|
})
|
|
}
|
|
}));
|
|
vi.mock('@/utils/logger', () => ({
|
|
Logger: vi.fn().mockImplementation(() => ({
|
|
error: vi.fn(),
|
|
warn: vi.fn(),
|
|
info: vi.fn(),
|
|
debug: vi.fn()
|
|
}))
|
|
}));
|
|
|
|
describe('Debug Validator Tests', () => {
|
|
let validator: WorkflowValidator;
|
|
let mockNodeRepository: any;
|
|
let mockEnhancedConfigValidator: any;
|
|
|
|
beforeEach(() => {
|
|
// Create mock repository
|
|
mockNodeRepository = {
|
|
getNode: (nodeType: string) => {
|
|
// Handle both n8n-nodes-base.set and nodes-base.set (normalized)
|
|
if (nodeType === 'n8n-nodes-base.set' || nodeType === 'nodes-base.set') {
|
|
return {
|
|
name: 'Set',
|
|
type: 'nodes-base.set',
|
|
typeVersion: 1,
|
|
properties: [],
|
|
package: 'n8n-nodes-base',
|
|
version: 1,
|
|
displayName: 'Set'
|
|
};
|
|
}
|
|
return null;
|
|
}
|
|
};
|
|
|
|
// Create mock EnhancedConfigValidator
|
|
mockEnhancedConfigValidator = {
|
|
validateWithMode: () => ({
|
|
valid: true,
|
|
errors: [],
|
|
warnings: [],
|
|
suggestions: [],
|
|
mode: 'operation',
|
|
visibleProperties: [],
|
|
hiddenProperties: []
|
|
})
|
|
};
|
|
|
|
// Create validator instance
|
|
validator = new WorkflowValidator(mockNodeRepository, mockEnhancedConfigValidator as any);
|
|
});
|
|
|
|
it('should handle nodes at extreme positions - debug', async () => {
|
|
const workflow = {
|
|
nodes: [
|
|
{ id: '1', name: 'FarLeft', type: 'n8n-nodes-base.set', position: [-999999, -999999] as [number, number], parameters: {} },
|
|
{ id: '2', name: 'FarRight', type: 'n8n-nodes-base.set', position: [999999, 999999] as [number, number], parameters: {} },
|
|
{ id: '3', name: 'Zero', type: 'n8n-nodes-base.set', position: [0, 0] as [number, number], parameters: {} }
|
|
],
|
|
connections: {
|
|
'FarLeft': {
|
|
main: [[{ node: 'FarRight', type: 'main', index: 0 }]]
|
|
},
|
|
'FarRight': {
|
|
main: [[{ node: 'Zero', type: 'main', index: 0 }]]
|
|
}
|
|
}
|
|
};
|
|
|
|
const result = await validator.validateWorkflow(workflow);
|
|
|
|
|
|
// Test should pass with extreme positions
|
|
expect(result.valid).toBe(true);
|
|
expect(result.errors).toHaveLength(0);
|
|
});
|
|
|
|
it('should handle special characters in node names - debug', async () => {
|
|
const workflow = {
|
|
nodes: [
|
|
{ id: '1', name: 'Node@#$%', type: 'n8n-nodes-base.set', position: [0, 0] as [number, number], parameters: {} },
|
|
{ id: '2', name: 'Node 中文', type: 'n8n-nodes-base.set', position: [100, 0] as [number, number], parameters: {} },
|
|
{ id: '3', name: 'Node😊', type: 'n8n-nodes-base.set', position: [200, 0] as [number, number], parameters: {} }
|
|
],
|
|
connections: {
|
|
'Node@#$%': {
|
|
main: [[{ node: 'Node 中文', type: 'main', index: 0 }]]
|
|
},
|
|
'Node 中文': {
|
|
main: [[{ node: 'Node😊', type: 'main', index: 0 }]]
|
|
}
|
|
}
|
|
};
|
|
|
|
const result = await validator.validateWorkflow(workflow);
|
|
|
|
|
|
// Test should pass with special characters in node names
|
|
expect(result.valid).toBe(true);
|
|
expect(result.errors).toHaveLength(0);
|
|
});
|
|
|
|
it('should handle non-array nodes - debug', async () => {
|
|
const workflow = {
|
|
nodes: 'not-an-array',
|
|
connections: {}
|
|
};
|
|
const result = await validator.validateWorkflow(workflow as any);
|
|
|
|
|
|
expect(result.valid).toBe(false);
|
|
expect(result.errors[0].message).toContain('nodes must be an array');
|
|
});
|
|
}); |