Agentic-qe n8n-workflow-testing-fundamentals
Comprehensive n8n workflow testing including execution lifecycle, node connection patterns, data flow validation, and error handling strategies. Use when testing n8n workflow automation applications.
git clone https://github.com/proffesor-for-testing/agentic-qe
T=$(mktemp -d) && git clone --depth=1 https://github.com/proffesor-for-testing/agentic-qe "$T" && mkdir -p ~/.claude/skills && cp -r "$T/assets/skills/n8n-workflow-testing-fundamentals" ~/.claude/skills/proffesor-for-testing-agentic-qe-n8n-workflow-testing-fundamentals-027380 && rm -rf "$T"
assets/skills/n8n-workflow-testing-fundamentals/SKILL.mdn8n Workflow Testing Fundamentals
<default_to_action> When testing n8n workflows:
- VALIDATE workflow structure before execution
- TEST with realistic test data
- VERIFY node-to-node data flow
- CHECK error handling paths
- MEASURE execution performance
Quick n8n Testing Checklist:
- All nodes properly connected (no orphans)
- Trigger node correctly configured
- Data mappings between nodes valid
- Error workflows defined
- Credentials properly referenced
Critical Success Factors:
- Test each execution path separately
- Validate data transformations at each node
- Check retry and error handling behavior
- Verify integrations with external services </default_to_action>
Quick Reference Card
When to Use
- Testing new n8n workflows
- Validating workflow changes
- Debugging failed executions
- Performance optimization
- Pre-deployment validation
n8n Workflow Components
| Component | Purpose | Testing Focus |
|---|---|---|
| Trigger | Starts workflow | Reliable activation, payload handling |
| Action Nodes | Process data | Configuration, data mapping |
| Logic Nodes | Control flow | Conditional routing, branches |
| Integration Nodes | External APIs | Auth, rate limits, errors |
| Error Workflow | Handle failures | Recovery, notifications |
Workflow Execution States
| State | Meaning | Test Action |
|---|---|---|
| Currently executing | Monitor progress |
| Completed successfully | Validate outputs |
| Execution failed | Analyze error |
| Waiting for trigger | Test trigger mechanism |
Workflow Structure Validation
// Validate workflow structure before execution async function validateWorkflowStructure(workflowId: string) { const workflow = await getWorkflow(workflowId); // Check for trigger node const triggerNode = workflow.nodes.find(n => n.type.includes('trigger') || n.type.includes('webhook') ); if (!triggerNode) { throw new Error('Workflow must have a trigger node'); } // Check for orphan nodes (no connections) const connectedNodes = new Set(); for (const [source, targets] of Object.entries(workflow.connections)) { connectedNodes.add(source); for (const outputs of Object.values(targets)) { for (const connections of outputs) { for (const conn of connections) { connectedNodes.add(conn.node); } } } } const orphans = workflow.nodes.filter(n => !connectedNodes.has(n.name)); if (orphans.length > 0) { console.warn('Orphan nodes detected:', orphans.map(n => n.name)); } // Validate credentials for (const node of workflow.nodes) { if (node.credentials) { for (const [type, ref] of Object.entries(node.credentials)) { if (!await credentialExists(ref.id)) { throw new Error(`Missing credential: ${type} for node ${node.name}`); } } } } return { valid: true, orphans, triggerNode }; }
Execution Testing
// Test workflow execution with various inputs async function testWorkflowExecution(workflowId: string, testCases: TestCase[]) { const results: TestResult[] = []; for (const testCase of testCases) { const startTime = Date.now(); // Execute workflow const execution = await executeWorkflow(workflowId, testCase.input); // Wait for completion const result = await waitForCompletion(execution.id, testCase.timeout || 30000); // Validate output const outputValid = validateOutput(result.data, testCase.expected); results.push({ testCase: testCase.name, success: result.status === 'success' && outputValid, duration: Date.now() - startTime, actualOutput: result.data, expectedOutput: testCase.expected }); } return results; } // Example test cases const testCases = [ { name: 'Valid customer data', input: { name: 'John Doe', email: 'john@example.com' }, expected: { processed: true, customerId: /^cust_/ }, timeout: 10000 }, { name: 'Missing email', input: { name: 'Jane Doe' }, expected: { error: 'Email required' }, timeout: 5000 }, { name: 'Invalid email format', input: { name: 'Bob', email: 'not-an-email' }, expected: { error: 'Invalid email' }, timeout: 5000 } ];
Data Flow Validation
// Trace data through workflow nodes async function validateDataFlow(executionId: string) { const execution = await getExecution(executionId); const nodeResults = execution.data.resultData.runData; const dataFlow: DataFlowStep[] = []; for (const [nodeName, runs] of Object.entries(nodeResults)) { for (const run of runs) { dataFlow.push({ node: nodeName, input: run.data?.main?.[0]?.[0]?.json || {}, output: run.data?.main?.[0]?.[0]?.json || {}, executionTime: run.executionTime, status: run.executionStatus }); } } // Validate data transformations for (let i = 1; i < dataFlow.length; i++) { const prev = dataFlow[i - 1]; const curr = dataFlow[i]; // Check if expected data passed through validateDataMapping(prev.output, curr.input); } return dataFlow; } // Validate data mapping between nodes function validateDataMapping(sourceOutput: any, targetInput: any) { // Check all required fields are present const missingFields: string[] = []; for (const [key, value] of Object.entries(targetInput)) { if (value === undefined && sourceOutput[key] === undefined) { missingFields.push(key); } } if (missingFields.length > 0) { console.warn('Missing fields in data mapping:', missingFields); } return missingFields.length === 0; }
Error Handling Testing
// Test error handling paths async function testErrorHandling(workflowId: string) { const errorScenarios = [ { name: 'API timeout', inject: { delay: 35000 }, // Trigger timeout expectedError: 'timeout' }, { name: 'Invalid data', inject: { invalidField: true }, expectedError: 'validation' }, { name: 'Missing credentials', inject: { removeCredentials: true }, expectedError: 'authentication' } ]; const results: ErrorTestResult[] = []; for (const scenario of errorScenarios) { // Execute with error injection const execution = await executeWithErrorInjection(workflowId, scenario.inject); // Check error was caught const result = await waitForCompletion(execution.id); // Validate error handling results.push({ scenario: scenario.name, errorCaught: result.status === 'failed', errorType: result.data?.resultData?.error?.type, expectedError: scenario.expectedError, errorWorkflowTriggered: await checkErrorWorkflowTriggered(execution.id), alertSent: await checkAlertSent(execution.id) }); } return results; } // Verify error workflow was triggered async function checkErrorWorkflowTriggered(executionId: string): Promise<boolean> { const errorExecutions = await getExecutions({ filter: { metadata: { errorTriggeredBy: executionId } } }); return errorExecutions.length > 0; }
Node Connection Patterns
Linear Flow
Trigger → Process → Transform → Output
Testing: Execute once, validate each node output
Branching Flow
Trigger → IF → [Branch A] → Merge → Output → [Branch B] →
Testing: Test both branches separately, verify merge behavior
Parallel Flow
Trigger → Split → [Process A] → Merge → Output → [Process B] →
Testing: Validate parallel execution, check merge timing
Loop Flow
Trigger → SplitInBatches → Process → [Loop back until done] → Output
Testing: Test with varying batch sizes, verify all items processed
Common Testing Patterns
Test Data Generation
// Generate test data for common n8n patterns const testDataGenerators = { webhook: () => ({ body: { event: 'test', timestamp: new Date().toISOString() }, headers: { 'Content-Type': 'application/json' }, query: { source: 'test' } }), slack: () => ({ type: 'message', channel: 'C123456', user: 'U789012', text: 'Test message' }), github: () => ({ action: 'opened', issue: { number: 1, title: 'Test Issue', body: 'Test body' }, repository: { full_name: 'test/repo' } }), stripe: () => ({ type: 'payment_intent.succeeded', data: { object: { id: 'pi_test123', amount: 1000, currency: 'usd' } } }) };
Execution Assertions
// Common assertions for workflow execution const workflowAssertions = { // Assert workflow completed assertCompleted: (execution) => { expect(execution.finished).toBe(true); expect(execution.status).toBe('success'); }, // Assert specific node executed assertNodeExecuted: (execution, nodeName) => { const nodeData = execution.data.resultData.runData[nodeName]; expect(nodeData).toBeDefined(); expect(nodeData[0].executionStatus).toBe('success'); }, // Assert data transformation assertDataTransformed: (execution, nodeName, expectedData) => { const nodeOutput = execution.data.resultData.runData[nodeName][0].data.main[0][0].json; expect(nodeOutput).toMatchObject(expectedData); }, // Assert execution time assertExecutionTime: (execution, maxMs) => { const duration = new Date(execution.stoppedAt) - new Date(execution.startedAt); expect(duration).toBeLessThan(maxMs); } };
Agent Coordination Hints
Memory Namespace
aqe/n8n/ ├── workflows/* - Cached workflow definitions ├── test-results/* - Test execution results ├── validations/* - Validation reports ├── patterns/* - Discovered testing patterns └── executions/* - Execution tracking
Fleet Coordination
// Comprehensive n8n testing with fleet const n8nFleet = await FleetManager.coordinate({ strategy: 'n8n-testing', agents: [ 'n8n-workflow-executor', // Execute and validate 'n8n-node-validator', // Validate configurations 'n8n-trigger-test', // Test triggers 'n8n-expression-validator', // Validate expressions 'n8n-integration-test' // Test integrations ], topology: 'parallel' });
Related Skills
- n8n-expression-testing - Expression validation
- n8n-trigger-testing-strategies - Trigger testing
- n8n-integration-testing-patterns - Integration testing
- n8n-security-testing - Security validation
Remember
n8n workflows are JSON-based execution flows that connect 400+ services. Testing requires validating:
- Workflow structure (nodes, connections)
- Trigger reliability (webhooks, schedules)
- Data flow (transformations between nodes)
- Error handling (retry, fallback, notifications)
- Performance (execution time, resource usage)
With Agents: Use n8n-workflow-executor for execution testing, n8n-node-validator for configuration validation, and coordinate multiple agents for comprehensive workflow testing.