Files
n8n-mcp/docs/local/integration-testing-plan.md
czlonkowski 9e1a4129c0 feat(tests): implement Phase 2 integration testing - workflow creation tests
Implements comprehensive workflow creation tests against real n8n instance
with 15 test scenarios covering P0 bugs, base nodes, advanced features,
error scenarios, and edge cases.

Key Changes:
- Added 15 workflow creation test scenarios in create-workflow.test.ts
- Fixed critical MSW interference with real API calls
- Fixed environment loading priority (.env before test defaults)
- Implemented multi-level cleanup with webhook workflow preservation
- Migrated from webhook IDs to webhook URLs configuration
- Added TypeScript type safety fixes (26 errors resolved)
- Updated test names to reflect actual n8n API behavior

Bug Fixes:
- Removed MSW from integration test setup (was blocking real API calls)
- Fixed .env loading order to preserve real credentials over test defaults
- Added type guards for undefined workflow IDs
- Fixed position arrays to use proper tuple types [number, number]
- Added literal types for executionOrder and settings values

Test Coverage:
- P0: Critical bug verification (FULL vs SHORT node type format)
- P1: Base n8n nodes (webhook, HTTP, langchain, multi-node)
- P2: Advanced features (connections, settings, expressions, error handling)
- Error scenarios (documents actual n8n API validation behavior)
- Edge cases (minimal workflows, empty connections, no settings)

Technical Improvements:
- Cleanup strategy preserves pre-activated webhook workflows
- Single webhook URL accepts all HTTP methods (GET, POST, PUT, DELETE)
- Environment-aware credential loading with validation
- Comprehensive test context for resource tracking

All 15 tests passing 
TypeScript: 0 errors 

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-04 09:30:43 +02:00

31 KiB
Raw Blame History

Comprehensive Integration Testing Plan

Status

Phase 1: Foundation COMPLETE (October 3, 2025)

  • All utility files created and tested
  • Webhook workflows created on https://n8n-test.n8n-mcp.com
  • GitHub secrets configured
  • Critical fix: Updated credentials to use webhook URLs instead of IDs
  • Environment loading fixed to support real n8n API integration tests

Phase 2: Workflow Creation Tests COMPLETE (October 3, 2025)

  • 15 test scenarios implemented and passing
  • P0 bug verification confirmed (FULL node type format)
  • All test categories covered: base nodes, advanced features, error scenarios, edge cases
  • Documented actual n8n API behavior (validation at execution time, not creation time)
  • Test file: tests/integration/n8n-api/workflows/create-workflow.test.ts (484 lines)

Next Phase: Phase 3 - Workflow Retrieval Tests


Overview

Transform the test suite to test all 17 n8n API handlers against a real n8n instance instead of mocks. This plan ensures 100% coverage of every tool, operation, and parameter combination to prevent bugs like the P0 workflow creation issue from slipping through.

Critical Requirements

  1. Credentials:

    • Local development: Read from .env file
    • CI/GitHub Actions: Use GitHub secrets (N8N_URL, N8N_API_KEY)
  2. Pre-activated Webhook Workflows:

    • n8n API doesn't support workflow activation via API
    • Need pre-created, activated workflows for webhook testing
    • Store webhook URLs (not workflow IDs) in .env:
      • N8N_TEST_WEBHOOK_GET_URL - GET method webhook URL
      • N8N_TEST_WEBHOOK_POST_URL - POST method webhook URL
      • N8N_TEST_WEBHOOK_PUT_URL - PUT method webhook URL
      • N8N_TEST_WEBHOOK_DELETE_URL - DELETE method webhook URL
    • Rationale: Webhook URLs are what the n8n_trigger_webhook_workflow tool needs. Workflow IDs are only for workflow management tests (which create workflows dynamically during test execution).
  3. 100% Coverage Goal: Test EVERY tool, EVERY operation, EVERY parameter combination


Complete Test Coverage Matrix

Total Test Scenarios: ~150+

Workflow Management (10 handlers)

1. handleCreateWorkflow - 10+ scenarios

  • Create workflow with base nodes (webhook, httpRequest, set)
  • Create workflow with langchain nodes (agent, aiChain)
  • Invalid node types (error handling)
  • Complex multi-node workflows
  • Complex connection patterns
  • P0 Bug Verification: SHORT vs FULL node type handling
  • Missing required parameters
  • Duplicate node names
  • Invalid connection references
  • Settings variations

2. handleGetWorkflow - 3 scenarios

  • Successful retrieval
  • Not found (invalid ID)
  • Malformed ID

3. handleGetWorkflowDetails - 4 scenarios

  • Basic workflow
  • Workflow with metadata
  • Workflow with version history
  • Workflow with execution stats

4. handleGetWorkflowStructure - 2 scenarios

  • Simple workflow
  • Complex workflow (verify no parameter data)

5. handleGetWorkflowMinimal - 2 scenarios

  • Active workflow
  • Inactive workflow

6. handleUpdateWorkflow - 8+ scenarios

  • Full workflow replacement
  • Update nodes
  • Update connections
  • Update settings
  • Update tags
  • Validation errors
  • Concurrent update conflicts
  • Large workflow updates

7. handleUpdatePartialWorkflow - 30+ scenarios (15 operations × 2 paths)

Node Operations (12 scenarios):

  • addNode: Success, duplicate name, invalid type, missing position
  • removeNode: By ID, by name, not found, with connection cleanup
  • updateNode: By ID, by name, invalid updates, nested parameter updates
  • moveNode: Valid position, boundary positions
  • enableNode: Success, already enabled
  • disableNode: Success, already disabled

Connection Operations (10 scenarios):

  • addConnection: Default ports, custom ports, invalid nodes
  • removeConnection: Success, not found, with ignoreErrors
  • updateConnection: Change ports, change indices
  • cleanStaleConnections: Dry run, actual cleanup
  • replaceConnections: Full replacement, validation

Metadata Operations (8 scenarios):

  • updateSettings: Timezone, execution order, error workflow
  • updateName: Valid, duplicate, empty
  • addTag: New tag, existing tag
  • removeTag: Existing, non-existing

8. handleDeleteWorkflow - 3 scenarios

  • Successful deletion
  • Not found
  • Verify cleanup (workflow actually deleted)

9. handleListWorkflows - 12+ scenarios

  • No filters (all workflows)
  • Filter by active status (true/false)
  • Filter by tags (single, multiple)
  • Filter by projectId (enterprise feature)
  • Pagination: first page, next page, last page
  • Pagination: cursor handling
  • Exclude pinned data
  • Limit variations (1, 50, 100)
  • Empty results
  • Sort order verification

10. handleValidateWorkflow - 16 scenarios (4 profiles × 4 validation types)

Validation Profiles:

  • strict: All validations enabled, strictest rules
  • runtime: Production-ready validation
  • ai-friendly: Relaxed rules for AI-generated workflows
  • minimal: Basic structure validation only

Validation Types (for each profile):

  • All validations enabled (default)
  • Nodes only (validateNodes: true, others false)
  • Connections only (validateConnections: true, others false)
  • Expressions only (validateExpressions: true, others false)

11. handleAutofixWorkflow - 20+ scenarios

Fix Types (5):

  • expression-format: Fix {{}} syntax issues
  • typeversion-correction: Fix outdated typeVersion
  • error-output-config: Fix error output configuration
  • node-type-correction: Fix incorrect node types
  • webhook-missing-path: Add missing webhook paths

Confidence Levels (3):

  • high: Only apply high-confidence fixes
  • medium: Apply high + medium confidence fixes
  • low: Apply all fixes

Test Matrix:

  • Each fix type with preview mode (applyFixes: false)
  • Each fix type with apply mode (applyFixes: true)
  • Confidence threshold filtering
  • maxFixes parameter limiting
  • Multiple fix types in single workflow
  • No fixes available scenario

Execution Management (4 handlers)

12. handleTriggerWebhookWorkflow - 16+ scenarios

HTTP Methods (4):

  • GET: Query parameters, no data
  • POST: JSON body, form data, headers
  • PUT: Update data, custom headers
  • DELETE: Query parameters, headers

Scenarios per method:

  • Basic trigger (no data)
  • With request data
  • With custom headers
  • Wait for response (true/false)
  • Workflow not found
  • Invalid webhook URL

13. handleGetExecution - 20+ scenarios

Execution Modes (4):

  • preview: Structure & counts only (no data)
  • summary: 2 samples per node (default)
  • filtered: Custom limits and node filters
  • full: Complete execution data

Scenarios per mode:

  • Successful execution
  • Failed execution
  • Running execution
  • With input data (includeInputData: true)
  • Node filters (nodeNames: ['Node1', 'Node2'])
  • Item limits (itemsLimit: 0, 2, 5, -1)
  • Not found

14. handleListExecutions - 10+ scenarios

  • No filters (all executions)
  • Filter by workflowId
  • Filter by status (success, error, waiting)
  • Filter by projectId
  • Pagination: first page, next page, last page
  • Include execution data (includeData: true/false)
  • Limit variations (1, 50, 100)
  • Empty results

15. handleDeleteExecution - 3 scenarios

  • Successful deletion
  • Not found
  • Verify cleanup

System/Utility (3 handlers)

16. handleHealthCheck - 2 scenarios

  • API available
  • Feature availability check

17. handleListAvailableTools - 1 scenario

  • List all tools

18. handleDiagnostic - 3 scenarios

  • Basic diagnostic
  • Verbose mode (verbose: true)
  • Configuration display

Implementation Phases

Phase 1: Foundation (Branch: feat/integration-tests-foundation)

1.1 Environment Configuration

Update .env.example:

# ========================================
# INTEGRATION TESTING CONFIGURATION
# ========================================

# n8n API Configuration for Integration Tests
N8N_API_URL=http://localhost:5678
N8N_API_KEY=your-api-key-here

# Pre-activated Webhook URLs for Testing
# Create these workflows manually in n8n and activate them
# Store the full webhook URLs (not workflow IDs)
N8N_TEST_WEBHOOK_GET_URL=https://n8n-test.n8n-mcp.com/webhook/mcp-test-get
N8N_TEST_WEBHOOK_POST_URL=https://n8n-test.n8n-mcp.com/webhook/mcp-test-post
N8N_TEST_WEBHOOK_PUT_URL=https://n8n-test.n8n-mcp.com/webhook/mcp-test-put
N8N_TEST_WEBHOOK_DELETE_URL=https://n8n-test.n8n-mcp.com/webhook/mcp-test-delete

# Test Configuration
N8N_TEST_CLEANUP_ENABLED=true           # Enable automatic cleanup
N8N_TEST_TAG=mcp-integration-test       # Tag for test workflows
N8N_TEST_NAME_PREFIX=[MCP-TEST]         # Name prefix for test workflows

GitHub Secrets (for CI):

  • N8N_URL: n8n instance URL (e.g., https://n8n-test.n8n-mcp.com)
  • N8N_API_KEY: n8n API key (JWT token from n8n Settings > API)
  • N8N_TEST_WEBHOOK_GET_URL: Pre-activated GET webhook URL
  • N8N_TEST_WEBHOOK_POST_URL: Pre-activated POST webhook URL
  • N8N_TEST_WEBHOOK_PUT_URL: Pre-activated PUT webhook URL
  • N8N_TEST_WEBHOOK_DELETE_URL: Pre-activated DELETE webhook URL

Note: Webhook URLs can be stored as repository secrets (not environment secrets) since they don't grant API access. The real secret is N8N_API_KEY.

1.2 Directory Structure

tests/integration/n8n-api/
├── workflows/
│   ├── create-workflow.test.ts          (10+ scenarios)
│   ├── get-workflow.test.ts             (3 scenarios)
│   ├── get-workflow-details.test.ts     (4 scenarios)
│   ├── get-workflow-structure.test.ts   (2 scenarios)
│   ├── get-workflow-minimal.test.ts     (2 scenarios)
│   ├── update-workflow.test.ts          (8+ scenarios)
│   ├── update-partial-workflow.test.ts  (30+ scenarios - 15 operations)
│   ├── delete-workflow.test.ts          (3 scenarios)
│   ├── list-workflows.test.ts           (12+ scenarios)
│   ├── validate-workflow.test.ts        (16 scenarios - 4 profiles × 4 types)
│   └── autofix-workflow.test.ts         (20+ scenarios - 5 types × modes)
├── executions/
│   ├── trigger-webhook.test.ts          (16+ scenarios - 4 methods)
│   ├── get-execution.test.ts            (20+ scenarios - 4 modes)
│   ├── list-executions.test.ts          (10+ scenarios)
│   └── delete-execution.test.ts         (3 scenarios)
├── system/
│   ├── health-check.test.ts             (2 scenarios)
│   ├── list-tools.test.ts               (1 scenario)
│   └── diagnostic.test.ts               (3 scenarios)
└── utils/
    ├── credentials.ts                   # Environment-aware credential loader
    ├── n8n-client.ts                    # Pre-configured API client
    ├── cleanup-helpers.ts               # Multi-level cleanup
    ├── test-context.ts                  # Resource tracking
    ├── fixtures.ts                      # Reusable workflow templates
    ├── factories.ts                     # Test data generators
    └── webhook-workflows.ts             # Webhook workflow configurations

1.3 Core Utilities

credentials.ts - Environment-aware credential loader:

import dotenv from 'dotenv';

dotenv.config();

export interface N8nTestCredentials {
  url: string;
  apiKey: string;
  webhookUrls: {
    get: string;
    post: string;
    put: string;
    delete: string;
  };
  cleanup: {
    enabled: boolean;
    tag: string;
    namePrefix: string;
  };
}

export function getN8nCredentials(): N8nTestCredentials {
  if (process.env.CI) {
    // CI: Use GitHub secrets
    const url = process.env.N8N_URL;
    const apiKey = process.env.N8N_API_KEY;

    if (!url || !apiKey) {
      throw new Error(
        'Missing required CI credentials:\n' +
        `  N8N_URL: ${url ? 'set' : 'MISSING'}\n` +
        `  N8N_API_KEY: ${apiKey ? 'set' : 'MISSING'}\n` +
        'Please configure GitHub secrets for integration tests.'
      );
    }

    return {
      url,
      apiKey,
      webhookUrls: {
        get: process.env.N8N_TEST_WEBHOOK_GET_URL || '',
        post: process.env.N8N_TEST_WEBHOOK_POST_URL || '',
        put: process.env.N8N_TEST_WEBHOOK_PUT_URL || '',
        delete: process.env.N8N_TEST_WEBHOOK_DELETE_URL || ''
      },
      cleanup: {
        enabled: true,
        tag: 'mcp-integration-test',
        namePrefix: '[MCP-TEST]'
      }
    };
  } else {
    // Local: Use .env file
    const url = process.env.N8N_API_URL;
    const apiKey = process.env.N8N_API_KEY;

    if (!url || !apiKey) {
      throw new Error(
        'Missing required credentials in .env:\n' +
        `  N8N_API_URL: ${url ? 'set' : 'MISSING'}\n` +
        `  N8N_API_KEY: ${apiKey ? 'set' : 'MISSING'}\n\n` +
        'Please add these to your .env file.\n' +
        'See .env.example for configuration details.'
      );
    }

    return {
      url,
      apiKey,
      webhookUrls: {
        get: process.env.N8N_TEST_WEBHOOK_GET_URL || '',
        post: process.env.N8N_TEST_WEBHOOK_POST_URL || '',
        put: process.env.N8N_TEST_WEBHOOK_PUT_URL || '',
        delete: process.env.N8N_TEST_WEBHOOK_DELETE_URL || ''
      },
      cleanup: {
        enabled: process.env.N8N_TEST_CLEANUP_ENABLED !== 'false',
        tag: process.env.N8N_TEST_TAG || 'mcp-integration-test',
        namePrefix: process.env.N8N_TEST_NAME_PREFIX || '[MCP-TEST]'
      }
    };
  }
}

export function validateCredentials(creds: N8nTestCredentials): void {
  if (!creds.url) throw new Error('N8N_API_URL is required');
  if (!creds.apiKey) throw new Error('N8N_API_KEY is required');
}

export function validateWebhookUrls(creds: N8nTestCredentials): void {
  const missing: string[] = [];
  if (!creds.webhookUrls.get) missing.push('GET');
  if (!creds.webhookUrls.post) missing.push('POST');
  if (!creds.webhookUrls.put) missing.push('PUT');
  if (!creds.webhookUrls.delete) missing.push('DELETE');

  if (missing.length > 0) {
    throw new Error(
      `Missing webhook URLs for HTTP methods: ${missing.join(', ')}\n` +
      `Please create and activate webhook workflows, then set:\n` +
      missing.map(m => `  N8N_TEST_WEBHOOK_${m}_URL`).join('\n')
    );
  }
}

n8n-client.ts - Pre-configured API client wrapper:

import { N8nApiClient } from '../../../src/services/n8n-api-client';
import { getN8nCredentials } from './credentials';

let client: N8nApiClient | null = null;

export function getTestN8nClient(): N8nApiClient {
  if (!client) {
    const creds = getN8nCredentials();
    client = new N8nApiClient(creds.url, creds.apiKey);
  }
  return client;
}

export function resetTestN8nClient(): void {
  client = null;
}

test-context.ts - Resource tracking for cleanup:

import { getN8nCredentials } from './credentials';

export interface TestContext {
  workflowIds: string[];
  executionIds: string[];
  cleanup: () => Promise<void>;
}

export function createTestContext(): TestContext {
  const context: TestContext = {
    workflowIds: [],
    executionIds: [],
    cleanup: async () => {
      const creds = getN8nCredentials();
      if (!creds.cleanup.enabled) return;

      const client = getTestN8nClient();

      // Delete executions first
      for (const id of context.executionIds) {
        try {
          await client.deleteExecution(id);
        } catch (error) {
          console.warn(`Failed to delete execution ${id}:`, error);
        }
      }

      // Then delete workflows
      for (const id of context.workflowIds) {
        try {
          await client.deleteWorkflow(id);
        } catch (error) {
          console.warn(`Failed to delete workflow ${id}:`, error);
        }
      }

      context.workflowIds = [];
      context.executionIds = [];
    }
  };

  return context;
}

cleanup-helpers.ts - Multi-level cleanup strategies:

import { N8nApiClient } from '../../../src/services/n8n-api-client';
import { getN8nCredentials, getTestN8nClient } from './credentials';

/**
 * Clean up orphaned test workflows
 * Run this periodically in CI to clean up failed test runs
 */
export async function cleanupOrphanedWorkflows(): Promise<void> {
  const creds = getN8nCredentials();
  const client = getTestN8nClient();

  let allWorkflows: any[] = [];
  let cursor: string | undefined;

  // Fetch all workflows with pagination
  do {
    const response = await client.listWorkflows({ cursor, limit: 100 });
    allWorkflows.push(...response.data);
    cursor = response.nextCursor;
  } while (cursor);

  // Find test workflows
  const testWorkflows = allWorkflows.filter(w =>
    w.tags?.includes(creds.cleanup.tag) ||
    w.name?.startsWith(creds.cleanup.namePrefix)
  );

  console.log(`Found ${testWorkflows.length} orphaned test workflows`);

  // Delete them
  for (const workflow of testWorkflows) {
    try {
      await client.deleteWorkflow(workflow.id);
      console.log(`Deleted orphaned workflow: ${workflow.name} (${workflow.id})`);
    } catch (error) {
      console.warn(`Failed to delete workflow ${workflow.id}:`, error);
    }
  }
}

/**
 * Clean up old executions (older than 24 hours)
 */
export async function cleanupOldExecutions(): Promise<void> {
  const client = getTestN8nClient();

  let allExecutions: any[] = [];
  let cursor: string | undefined;

  // Fetch all executions
  do {
    const response = await client.listExecutions({ cursor, limit: 100 });
    allExecutions.push(...response.data);
    cursor = response.nextCursor;
  } while (cursor);

  const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000;
  const oldExecutions = allExecutions.filter(e =>
    new Date(e.startedAt).getTime() < oneDayAgo
  );

  console.log(`Found ${oldExecutions.length} old executions`);

  for (const execution of oldExecutions) {
    try {
      await client.deleteExecution(execution.id);
    } catch (error) {
      console.warn(`Failed to delete execution ${execution.id}:`, error);
    }
  }
}

fixtures.ts - Reusable workflow templates:

import { Workflow } from '../../../src/types/n8n-api';

export const SIMPLE_WEBHOOK_WORKFLOW: Partial<Workflow> = {
  name: '[MCP-TEST] Simple Webhook',
  nodes: [
    {
      id: 'webhook-1',
      name: 'Webhook',
      type: 'n8n-nodes-base.webhook',
      typeVersion: 2,
      position: [250, 300],
      parameters: {
        httpMethod: 'GET',
        path: 'test-webhook'
      }
    }
  ],
  connections: {}
};

export const SIMPLE_HTTP_WORKFLOW: Partial<Workflow> = {
  name: '[MCP-TEST] Simple HTTP Request',
  nodes: [
    {
      id: 'webhook-1',
      name: 'Webhook',
      type: 'n8n-nodes-base.webhook',
      typeVersion: 2,
      position: [250, 300],
      parameters: {
        httpMethod: 'GET',
        path: 'trigger'
      }
    },
    {
      id: 'http-1',
      name: 'HTTP Request',
      type: 'n8n-nodes-base.httpRequest',
      typeVersion: 4.2,
      position: [450, 300],
      parameters: {
        url: 'https://httpbin.org/get',
        method: 'GET'
      }
    }
  ],
  connections: {
    Webhook: {
      main: [[{ node: 'HTTP Request', type: 'main', index: 0 }]]
    }
  }
};

// Add more fixtures for complex workflows

webhook-workflows.ts - Webhook workflow setup guide:

/**
 * Guide for setting up webhook workflows manually in n8n
 *
 * These workflows must be created manually and activated because
 * n8n API doesn't support workflow activation.
 *
 * For each HTTP method, create a workflow with:
 * 1. Single Webhook node
 * 2. Configured for the specific HTTP method
 * 3. Unique webhook path
 * 4. Activated in n8n UI
 * 5. Workflow ID added to .env
 */

export const WEBHOOK_WORKFLOW_CONFIGS = {
  GET: {
    name: '[MCP-TEST] Webhook GET',
    description: 'Pre-activated webhook for GET method testing',
    nodes: [
      {
        name: 'Webhook',
        type: 'n8n-nodes-base.webhook',
        typeVersion: 2,
        parameters: {
          httpMethod: 'GET',
          path: 'mcp-test-get',
          responseMode: 'lastNode'
        }
      }
    ]
  },
  POST: {
    name: '[MCP-TEST] Webhook POST',
    description: 'Pre-activated webhook for POST method testing',
    nodes: [
      {
        name: 'Webhook',
        type: 'n8n-nodes-base.webhook',
        typeVersion: 2,
        parameters: {
          httpMethod: 'POST',
          path: 'mcp-test-post',
          responseMode: 'lastNode'
        }
      }
    ]
  },
  PUT: {
    name: '[MCP-TEST] Webhook PUT',
    description: 'Pre-activated webhook for PUT method testing',
    nodes: [
      {
        name: 'Webhook',
        type: 'n8n-nodes-base.webhook',
        typeVersion: 2,
        parameters: {
          httpMethod: 'PUT',
          path: 'mcp-test-put',
          responseMode: 'lastNode'
        }
      }
    ]
  },
  DELETE: {
    name: '[MCP-TEST] Webhook DELETE',
    description: 'Pre-activated webhook for DELETE method testing',
    nodes: [
      {
        name: 'Webhook',
        type: 'n8n-nodes-base.webhook',
        typeVersion: 2,
        parameters: {
          httpMethod: 'DELETE',
          path: 'mcp-test-delete',
          responseMode: 'lastNode'
        }
      }
    ]
  }
};

export function printSetupInstructions(): void {
  console.log(`
╔════════════════════════════════════════════════════════════════╗
║  WEBHOOK WORKFLOW SETUP REQUIRED                               ║
╠════════════════════════════════════════════════════════════════╣
║                                                                ║
║  Integration tests require 4 pre-activated webhook workflows:  ║
║                                                                ║
║  1. Create workflows manually in n8n UI                        ║
║  2. Use the configurations shown below                         ║
║  3. ACTIVATE each workflow in n8n UI                           ║
║  4. Copy workflow IDs to .env file                             ║
║                                                                ║
╚════════════════════════════════════════════════════════════════╝

Required workflows:
`);

  Object.entries(WEBHOOK_WORKFLOW_CONFIGS).forEach(([method, config]) => {
    console.log(`
${method} Method:
  Name: ${config.name}
  Path: ${config.nodes[0].parameters.path}
  .env variable: N8N_TEST_WEBHOOK_${method}_ID
`);
  });
}

Phase 2: Workflow Creation Tests (P0)

Branch: feat/integration-tests-workflow-creation

File: tests/integration/n8n-api/workflows/create-workflow.test.ts

10+ Test Scenarios:

  1. Create workflow with base webhook node (verify P0 bug fix)
  2. Create workflow with base HTTP request node
  3. Create workflow with langchain agent node
  4. Create complex multi-node workflow
  5. Create workflow with complex connections
  6. Error: Invalid node type
  7. Error: Missing required parameters
  8. Error: Duplicate node names
  9. Error: Invalid connection references
  10. Create workflow with custom settings

Phase 3: Workflow Retrieval Tests (P1)

Branch: feat/integration-tests-workflow-retrieval

Files:

  • get-workflow.test.ts (3 scenarios)
  • get-workflow-details.test.ts (4 scenarios)
  • get-workflow-structure.test.ts (2 scenarios)
  • get-workflow-minimal.test.ts (2 scenarios)

Phase 4: Workflow Update Tests (P1)

Branch: feat/integration-tests-workflow-updates

Files:

  • update-workflow.test.ts (8+ scenarios)
  • update-partial-workflow.test.ts (30+ scenarios covering all 15 operations)

Phase 5: Workflow Management Tests (P2)

Branch: feat/integration-tests-workflow-management

Files:

  • delete-workflow.test.ts (3 scenarios)
  • list-workflows.test.ts (12+ scenarios with all filters and pagination)

Phase 6: Validation & Autofix Tests (P2)

Branch: feat/integration-tests-validation

Files:

  • validate-workflow.test.ts (16 scenarios: 4 profiles × 4 validation types)
  • autofix-workflow.test.ts (20+ scenarios: 5 fix types × confidence levels)

Phase 7: Execution Management Tests (P2)

Branch: feat/integration-tests-executions

Files:

  • trigger-webhook.test.ts (16+ scenarios: 4 HTTP methods × variations)
  • get-execution.test.ts (20+ scenarios: 4 modes × filters)
  • list-executions.test.ts (10+ scenarios)
  • delete-execution.test.ts (3 scenarios)

Special Considerations for Webhook Testing:

  • Use pre-activated workflows from .env
  • Each HTTP method uses a different workflow ID
  • Test both successful triggers and error cases
  • Verify response data for synchronous executions

Phase 8: System Tools Tests (P3)

Branch: feat/integration-tests-system

Files:

  • health-check.test.ts (2 scenarios)
  • list-tools.test.ts (1 scenario)
  • diagnostic.test.ts (3 scenarios)

Phase 9: CI/CD Integration

Branch: feat/integration-tests-ci

GitHub Actions Workflow (.github/workflows/integration-tests.yml):

name: Integration Tests

on:
  pull_request:
  push:
    branches: [main]
  schedule:
    - cron: '0 2 * * *'  # Daily at 2 AM
  workflow_dispatch:

jobs:
  integration-tests:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build project
        run: npm run build

      - name: Run integration tests
        env:
          N8N_URL: ${{ secrets.N8N_URL }}
          N8N_API_KEY: ${{ secrets.N8N_API_KEY }}
          N8N_TEST_WEBHOOK_GET_URL: ${{ secrets.N8N_TEST_WEBHOOK_GET_URL }}
          N8N_TEST_WEBHOOK_POST_URL: ${{ secrets.N8N_TEST_WEBHOOK_POST_URL }}
          N8N_TEST_WEBHOOK_PUT_URL: ${{ secrets.N8N_TEST_WEBHOOK_PUT_URL }}
          N8N_TEST_WEBHOOK_DELETE_URL: ${{ secrets.N8N_TEST_WEBHOOK_DELETE_URL }}
          CI: true
        run: npm run test:integration:n8n

      - name: Cleanup orphaned workflows
        if: always()
        env:
          N8N_URL: ${{ secrets.N8N_URL }}
          N8N_API_KEY: ${{ secrets.N8N_API_KEY }}
        run: npm run test:cleanup:orphans

Add npm scripts to package.json:

{
  "scripts": {
    "test:integration:n8n": "vitest run tests/integration/n8n-api",
    "test:cleanup:orphans": "tsx tests/integration/n8n-api/utils/cleanup-orphans.ts"
  }
}

Test Isolation Strategy

Workflow Naming Convention

  • Prefix: [MCP-TEST]
  • Include test name: [MCP-TEST] Create Workflow - Base Nodes
  • Include timestamp for uniqueness: [MCP-TEST] Test Name ${Date.now()}

Workflow Tagging

  • All test workflows tagged with: mcp-integration-test
  • Enables bulk cleanup queries

Cleanup Levels

  1. Test-level: After each test via afterEach hook
  2. Suite-level: After each test file via afterAll hook
  3. CI-level: After CI job completes (always run)
  4. Orphan cleanup: Periodic job to clean up failed test runs

Pre-Test Setup Checklist

Local Development

  1. Install n8n locally or use Docker
  2. Start n8n instance: npx n8n start
  3. Create 4 webhook workflows (GET, POST, PUT, DELETE)
  4. Activate all 4 webhook workflows in n8n UI
  5. Get webhook URLs from the workflow's Webhook node
  6. Copy .env.example to .env
  7. Set N8N_API_URL=<your-n8n-url>
  8. Generate API key in n8n Settings > API
  9. Set N8N_API_KEY=<your-key>
  10. Set all 4 N8N_TEST_WEBHOOK_*_URL variables with full webhook URLs

CI/GitHub Actions ( COMPLETED)

  1. Set up cloud n8n instance: https://n8n-test.n8n-mcp.com
  2. Create 4 webhook workflows (GET, POST, PUT, DELETE)
  3. Activate all 4 webhook workflows
  4. Add GitHub secrets: N8N_URL, N8N_API_KEY
  5. Add webhook URL secrets:
    • N8N_TEST_WEBHOOK_GET_URL=https://n8n-test.n8n-mcp.com/webhook/mcp-test-get
    • N8N_TEST_WEBHOOK_POST_URL=https://n8n-test.n8n-mcp.com/webhook/mcp-test-post
    • N8N_TEST_WEBHOOK_PUT_URL=https://n8n-test.n8n-mcp.com/webhook/mcp-test-put
    • N8N_TEST_WEBHOOK_DELETE_URL=https://n8n-test.n8n-mcp.com/webhook/mcp-test-delete

Success Criteria

Phase 1: Foundation COMPLETE

  • Environment configuration (.env, GitHub secrets)
  • All utility files created (8 files, ~1,520 lines of code)
  • Pre-activated webhook workflows created and tested
  • Cleanup helpers with pagination safety
  • Resource tracking with TestContext
  • Fixtures and factories for test data
  • Documentation updated
  • Environment loading fixed (loads .env before test defaults)
  • Vitest integration config updated (removed MSW for n8n-api tests)

Phase 2: Workflow Creation Tests COMPLETE

  • 15 test scenarios implemented (all passing)
  • P0 bug verification (FULL vs SHORT node type format)
  • Base node tests (webhook, HTTP, langchain, multi-node)
  • Advanced features (connections, settings, expressions, error handling)
  • Error scenarios (4 tests documenting actual API behavior)
  • Edge cases (3 tests for minimal/empty configurations)
  • Test file: 484 lines covering all handleCreateWorkflow scenarios
  • All tests passing on real n8n instance

Overall Project (In Progress)

  • All 17 handlers have integration tests (1 of 17 complete)
  • All operations/parameters covered (15 of 150+ scenarios complete)
  • Tests run successfully locally (Phase 2 verified)
  • Tests run successfully in CI (pending Phase 9)
  • No manual cleanup required (automatic)
  • Test coverage catches P0-level bugs (verified in Phase 2)
  • CI runs on every PR and daily (pending Phase 9)
  • Clear error messages when tests fail
  • Documentation for webhook workflow setup

Timeline Estimate

  • Phase 1 (Foundation): COMPLETE (October 3, 2025)
  • Phase 2 (Workflow Creation): COMPLETE (October 3, 2025)
  • Phase 3 (Retrieval): 1 day
  • Phase 4 (Updates): 2-3 days (15 operations)
  • Phase 5 (Management): 1 day
  • Phase 6 (Validation): 2 days
  • Phase 7 (Executions): 2 days
  • Phase 8 (System): 1 day
  • Phase 9 (CI/CD): 1 day

Total: 2 days complete (~4-6 hours actual), ~12-16 days remaining


Notes

  • Each phase should be developed on a separate branch
  • Phases can be parallelized where dependencies allow
  • Run local tests frequently to catch issues early
  • Document any n8n API quirks discovered during testing

Key Learnings from Phase 2

n8n API Behavior Discoveries

  1. Validation Timing: n8n API accepts workflows with invalid node types and connection references at creation time. Validation only happens at execution time.
  2. Node Type Format: FULL node type format (n8n-nodes-base.*) must be used in API requests. The P0 bug was confirmed fixed.
  3. Missing Parameters: n8n accepts workflows with missing required parameters. They fail during execution, not creation.
  4. Duplicate Names: n8n API handles duplicate node names gracefully (may auto-rename).

Technical Implementation Insights

  1. MSW Interference: Integration tests that need real network requests must NOT load MSW setup. Removed from vitest.config.integration.ts.
  2. Environment Loading: Must load .env file BEFORE test defaults in global setup to preserve real credentials.
  3. Cleanup Safety: TestContext pattern works well for tracking and cleaning up test resources.
  4. Test Isolation: Each test creates unique workflows with timestamps to avoid conflicts.