mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-01-30 06:22:04 +00:00
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>
178 lines
4.8 KiB
TypeScript
178 lines
4.8 KiB
TypeScript
/**
|
|
* Test Context for Resource Tracking and Cleanup
|
|
*
|
|
* Tracks resources created during tests (workflows, executions) and
|
|
* provides automatic cleanup functionality.
|
|
*/
|
|
|
|
import { getTestN8nClient } from './n8n-client';
|
|
import { getN8nCredentials } from './credentials';
|
|
import { Logger } from '../../../../src/utils/logger';
|
|
|
|
const logger = new Logger({ prefix: '[TestContext]' });
|
|
|
|
export interface TestContext {
|
|
/** Workflow IDs created during the test */
|
|
workflowIds: string[];
|
|
|
|
/** Execution IDs created during the test */
|
|
executionIds: string[];
|
|
|
|
/** Clean up all tracked resources */
|
|
cleanup: () => Promise<void>;
|
|
|
|
/** Track a workflow for cleanup */
|
|
trackWorkflow: (id: string) => void;
|
|
|
|
/** Track an execution for cleanup */
|
|
trackExecution: (id: string) => void;
|
|
|
|
/** Remove a workflow from tracking (e.g., already deleted) */
|
|
untrackWorkflow: (id: string) => void;
|
|
|
|
/** Remove an execution from tracking (e.g., already deleted) */
|
|
untrackExecution: (id: string) => void;
|
|
}
|
|
|
|
/**
|
|
* Create a test context for tracking and cleaning up resources
|
|
*
|
|
* Use this in test setup to create a context that tracks all
|
|
* workflows and executions created during the test. Call cleanup()
|
|
* in afterEach or afterAll to remove test resources.
|
|
*
|
|
* @returns TestContext
|
|
*
|
|
* @example
|
|
* describe('Workflow tests', () => {
|
|
* let context: TestContext;
|
|
*
|
|
* beforeEach(() => {
|
|
* context = createTestContext();
|
|
* });
|
|
*
|
|
* afterEach(async () => {
|
|
* await context.cleanup();
|
|
* });
|
|
*
|
|
* it('creates a workflow', async () => {
|
|
* const workflow = await client.createWorkflow({ ... });
|
|
* context.trackWorkflow(workflow.id);
|
|
* // Test runs, then cleanup() automatically deletes the workflow
|
|
* });
|
|
* });
|
|
*/
|
|
export function createTestContext(): TestContext {
|
|
const context: TestContext = {
|
|
workflowIds: [],
|
|
executionIds: [],
|
|
|
|
trackWorkflow(id: string) {
|
|
if (!this.workflowIds.includes(id)) {
|
|
this.workflowIds.push(id);
|
|
logger.debug(`Tracking workflow for cleanup: ${id}`);
|
|
}
|
|
},
|
|
|
|
trackExecution(id: string) {
|
|
if (!this.executionIds.includes(id)) {
|
|
this.executionIds.push(id);
|
|
logger.debug(`Tracking execution for cleanup: ${id}`);
|
|
}
|
|
},
|
|
|
|
untrackWorkflow(id: string) {
|
|
const index = this.workflowIds.indexOf(id);
|
|
if (index > -1) {
|
|
this.workflowIds.splice(index, 1);
|
|
logger.debug(`Untracked workflow: ${id}`);
|
|
}
|
|
},
|
|
|
|
untrackExecution(id: string) {
|
|
const index = this.executionIds.indexOf(id);
|
|
if (index > -1) {
|
|
this.executionIds.splice(index, 1);
|
|
logger.debug(`Untracked execution: ${id}`);
|
|
}
|
|
},
|
|
|
|
async cleanup() {
|
|
const creds = getN8nCredentials();
|
|
|
|
// Skip cleanup if disabled
|
|
if (!creds.cleanup.enabled) {
|
|
logger.info('Cleanup disabled, skipping resource cleanup');
|
|
return;
|
|
}
|
|
|
|
const client = getTestN8nClient();
|
|
|
|
// Delete executions first (they reference workflows)
|
|
if (this.executionIds.length > 0) {
|
|
logger.info(`Cleaning up ${this.executionIds.length} execution(s)`);
|
|
|
|
for (const id of this.executionIds) {
|
|
try {
|
|
await client.deleteExecution(id);
|
|
logger.debug(`Deleted execution: ${id}`);
|
|
} catch (error) {
|
|
// Log but don't fail - execution might already be deleted
|
|
logger.warn(`Failed to delete execution ${id}:`, error);
|
|
}
|
|
}
|
|
|
|
this.executionIds = [];
|
|
}
|
|
|
|
// Then delete workflows
|
|
if (this.workflowIds.length > 0) {
|
|
logger.info(`Cleaning up ${this.workflowIds.length} workflow(s)`);
|
|
|
|
for (const id of this.workflowIds) {
|
|
try {
|
|
await client.deleteWorkflow(id);
|
|
logger.debug(`Deleted workflow: ${id}`);
|
|
} catch (error) {
|
|
// Log but don't fail - workflow might already be deleted
|
|
logger.warn(`Failed to delete workflow ${id}:`, error);
|
|
}
|
|
}
|
|
|
|
this.workflowIds = [];
|
|
}
|
|
}
|
|
};
|
|
|
|
return context;
|
|
}
|
|
|
|
/**
|
|
* Create a test workflow name with prefix and timestamp
|
|
*
|
|
* Generates a unique workflow name for testing that follows
|
|
* the configured naming convention.
|
|
*
|
|
* @param baseName - Base name for the workflow
|
|
* @returns Prefixed workflow name with timestamp
|
|
*
|
|
* @example
|
|
* const name = createTestWorkflowName('Simple HTTP Request');
|
|
* // Returns: "[MCP-TEST] Simple HTTP Request 1704067200000"
|
|
*/
|
|
export function createTestWorkflowName(baseName: string): string {
|
|
const creds = getN8nCredentials();
|
|
const timestamp = Date.now();
|
|
return `${creds.cleanup.namePrefix} ${baseName} ${timestamp}`;
|
|
}
|
|
|
|
/**
|
|
* Get the configured test tag
|
|
*
|
|
* @returns Tag to apply to test workflows
|
|
*/
|
|
export function getTestTag(): string {
|
|
const creds = getN8nCredentials();
|
|
return creds.cleanup.tag;
|
|
}
|