Files
n8n-mcp/docs/local/integration-testing-plan.md
czlonkowski 2305aaab9e feat: implement integration testing foundation (Phase 1)
Complete implementation of Phase 1 foundation for n8n API integration tests.
Establishes core utilities, fixtures, and infrastructure for testing all 17 n8n API handlers against real n8n instance.

Changes:
- Add integration test environment configuration to .env.example
- Create comprehensive test utilities infrastructure:
  * credentials.ts: Environment-aware credential management (local .env vs CI secrets)
  * n8n-client.ts: Singleton API client wrapper with health checks
  * test-context.ts: Resource tracking and automatic cleanup
  * cleanup-helpers.ts: Multi-level cleanup strategies (orphaned, age-based, tag-based)
  * fixtures.ts: 6 pre-built workflow templates (webhook, HTTP, multi-node, error handling, AI, expressions)
  * factories.ts: Dynamic node/workflow builders with 15+ factory functions
  * webhook-workflows.ts: Webhook workflow configs and setup instructions

- Add npm scripts:
  * test:integration:n8n: Run n8n API integration tests
  * test:cleanup:orphans: Clean up orphaned test resources

- Create cleanup script for CI/manual use

Documentation:
- Add comprehensive integration testing plan (550 lines)
- Add Phase 1 completion summary with lessons learned

Key Features:
- Automatic credential detection (CI vs local)
- Multi-level cleanup (test, suite, CI, orphan)
- 6 workflow fixtures covering common scenarios
- 15+ factory functions for dynamic test data
- Support for 4 HTTP methods (GET, POST, PUT, DELETE) via pre-activated webhook workflows
- TypeScript-first with full type safety
- Comprehensive error handling with helpful messages

Total: ~1,520 lines of production-ready code + 650 lines of documentation

Ready for Phase 2: Workflow creation tests

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-03 13:12:42 +02:00

925 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Comprehensive Integration Testing Plan
## 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 workflow IDs in `.env`:
- `N8N_TEST_WEBHOOK_GET_ID` - Webhook with GET method
- `N8N_TEST_WEBHOOK_POST_ID` - Webhook with POST method
- `N8N_TEST_WEBHOOK_PUT_ID` - Webhook with PUT method
- `N8N_TEST_WEBHOOK_DELETE_ID` - Webhook with DELETE method
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`:**
```bash
# ========================================
# 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 Workflows for Testing
# Create these workflows manually in n8n and activate them
# Each workflow should have a single Webhook node with the specified HTTP method
N8N_TEST_WEBHOOK_GET_ID= # Webhook with GET method
N8N_TEST_WEBHOOK_POST_ID= # Webhook with POST method
N8N_TEST_WEBHOOK_PUT_ID= # Webhook with PUT method
N8N_TEST_WEBHOOK_DELETE_ID= # Webhook with DELETE method
# 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
- `N8N_API_KEY`: n8n API key
- `N8N_TEST_WEBHOOK_GET_ID`: Pre-activated GET webhook workflow ID
- `N8N_TEST_WEBHOOK_POST_ID`: Pre-activated POST webhook workflow ID
- `N8N_TEST_WEBHOOK_PUT_ID`: Pre-activated PUT webhook workflow ID
- `N8N_TEST_WEBHOOK_DELETE_ID`: Pre-activated DELETE webhook workflow ID
#### 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:
```typescript
import dotenv from 'dotenv';
dotenv.config();
export interface N8nTestCredentials {
url: string;
apiKey: string;
webhookWorkflows: {
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
return {
url: process.env.N8N_URL!,
apiKey: process.env.N8N_API_KEY!,
webhookWorkflows: {
get: process.env.N8N_TEST_WEBHOOK_GET_ID!,
post: process.env.N8N_TEST_WEBHOOK_POST_ID!,
put: process.env.N8N_TEST_WEBHOOK_PUT_ID!,
delete: process.env.N8N_TEST_WEBHOOK_DELETE_ID!
},
cleanup: {
enabled: true,
tag: 'mcp-integration-test',
namePrefix: '[MCP-TEST]'
}
};
} else {
// Local: Use .env file
return {
url: process.env.N8N_API_URL!,
apiKey: process.env.N8N_API_KEY!,
webhookWorkflows: {
get: process.env.N8N_TEST_WEBHOOK_GET_ID || '',
post: process.env.N8N_TEST_WEBHOOK_POST_ID || '',
put: process.env.N8N_TEST_WEBHOOK_PUT_ID || '',
delete: process.env.N8N_TEST_WEBHOOK_DELETE_ID || ''
},
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 validateWebhookWorkflows(creds: N8nTestCredentials): void {
const missing: string[] = [];
if (!creds.webhookWorkflows.get) missing.push('GET');
if (!creds.webhookWorkflows.post) missing.push('POST');
if (!creds.webhookWorkflows.put) missing.push('PUT');
if (!creds.webhookWorkflows.delete) missing.push('DELETE');
if (missing.length > 0) {
throw new Error(
`Missing webhook workflow IDs for HTTP methods: ${missing.join(', ')}\n` +
`Please create and activate webhook workflows, then set:\n` +
missing.map(m => ` N8N_TEST_WEBHOOK_${m}_ID`).join('\n')
);
}
}
```
**n8n-client.ts** - Pre-configured API client wrapper:
```typescript
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:
```typescript
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:
```typescript
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:
```typescript
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:
```typescript
/**
* 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`):
```yaml
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_ID: ${{ secrets.N8N_TEST_WEBHOOK_GET_ID }}
N8N_TEST_WEBHOOK_POST_ID: ${{ secrets.N8N_TEST_WEBHOOK_POST_ID }}
N8N_TEST_WEBHOOK_PUT_ID: ${{ secrets.N8N_TEST_WEBHOOK_PUT_ID }}
N8N_TEST_WEBHOOK_DELETE_ID: ${{ secrets.N8N_TEST_WEBHOOK_DELETE_ID }}
CI: true
run: npm run test:integration
- 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`**:
```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 workflow IDs from n8n UI
6. ✅ Copy `.env.example` to `.env`
7. ✅ Set `N8N_API_URL=http://localhost:5678`
8. ✅ Generate API key in n8n Settings > API
9. ✅ Set `N8N_API_KEY=<your-key>`
10. ✅ Set all 4 `N8N_TEST_WEBHOOK_*_ID` variables
### CI/GitHub Actions
1. ✅ Set up cloud n8n instance (or self-hosted)
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 workflow ID secrets (4 total)
---
## Success Criteria
- ✅ All 17 handlers have integration tests
- ✅ All operations/parameters covered (150+ scenarios)
- ✅ Tests run successfully locally and in CI
- ✅ No manual cleanup required (automatic)
- ✅ Test coverage catches P0-level bugs
- ✅ CI runs on every PR and daily
- ✅ Clear error messages when tests fail
- ✅ Documentation for webhook workflow setup
---
## Timeline Estimate
- **Phase 1 (Foundation)**: 2-3 days
- **Phase 2 (Workflow Creation)**: 1 day
- **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**: ~14-18 days
---
## 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