diff --git a/tests/integration/n8n-api/system/diagnostic.test.ts b/tests/integration/n8n-api/system/diagnostic.test.ts index 986447d..646409a 100644 --- a/tests/integration/n8n-api/system/diagnostic.test.ts +++ b/tests/integration/n8n-api/system/diagnostic.test.ts @@ -9,6 +9,7 @@ import { describe, it, expect, beforeEach } from 'vitest'; import { createMcpContext } from '../utils/mcp-context'; import { InstanceContext } from '../../../../src/types/instance-context'; import { handleDiagnostic } from '../../../../src/mcp/handlers-n8n-manager'; +import { DiagnosticResponse } from '../utils/response-types'; describe('Integration: handleDiagnostic', () => { let mcpContext: InstanceContext; @@ -31,7 +32,7 @@ describe('Integration: handleDiagnostic', () => { expect(response.success).toBe(true); expect(response.data).toBeDefined(); - const data = response.data as any; + const data = response.data as DiagnosticResponse; // Verify core diagnostic fields expect(data).toHaveProperty('timestamp'); @@ -52,7 +53,7 @@ describe('Integration: handleDiagnostic', () => { mcpContext ); - const data = response.data as any; + const data = response.data as DiagnosticResponse; expect(data.environment).toBeDefined(); expect(data.environment).toHaveProperty('N8N_API_URL'); @@ -72,7 +73,7 @@ describe('Integration: handleDiagnostic', () => { mcpContext ); - const data = response.data as any; + const data = response.data as DiagnosticResponse; expect(data.apiConfiguration).toBeDefined(); expect(data.apiConfiguration).toHaveProperty('configured'); @@ -109,7 +110,7 @@ describe('Integration: handleDiagnostic', () => { mcpContext ); - const data = response.data as any; + const data = response.data as DiagnosticResponse; expect(data.toolsAvailability).toBeDefined(); expect(data.toolsAvailability).toHaveProperty('documentationTools'); @@ -144,7 +145,7 @@ describe('Integration: handleDiagnostic', () => { mcpContext ); - const data = response.data as any; + const data = response.data as DiagnosticResponse; expect(data.troubleshooting).toBeDefined(); expect(data.troubleshooting).toHaveProperty('steps'); @@ -172,32 +173,33 @@ describe('Integration: handleDiagnostic', () => { ); expect(response.success).toBe(true); - const data = response.data as any; + const data = response.data as DiagnosticResponse; // Verbose mode should add debug section expect(data).toHaveProperty('debug'); expect(data.debug).toBeDefined(); // Verify debug information + expect(data.debug).toBeDefined(); expect(data.debug).toHaveProperty('processEnv'); expect(data.debug).toHaveProperty('nodeVersion'); expect(data.debug).toHaveProperty('platform'); expect(data.debug).toHaveProperty('workingDirectory'); // Process env should list relevant environment variables - expect(Array.isArray(data.debug.processEnv)).toBe(true); + expect(Array.isArray(data.debug?.processEnv)).toBe(true); // Node version should be a string - expect(typeof data.debug.nodeVersion).toBe('string'); - expect(data.debug.nodeVersion).toMatch(/^v\d+\.\d+\.\d+/); + expect(typeof data.debug?.nodeVersion).toBe('string'); + expect(data.debug?.nodeVersion).toMatch(/^v\d+\.\d+\.\d+/); // Platform should be a string (linux, darwin, win32, etc.) - expect(typeof data.debug.platform).toBe('string'); - expect(data.debug.platform.length).toBeGreaterThan(0); + expect(typeof data.debug?.platform).toBe('string'); + expect(data.debug && data.debug.platform.length).toBeGreaterThan(0); // Working directory should be a path - expect(typeof data.debug.workingDirectory).toBe('string'); - expect(data.debug.workingDirectory.length).toBeGreaterThan(0); + expect(typeof data.debug?.workingDirectory).toBe('string'); + expect(data.debug && data.debug.workingDirectory.length).toBeGreaterThan(0); }); it('should not include debug info when verbose is false', async () => { @@ -207,7 +209,7 @@ describe('Integration: handleDiagnostic', () => { ); expect(response.success).toBe(true); - const data = response.data as any; + const data = response.data as DiagnosticResponse; // Debug section should not be present expect(data.debug).toBeUndefined(); @@ -220,7 +222,7 @@ describe('Integration: handleDiagnostic', () => { ); expect(response.success).toBe(true); - const data = response.data as any; + const data = response.data as DiagnosticResponse; // Debug section should not be present when verbose not specified expect(data.debug).toBeUndefined(); @@ -241,7 +243,7 @@ describe('Integration: handleDiagnostic', () => { expect(response.success).toBe(true); expect(response.data).toBeDefined(); - const data = response.data as any; + const data = response.data as DiagnosticResponse; // Verify all required fields const requiredFields = [ diff --git a/tests/integration/n8n-api/system/health-check.test.ts b/tests/integration/n8n-api/system/health-check.test.ts index f8d460f..9fe4244 100644 --- a/tests/integration/n8n-api/system/health-check.test.ts +++ b/tests/integration/n8n-api/system/health-check.test.ts @@ -9,6 +9,7 @@ import { describe, it, expect, beforeEach } from 'vitest'; import { createMcpContext } from '../utils/mcp-context'; import { InstanceContext } from '../../../../src/types/instance-context'; import { handleHealthCheck } from '../../../../src/mcp/handlers-n8n-manager'; +import { HealthCheckResponse } from '../utils/response-types'; describe('Integration: handleHealthCheck', () => { let mcpContext: InstanceContext; @@ -28,7 +29,7 @@ describe('Integration: handleHealthCheck', () => { expect(response.success).toBe(true); expect(response.data).toBeDefined(); - const data = response.data as any; + const data = response.data as HealthCheckResponse; // Verify required fields expect(data).toHaveProperty('status'); @@ -53,7 +54,7 @@ describe('Integration: handleHealthCheck', () => { const response = await handleHealthCheck(mcpContext); expect(response.success).toBe(true); - const data = response.data as any; + const data = response.data as HealthCheckResponse; // Check for feature information // Note: Features may vary by n8n instance configuration @@ -89,7 +90,7 @@ describe('Integration: handleHealthCheck', () => { expect(response.success).toBe(true); expect(response.data).toBeDefined(); - const data = response.data as any; + const data = response.data as HealthCheckResponse; // Verify all expected fields are present const expectedFields = ['status', 'apiUrl', 'mcpVersion']; diff --git a/tests/integration/n8n-api/system/list-tools.test.ts b/tests/integration/n8n-api/system/list-tools.test.ts index 1e37726..38594f7 100644 --- a/tests/integration/n8n-api/system/list-tools.test.ts +++ b/tests/integration/n8n-api/system/list-tools.test.ts @@ -9,6 +9,7 @@ import { describe, it, expect, beforeEach } from 'vitest'; import { createMcpContext } from '../utils/mcp-context'; import { InstanceContext } from '../../../../src/types/instance-context'; import { handleListAvailableTools } from '../../../../src/mcp/handlers-n8n-manager'; +import { ListToolsResponse } from '../utils/response-types'; describe('Integration: handleListAvailableTools', () => { let mcpContext: InstanceContext; @@ -28,7 +29,7 @@ describe('Integration: handleListAvailableTools', () => { expect(response.success).toBe(true); expect(response.data).toBeDefined(); - const data = response.data as any; + const data = response.data as ListToolsResponse; // Verify tools array exists expect(data).toHaveProperty('tools'); @@ -42,14 +43,14 @@ describe('Integration: handleListAvailableTools', () => { expect(categories).toContain('System'); // Verify each category has tools - data.tools.forEach((category: any) => { + data.tools.forEach(category => { expect(category).toHaveProperty('category'); expect(category).toHaveProperty('tools'); expect(Array.isArray(category.tools)).toBe(true); expect(category.tools.length).toBeGreaterThan(0); // Verify each tool has required fields - category.tools.forEach((tool: any) => { + category.tools.forEach(tool => { expect(tool).toHaveProperty('name'); expect(tool).toHaveProperty('description'); expect(typeof tool.name).toBe('string'); @@ -62,7 +63,7 @@ describe('Integration: handleListAvailableTools', () => { const response = await handleListAvailableTools(mcpContext); expect(response.success).toBe(true); - const data = response.data as any; + const data = response.data as ListToolsResponse; // Verify configuration status expect(data).toHaveProperty('apiConfigured'); @@ -85,7 +86,7 @@ describe('Integration: handleListAvailableTools', () => { const response = await handleListAvailableTools(mcpContext); expect(response.success).toBe(true); - const data = response.data as any; + const data = response.data as ListToolsResponse; // Verify limitations are documented expect(data).toHaveProperty('limitations'); @@ -93,7 +94,7 @@ describe('Integration: handleListAvailableTools', () => { expect(data.limitations.length).toBeGreaterThan(0); // Verify limitations are informative strings - data.limitations.forEach((limitation: string) => { + data.limitations.forEach(limitation => { expect(typeof limitation).toBe('string'); expect(limitation.length).toBeGreaterThan(0); }); @@ -112,12 +113,12 @@ describe('Integration: handleListAvailableTools', () => { describe('Workflow Management Tools', () => { it('should include all workflow management tools', async () => { const response = await handleListAvailableTools(mcpContext); - const data = response.data as any; + const data = response.data as ListToolsResponse; - const workflowCategory = data.tools.find((cat: any) => cat.category === 'Workflow Management'); + const workflowCategory = data.tools.find(cat => cat.category === 'Workflow Management'); expect(workflowCategory).toBeDefined(); - const toolNames = workflowCategory.tools.map((t: any) => t.name); + const toolNames = workflowCategory!.tools.map(t => t.name); // Core workflow tools expect(toolNames).toContain('n8n_create_workflow'); @@ -142,12 +143,12 @@ describe('Integration: handleListAvailableTools', () => { describe('Execution Management Tools', () => { it('should include all execution management tools', async () => { const response = await handleListAvailableTools(mcpContext); - const data = response.data as any; + const data = response.data as ListToolsResponse; - const executionCategory = data.tools.find((cat: any) => cat.category === 'Execution Management'); + const executionCategory = data.tools.find(cat => cat.category === 'Execution Management'); expect(executionCategory).toBeDefined(); - const toolNames = executionCategory.tools.map((t: any) => t.name); + const toolNames = executionCategory!.tools.map(t => t.name); expect(toolNames).toContain('n8n_trigger_webhook_workflow'); expect(toolNames).toContain('n8n_get_execution'); @@ -163,12 +164,12 @@ describe('Integration: handleListAvailableTools', () => { describe('System Tools', () => { it('should include system tools', async () => { const response = await handleListAvailableTools(mcpContext); - const data = response.data as any; + const data = response.data as ListToolsResponse; - const systemCategory = data.tools.find((cat: any) => cat.category === 'System'); + const systemCategory = data.tools.find(cat => cat.category === 'System'); expect(systemCategory).toBeDefined(); - const toolNames = systemCategory.tools.map((t: any) => t.name); + const toolNames = systemCategory!.tools.map(t => t.name); expect(toolNames).toContain('n8n_health_check'); expect(toolNames).toContain('n8n_list_available_tools'); @@ -186,7 +187,7 @@ describe('Integration: handleListAvailableTools', () => { expect(response.success).toBe(true); expect(response.data).toBeDefined(); - const data = response.data as any; + const data = response.data as ListToolsResponse; // Verify all required fields expect(data).toHaveProperty('tools'); diff --git a/tests/integration/n8n-api/utils/response-types.ts b/tests/integration/n8n-api/utils/response-types.ts new file mode 100644 index 0000000..7e64395 --- /dev/null +++ b/tests/integration/n8n-api/utils/response-types.ts @@ -0,0 +1,202 @@ +/** + * TypeScript interfaces for n8n API and MCP handler responses + * Used in integration tests to provide type safety + */ + +// ====================================================================== +// System Tool Response Types +// ====================================================================== + +export interface HealthCheckResponse { + status: string; + instanceId?: string; + n8nVersion?: string; + features?: Record; + apiUrl: string; + mcpVersion: string; + supportedN8nVersion?: string; + versionNote?: string; + [key: string]: any; // Allow dynamic property access for optional field checks +} + +export interface ToolDefinition { + name: string; + description: string; +} + +export interface ToolCategory { + category: string; + tools: ToolDefinition[]; +} + +export interface ApiConfiguration { + apiUrl: string; + timeout: number; + maxRetries: number; +} + +export interface ListToolsResponse { + tools: ToolCategory[]; + apiConfigured: boolean; + configuration?: ApiConfiguration | null; + limitations: string[]; +} + +export interface ApiStatus { + configured: boolean; + connected: boolean; + error?: string | null; + version?: string | null; +} + +export interface ToolsAvailability { + documentationTools: { + count: number; + enabled: boolean; + description: string; + }; + managementTools: { + count: number; + enabled: boolean; + description: string; + }; + totalAvailable: number; +} + +export interface DebugInfo { + processEnv: string[]; + nodeVersion: string; + platform: string; + workingDirectory: string; +} + +export interface DiagnosticResponse { + timestamp: string; + environment: { + N8N_API_URL: string | null; + N8N_API_KEY: string | null; + NODE_ENV: string; + MCP_MODE: string; + }; + apiConfiguration: { + configured: boolean; + status: ApiStatus; + config?: { + baseUrl: string; + timeout: number; + maxRetries: number; + } | null; + }; + toolsAvailability: ToolsAvailability; + troubleshooting: { + steps: string[]; + documentation: string; + }; + debug?: DebugInfo; + [key: string]: any; // Allow dynamic property access for optional field checks +} + +// ====================================================================== +// Execution Response Types +// ====================================================================== + +export interface ExecutionData { + id: string; + status?: 'success' | 'error' | 'running' | 'waiting'; + mode?: string; + startedAt?: string; + stoppedAt?: string; + workflowId?: string; + data?: any; +} + +export interface ListExecutionsResponse { + executions: ExecutionData[]; + returned: number; + nextCursor?: string; + hasMore: boolean; + _note?: string; +} + +// ====================================================================== +// Workflow Response Types +// ====================================================================== + +export interface WorkflowNode { + id: string; + name: string; + type: string; + typeVersion: number; + position: [number, number]; + parameters: Record; + credentials?: Record; + disabled?: boolean; +} + +export interface WorkflowConnections { + [key: string]: any; +} + +export interface WorkflowData { + id: string; + name: string; + active: boolean; + nodes: WorkflowNode[]; + connections: WorkflowConnections; + settings?: Record; + staticData?: Record; + tags?: string[]; + versionId?: string; + createdAt?: string; + updatedAt?: string; +} + +export interface ValidationError { + nodeId?: string; + nodeName?: string; + field?: string; + message: string; + type?: string; +} + +export interface ValidationWarning { + nodeId?: string; + nodeName?: string; + message: string; + type?: string; +} + +export interface ValidateWorkflowResponse { + valid: boolean; + errors?: ValidationError[]; + warnings?: ValidationWarning[]; + errorCount?: number; + warningCount?: number; + summary?: string; +} + +export interface AutofixChange { + nodeId: string; + nodeName: string; + field: string; + oldValue: any; + newValue: any; + reason: string; +} + +export interface AutofixSuggestion { + fixType: string; + nodeId: string; + nodeName: string; + description: string; + confidence: 'high' | 'medium' | 'low'; + changes: AutofixChange[]; +} + +export interface AutofixResponse { + appliedFixes?: number; + suggestions?: AutofixSuggestion[]; + workflow?: WorkflowData; + summary?: string; + preview?: boolean; +}