File size: 5,272 Bytes
da2e594
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/usr/bin/env tsx

/**
 * Test script for empty connection validation
 * Tests the improvements to prevent broken workflows like the one in the logs
 */

import { WorkflowValidator } from '../src/services/workflow-validator';
import { EnhancedConfigValidator } from '../src/services/enhanced-config-validator';
import { NodeRepository } from '../src/database/node-repository';
import { createDatabaseAdapter } from '../src/database/database-adapter';
import { validateWorkflowStructure, getWorkflowFixSuggestions, getWorkflowStructureExample } from '../src/services/n8n-validation';
import { Logger } from '../src/utils/logger';

const logger = new Logger({ prefix: '[TestEmptyConnectionValidation]' });

async function testValidation() {
  const adapter = await createDatabaseAdapter('./data/nodes.db');
  const repository = new NodeRepository(adapter);
  const validator = new WorkflowValidator(repository, EnhancedConfigValidator);

  logger.info('Testing empty connection validation...\n');

  // Test 1: The broken workflow from the logs
  const brokenWorkflow = {
    "nodes": [
      {
        "parameters": {},
        "id": "webhook_node",
        "name": "Webhook",
        "type": "nodes-base.webhook",
        "typeVersion": 2,
        "position": [260, 300] as [number, number]
      }
    ],
    "connections": {},
    "pinData": {},
    "meta": {
      "instanceId": "74e11c77e266f2c77f6408eb6c88e3fec63c9a5d8c4a3a2ea4c135c542012d6b"
    }
  };

  logger.info('Test 1: Broken single-node workflow with empty connections');
  const result1 = await validator.validateWorkflow(brokenWorkflow as any);
  
  logger.info('Validation result:');
  logger.info(`Valid: ${result1.valid}`);
  logger.info(`Errors: ${result1.errors.length}`);
  result1.errors.forEach(err => {
    if (typeof err === 'string') {
      logger.error(`  - ${err}`);
    } else if (err && typeof err === 'object' && 'message' in err) {
      logger.error(`  - ${err.message}`);
    } else {
      logger.error(`  - ${JSON.stringify(err)}`);
    }
  });
  logger.info(`Warnings: ${result1.warnings.length}`);
  result1.warnings.forEach(warn => logger.warn(`  - ${warn.message || JSON.stringify(warn)}`));
  logger.info(`Suggestions: ${result1.suggestions.length}`);
  result1.suggestions.forEach(sug => logger.info(`  - ${sug}`));

  // Test 2: Multi-node workflow with no connections
  const multiNodeNoConnections = {
    "name": "Test Workflow",
    "nodes": [
      {
        "id": "manual-1",
        "name": "Manual Trigger",
        "type": "n8n-nodes-base.manualTrigger",
        "typeVersion": 1,
        "position": [250, 300] as [number, number],
        "parameters": {}
      },
      {
        "id": "set-1",
        "name": "Set",
        "type": "n8n-nodes-base.set",
        "typeVersion": 3.4,
        "position": [450, 300] as [number, number],
        "parameters": {}
      }
    ],
    "connections": {}
  };

  logger.info('\nTest 2: Multi-node workflow with empty connections');
  const result2 = await validator.validateWorkflow(multiNodeNoConnections as any);
  
  logger.info('Validation result:');
  logger.info(`Valid: ${result2.valid}`);
  logger.info(`Errors: ${result2.errors.length}`);
  result2.errors.forEach(err => logger.error(`  - ${err.message || JSON.stringify(err)}`));
  logger.info(`Suggestions: ${result2.suggestions.length}`);
  result2.suggestions.forEach(sug => logger.info(`  - ${sug}`));

  // Test 3: Using n8n-validation functions
  logger.info('\nTest 3: Testing n8n-validation.ts functions');
  
  const errors = validateWorkflowStructure(brokenWorkflow as any);
  logger.info('Validation errors:');
  errors.forEach(err => logger.error(`  - ${err}`));
  
  const suggestions = getWorkflowFixSuggestions(errors);
  logger.info('Fix suggestions:');
  suggestions.forEach(sug => logger.info(`  - ${sug}`));
  
  logger.info('\nExample of proper workflow structure:');
  logger.info(getWorkflowStructureExample());

  // Test 4: Workflow using IDs instead of names in connections
  const workflowWithIdConnections = {
    "name": "Test Workflow",
    "nodes": [
      {
        "id": "manual-1",
        "name": "Manual Trigger",
        "type": "n8n-nodes-base.manualTrigger",
        "typeVersion": 1,
        "position": [250, 300] as [number, number],
        "parameters": {}
      },
      {
        "id": "set-1",
        "name": "Set Data",
        "type": "n8n-nodes-base.set",
        "typeVersion": 3.4,
        "position": [450, 300] as [number, number],
        "parameters": {}
      }
    ],
    "connections": {
      "manual-1": {  // Using ID instead of name!
        "main": [[{
          "node": "set-1",  // Using ID instead of name!
          "type": "main",
          "index": 0
        }]]
      }
    }
  };

  logger.info('\nTest 4: Workflow using IDs instead of names in connections');
  const result4 = await validator.validateWorkflow(workflowWithIdConnections as any);
  
  logger.info('Validation result:');
  logger.info(`Valid: ${result4.valid}`);
  logger.info(`Errors: ${result4.errors.length}`);
  result4.errors.forEach(err => logger.error(`  - ${err.message || JSON.stringify(err)}`));
  
  adapter.close();
}

testValidation().catch(err => {
  logger.error('Test failed:', err);
  process.exit(1);
});