agentic-qe 2.5.6 → 2.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/n8n/n8n-base-agent.md +376 -0
- package/.claude/agents/n8n/n8n-bdd-scenario-tester.md +613 -0
- package/.claude/agents/n8n/n8n-chaos-tester.md +654 -0
- package/.claude/agents/n8n/n8n-ci-orchestrator.md +850 -0
- package/.claude/agents/n8n/n8n-compliance-validator.md +685 -0
- package/.claude/agents/n8n/n8n-expression-validator.md +560 -0
- package/.claude/agents/n8n/n8n-integration-test.md +602 -0
- package/.claude/agents/n8n/n8n-monitoring-validator.md +589 -0
- package/.claude/agents/n8n/n8n-node-validator.md +455 -0
- package/.claude/agents/n8n/n8n-performance-tester.md +630 -0
- package/.claude/agents/n8n/n8n-security-auditor.md +786 -0
- package/.claude/agents/n8n/n8n-trigger-test.md +500 -0
- package/.claude/agents/n8n/n8n-unit-tester.md +633 -0
- package/.claude/agents/n8n/n8n-version-comparator.md +567 -0
- package/.claude/agents/n8n/n8n-workflow-executor.md +392 -0
- package/.claude/skills/n8n-expression-testing/SKILL.md +434 -0
- package/.claude/skills/n8n-integration-testing-patterns/SKILL.md +540 -0
- package/.claude/skills/n8n-security-testing/SKILL.md +599 -0
- package/.claude/skills/n8n-trigger-testing-strategies/SKILL.md +541 -0
- package/.claude/skills/n8n-workflow-testing-fundamentals/SKILL.md +447 -0
- package/CHANGELOG.md +127 -0
- package/README.md +7 -4
- package/dist/agents/BaseAgent.d.ts +142 -0
- package/dist/agents/BaseAgent.d.ts.map +1 -1
- package/dist/agents/BaseAgent.js +372 -2
- package/dist/agents/BaseAgent.js.map +1 -1
- package/dist/agents/TestGeneratorAgent.d.ts +5 -0
- package/dist/agents/TestGeneratorAgent.d.ts.map +1 -1
- package/dist/agents/TestGeneratorAgent.js +38 -0
- package/dist/agents/TestGeneratorAgent.js.map +1 -1
- package/dist/agents/index.d.ts +1 -1
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/n8n/N8nAPIClient.d.ts +121 -0
- package/dist/agents/n8n/N8nAPIClient.d.ts.map +1 -0
- package/dist/agents/n8n/N8nAPIClient.js +367 -0
- package/dist/agents/n8n/N8nAPIClient.js.map +1 -0
- package/dist/agents/n8n/N8nAuditPersistence.d.ts +120 -0
- package/dist/agents/n8n/N8nAuditPersistence.d.ts.map +1 -0
- package/dist/agents/n8n/N8nAuditPersistence.js +473 -0
- package/dist/agents/n8n/N8nAuditPersistence.js.map +1 -0
- package/dist/agents/n8n/N8nBDDScenarioTesterAgent.d.ts +159 -0
- package/dist/agents/n8n/N8nBDDScenarioTesterAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nBDDScenarioTesterAgent.js +697 -0
- package/dist/agents/n8n/N8nBDDScenarioTesterAgent.js.map +1 -0
- package/dist/agents/n8n/N8nBaseAgent.d.ts +126 -0
- package/dist/agents/n8n/N8nBaseAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nBaseAgent.js +446 -0
- package/dist/agents/n8n/N8nBaseAgent.js.map +1 -0
- package/dist/agents/n8n/N8nCIOrchestratorAgent.d.ts +164 -0
- package/dist/agents/n8n/N8nCIOrchestratorAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nCIOrchestratorAgent.js +610 -0
- package/dist/agents/n8n/N8nCIOrchestratorAgent.js.map +1 -0
- package/dist/agents/n8n/N8nChaosTesterAgent.d.ts +205 -0
- package/dist/agents/n8n/N8nChaosTesterAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nChaosTesterAgent.js +729 -0
- package/dist/agents/n8n/N8nChaosTesterAgent.js.map +1 -0
- package/dist/agents/n8n/N8nComplianceValidatorAgent.d.ts +228 -0
- package/dist/agents/n8n/N8nComplianceValidatorAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nComplianceValidatorAgent.js +986 -0
- package/dist/agents/n8n/N8nComplianceValidatorAgent.js.map +1 -0
- package/dist/agents/n8n/N8nContractTesterAgent.d.ts +213 -0
- package/dist/agents/n8n/N8nContractTesterAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nContractTesterAgent.js +989 -0
- package/dist/agents/n8n/N8nContractTesterAgent.js.map +1 -0
- package/dist/agents/n8n/N8nExpressionValidatorAgent.d.ts +99 -0
- package/dist/agents/n8n/N8nExpressionValidatorAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nExpressionValidatorAgent.js +632 -0
- package/dist/agents/n8n/N8nExpressionValidatorAgent.js.map +1 -0
- package/dist/agents/n8n/N8nFailureModeTesterAgent.d.ts +238 -0
- package/dist/agents/n8n/N8nFailureModeTesterAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nFailureModeTesterAgent.js +956 -0
- package/dist/agents/n8n/N8nFailureModeTesterAgent.js.map +1 -0
- package/dist/agents/n8n/N8nIdempotencyTesterAgent.d.ts +242 -0
- package/dist/agents/n8n/N8nIdempotencyTesterAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nIdempotencyTesterAgent.js +992 -0
- package/dist/agents/n8n/N8nIdempotencyTesterAgent.js.map +1 -0
- package/dist/agents/n8n/N8nIntegrationTestAgent.d.ts +104 -0
- package/dist/agents/n8n/N8nIntegrationTestAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nIntegrationTestAgent.js +653 -0
- package/dist/agents/n8n/N8nIntegrationTestAgent.js.map +1 -0
- package/dist/agents/n8n/N8nMonitoringValidatorAgent.d.ts +210 -0
- package/dist/agents/n8n/N8nMonitoringValidatorAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nMonitoringValidatorAgent.js +669 -0
- package/dist/agents/n8n/N8nMonitoringValidatorAgent.js.map +1 -0
- package/dist/agents/n8n/N8nNodeValidatorAgent.d.ts +142 -0
- package/dist/agents/n8n/N8nNodeValidatorAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nNodeValidatorAgent.js +1090 -0
- package/dist/agents/n8n/N8nNodeValidatorAgent.js.map +1 -0
- package/dist/agents/n8n/N8nPerformanceTesterAgent.d.ts +198 -0
- package/dist/agents/n8n/N8nPerformanceTesterAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nPerformanceTesterAgent.js +653 -0
- package/dist/agents/n8n/N8nPerformanceTesterAgent.js.map +1 -0
- package/dist/agents/n8n/N8nReplayabilityTesterAgent.d.ts +245 -0
- package/dist/agents/n8n/N8nReplayabilityTesterAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nReplayabilityTesterAgent.js +952 -0
- package/dist/agents/n8n/N8nReplayabilityTesterAgent.js.map +1 -0
- package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.d.ts +325 -0
- package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.js +1187 -0
- package/dist/agents/n8n/N8nSecretsHygieneAuditorAgent.js.map +1 -0
- package/dist/agents/n8n/N8nSecurityAuditorAgent.d.ts +91 -0
- package/dist/agents/n8n/N8nSecurityAuditorAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nSecurityAuditorAgent.js +825 -0
- package/dist/agents/n8n/N8nSecurityAuditorAgent.js.map +1 -0
- package/dist/agents/n8n/N8nTestHarness.d.ts +131 -0
- package/dist/agents/n8n/N8nTestHarness.d.ts.map +1 -0
- package/dist/agents/n8n/N8nTestHarness.js +456 -0
- package/dist/agents/n8n/N8nTestHarness.js.map +1 -0
- package/dist/agents/n8n/N8nTriggerTestAgent.d.ts +119 -0
- package/dist/agents/n8n/N8nTriggerTestAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nTriggerTestAgent.js +652 -0
- package/dist/agents/n8n/N8nTriggerTestAgent.js.map +1 -0
- package/dist/agents/n8n/N8nUnitTesterAgent.d.ts +130 -0
- package/dist/agents/n8n/N8nUnitTesterAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nUnitTesterAgent.js +522 -0
- package/dist/agents/n8n/N8nUnitTesterAgent.js.map +1 -0
- package/dist/agents/n8n/N8nVersionComparatorAgent.d.ts +201 -0
- package/dist/agents/n8n/N8nVersionComparatorAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nVersionComparatorAgent.js +645 -0
- package/dist/agents/n8n/N8nVersionComparatorAgent.js.map +1 -0
- package/dist/agents/n8n/N8nWorkflowExecutorAgent.d.ts +120 -0
- package/dist/agents/n8n/N8nWorkflowExecutorAgent.d.ts.map +1 -0
- package/dist/agents/n8n/N8nWorkflowExecutorAgent.js +347 -0
- package/dist/agents/n8n/N8nWorkflowExecutorAgent.js.map +1 -0
- package/dist/agents/n8n/index.d.ts +119 -0
- package/dist/agents/n8n/index.d.ts.map +1 -0
- package/dist/agents/n8n/index.js +298 -0
- package/dist/agents/n8n/index.js.map +1 -0
- package/dist/agents/n8n/types.d.ts +486 -0
- package/dist/agents/n8n/types.d.ts.map +1 -0
- package/dist/agents/n8n/types.js +8 -0
- package/dist/agents/n8n/types.js.map +1 -0
- package/dist/cli/init/agents.d.ts.map +1 -1
- package/dist/cli/init/agents.js +29 -0
- package/dist/cli/init/agents.js.map +1 -1
- package/dist/cli/init/skills.d.ts.map +1 -1
- package/dist/cli/init/skills.js +7 -1
- package/dist/cli/init/skills.js.map +1 -1
- package/dist/core/memory/HNSWVectorMemory.js +1 -1
- package/dist/core/memory/RuVectorPatternStore.d.ts +90 -0
- package/dist/core/memory/RuVectorPatternStore.d.ts.map +1 -1
- package/dist/core/memory/RuVectorPatternStore.js +209 -0
- package/dist/core/memory/RuVectorPatternStore.js.map +1 -1
- package/dist/learning/FederatedManager.d.ts +232 -0
- package/dist/learning/FederatedManager.d.ts.map +1 -0
- package/dist/learning/FederatedManager.js +489 -0
- package/dist/learning/FederatedManager.js.map +1 -0
- package/dist/learning/HNSWPatternAdapter.d.ts +117 -0
- package/dist/learning/HNSWPatternAdapter.d.ts.map +1 -0
- package/dist/learning/HNSWPatternAdapter.js +262 -0
- package/dist/learning/HNSWPatternAdapter.js.map +1 -0
- package/dist/learning/LearningEngine.d.ts +27 -0
- package/dist/learning/LearningEngine.d.ts.map +1 -1
- package/dist/learning/LearningEngine.js +75 -1
- package/dist/learning/LearningEngine.js.map +1 -1
- package/dist/learning/PatternCurator.d.ts +217 -0
- package/dist/learning/PatternCurator.d.ts.map +1 -0
- package/dist/learning/PatternCurator.js +393 -0
- package/dist/learning/PatternCurator.js.map +1 -0
- package/dist/learning/index.d.ts +6 -0
- package/dist/learning/index.d.ts.map +1 -1
- package/dist/learning/index.js +16 -1
- package/dist/learning/index.js.map +1 -1
- package/dist/learning/types.d.ts +4 -0
- package/dist/learning/types.d.ts.map +1 -1
- package/dist/mcp/server-instructions.d.ts +1 -1
- package/dist/mcp/server-instructions.js +1 -1
- package/dist/memory/HNSWPatternStore.d.ts +176 -0
- package/dist/memory/HNSWPatternStore.d.ts.map +1 -0
- package/dist/memory/HNSWPatternStore.js +392 -0
- package/dist/memory/HNSWPatternStore.js.map +1 -0
- package/dist/memory/index.d.ts +8 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +13 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/providers/HybridRouter.d.ts +85 -4
- package/dist/providers/HybridRouter.d.ts.map +1 -1
- package/dist/providers/HybridRouter.js +332 -10
- package/dist/providers/HybridRouter.js.map +1 -1
- package/dist/providers/LLMBaselineTracker.d.ts +120 -0
- package/dist/providers/LLMBaselineTracker.d.ts.map +1 -0
- package/dist/providers/LLMBaselineTracker.js +305 -0
- package/dist/providers/LLMBaselineTracker.js.map +1 -0
- package/dist/providers/OpenRouterProvider.d.ts +26 -0
- package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/providers/OpenRouterProvider.js +75 -6
- package/dist/providers/OpenRouterProvider.js.map +1 -1
- package/dist/providers/RuVectorClient.d.ts +259 -0
- package/dist/providers/RuVectorClient.d.ts.map +1 -0
- package/dist/providers/RuVectorClient.js +416 -0
- package/dist/providers/RuVectorClient.js.map +1 -0
- package/dist/providers/RuvllmPatternCurator.d.ts +116 -0
- package/dist/providers/RuvllmPatternCurator.d.ts.map +1 -0
- package/dist/providers/RuvllmPatternCurator.js +323 -0
- package/dist/providers/RuvllmPatternCurator.js.map +1 -0
- package/dist/providers/RuvllmProvider.d.ts +233 -1
- package/dist/providers/RuvllmProvider.d.ts.map +1 -1
- package/dist/providers/RuvllmProvider.js +781 -11
- package/dist/providers/RuvllmProvider.js.map +1 -1
- package/dist/providers/index.d.ts +5 -1
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +12 -2
- package/dist/providers/index.js.map +1 -1
- package/dist/utils/ruvllm-loader.d.ts +98 -1
- package/dist/utils/ruvllm-loader.d.ts.map +1 -1
- package/dist/utils/ruvllm-loader.js.map +1 -1
- package/docs/reference/agents.md +91 -2
- package/docs/reference/skills.md +97 -2
- package/package.json +2 -2
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: n8n-trigger-testing-strategies
|
|
3
|
+
description: "Webhook testing, schedule validation, event-driven triggers, and polling mechanism testing for n8n workflows. Use when testing how workflows are triggered."
|
|
4
|
+
category: n8n-testing
|
|
5
|
+
priority: high
|
|
6
|
+
tokenEstimate: 1000
|
|
7
|
+
agents: [n8n-trigger-test]
|
|
8
|
+
implementation_status: production
|
|
9
|
+
optimization_version: 1.0
|
|
10
|
+
last_optimized: 2025-12-15
|
|
11
|
+
dependencies: []
|
|
12
|
+
quick_reference_card: true
|
|
13
|
+
tags: [n8n, triggers, webhook, schedule, cron, polling, testing]
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# n8n Trigger Testing Strategies
|
|
17
|
+
|
|
18
|
+
<default_to_action>
|
|
19
|
+
When testing n8n triggers:
|
|
20
|
+
1. IDENTIFY trigger type (webhook, schedule, polling, event)
|
|
21
|
+
2. TEST with various valid payloads
|
|
22
|
+
3. VERIFY authentication and authorization
|
|
23
|
+
4. CHECK error handling for invalid inputs
|
|
24
|
+
5. MEASURE response time and reliability
|
|
25
|
+
|
|
26
|
+
**Quick Trigger Checklist:**
|
|
27
|
+
- Trigger activates workflow correctly
|
|
28
|
+
- Payload parsed and validated
|
|
29
|
+
- Authentication enforced (if configured)
|
|
30
|
+
- Error responses are informative
|
|
31
|
+
- Response time is acceptable
|
|
32
|
+
|
|
33
|
+
**Critical Success Factors:**
|
|
34
|
+
- Test edge cases (empty payloads, large payloads)
|
|
35
|
+
- Verify idempotency where needed
|
|
36
|
+
- Check timeout handling
|
|
37
|
+
- Monitor for missed triggers
|
|
38
|
+
</default_to_action>
|
|
39
|
+
|
|
40
|
+
## Quick Reference Card
|
|
41
|
+
|
|
42
|
+
### n8n Trigger Types
|
|
43
|
+
|
|
44
|
+
| Type | Use Case | Testing Focus |
|
|
45
|
+
|------|----------|---------------|
|
|
46
|
+
| **Webhook** | External HTTP calls | Payloads, auth, methods |
|
|
47
|
+
| **Schedule** | Timed execution | Cron accuracy, timezone |
|
|
48
|
+
| **Polling** | Check for changes | Interval, deduplication |
|
|
49
|
+
| **Event** | Service events | Event handling, filtering |
|
|
50
|
+
|
|
51
|
+
### Common Webhook Configurations
|
|
52
|
+
|
|
53
|
+
| Setting | Options | Impact |
|
|
54
|
+
|---------|---------|--------|
|
|
55
|
+
| HTTP Method | GET, POST, PUT, DELETE | Request handling |
|
|
56
|
+
| Authentication | None, Basic, Header | Security |
|
|
57
|
+
| Response Mode | Immediately, Last Node, Custom | Response timing |
|
|
58
|
+
| Path | Custom URL path | Endpoint identification |
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Webhook Testing
|
|
63
|
+
|
|
64
|
+
### Basic Webhook Test
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
// Test webhook with various payloads
|
|
68
|
+
async function testWebhook(webhookUrl: string): Promise<WebhookTestResult> {
|
|
69
|
+
const testPayloads = [
|
|
70
|
+
// Valid JSON
|
|
71
|
+
{ type: 'json', data: { event: 'test', timestamp: Date.now() } },
|
|
72
|
+
// Empty object
|
|
73
|
+
{ type: 'empty', data: {} },
|
|
74
|
+
// Large payload
|
|
75
|
+
{ type: 'large', data: { items: Array(1000).fill({ id: 1, name: 'test' }) } },
|
|
76
|
+
// Nested data
|
|
77
|
+
{ type: 'nested', data: { level1: { level2: { level3: { value: 'deep' } } } } },
|
|
78
|
+
// Special characters
|
|
79
|
+
{ type: 'special', data: { text: 'Hello <script>alert("xss")</script>' } }
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
const results: PayloadTestResult[] = [];
|
|
83
|
+
|
|
84
|
+
for (const payload of testPayloads) {
|
|
85
|
+
const startTime = Date.now();
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const response = await fetch(webhookUrl, {
|
|
89
|
+
method: 'POST',
|
|
90
|
+
headers: { 'Content-Type': 'application/json' },
|
|
91
|
+
body: JSON.stringify(payload.data)
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
results.push({
|
|
95
|
+
payloadType: payload.type,
|
|
96
|
+
success: response.ok,
|
|
97
|
+
status: response.status,
|
|
98
|
+
responseTime: Date.now() - startTime,
|
|
99
|
+
responseBody: await response.text()
|
|
100
|
+
});
|
|
101
|
+
} catch (error) {
|
|
102
|
+
results.push({
|
|
103
|
+
payloadType: payload.type,
|
|
104
|
+
success: false,
|
|
105
|
+
error: error.message
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return { webhookUrl, results };
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### HTTP Method Testing
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// Test all HTTP methods
|
|
118
|
+
async function testWebhookMethods(webhookUrl: string): Promise<MethodTestResult[]> {
|
|
119
|
+
const methods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'];
|
|
120
|
+
const results: MethodTestResult[] = [];
|
|
121
|
+
|
|
122
|
+
for (const method of methods) {
|
|
123
|
+
try {
|
|
124
|
+
const response = await fetch(webhookUrl, {
|
|
125
|
+
method,
|
|
126
|
+
headers: { 'Content-Type': 'application/json' },
|
|
127
|
+
body: ['GET', 'HEAD', 'OPTIONS'].includes(method) ? undefined : '{}'
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
results.push({
|
|
131
|
+
method,
|
|
132
|
+
allowed: response.ok || response.status !== 405,
|
|
133
|
+
status: response.status,
|
|
134
|
+
statusText: response.statusText
|
|
135
|
+
});
|
|
136
|
+
} catch (error) {
|
|
137
|
+
results.push({
|
|
138
|
+
method,
|
|
139
|
+
allowed: false,
|
|
140
|
+
error: error.message
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return results;
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Authentication Testing
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
// Test webhook authentication
|
|
153
|
+
async function testWebhookAuth(webhookUrl: string, authConfig: AuthConfig): Promise<AuthTestResult> {
|
|
154
|
+
const scenarios = [
|
|
155
|
+
// No auth
|
|
156
|
+
{ name: 'no-auth', headers: {} },
|
|
157
|
+
// Invalid auth
|
|
158
|
+
{ name: 'invalid-auth', headers: { 'Authorization': 'Bearer invalid-token' } },
|
|
159
|
+
// Valid auth
|
|
160
|
+
{ name: 'valid-auth', headers: { 'Authorization': `Bearer ${authConfig.token}` } },
|
|
161
|
+
// Expired auth
|
|
162
|
+
{ name: 'expired-auth', headers: { 'Authorization': `Bearer ${authConfig.expiredToken}` } }
|
|
163
|
+
];
|
|
164
|
+
|
|
165
|
+
const results: AuthScenarioResult[] = [];
|
|
166
|
+
|
|
167
|
+
for (const scenario of scenarios) {
|
|
168
|
+
const response = await fetch(webhookUrl, {
|
|
169
|
+
method: 'POST',
|
|
170
|
+
headers: {
|
|
171
|
+
'Content-Type': 'application/json',
|
|
172
|
+
...scenario.headers
|
|
173
|
+
},
|
|
174
|
+
body: '{}'
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
results.push({
|
|
178
|
+
scenario: scenario.name,
|
|
179
|
+
status: response.status,
|
|
180
|
+
authenticated: response.ok,
|
|
181
|
+
errorMessage: response.ok ? null : await response.text()
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
authRequired: !results.find(r => r.scenario === 'no-auth')?.authenticated,
|
|
187
|
+
invalidRejected: !results.find(r => r.scenario === 'invalid-auth')?.authenticated,
|
|
188
|
+
validAccepted: results.find(r => r.scenario === 'valid-auth')?.authenticated,
|
|
189
|
+
results
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Schedule Testing
|
|
197
|
+
|
|
198
|
+
### Cron Expression Validation
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
// Validate cron expression
|
|
202
|
+
function validateCronExpression(expression: string): CronValidationResult {
|
|
203
|
+
const parts = expression.trim().split(/\s+/);
|
|
204
|
+
|
|
205
|
+
if (parts.length < 5 || parts.length > 6) {
|
|
206
|
+
return {
|
|
207
|
+
valid: false,
|
|
208
|
+
error: `Expected 5-6 parts, got ${parts.length}`
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const [minute, hour, dayOfMonth, month, dayOfWeek, year] = parts;
|
|
213
|
+
|
|
214
|
+
const validations = [
|
|
215
|
+
{ field: 'minute', value: minute, range: [0, 59] },
|
|
216
|
+
{ field: 'hour', value: hour, range: [0, 23] },
|
|
217
|
+
{ field: 'dayOfMonth', value: dayOfMonth, range: [1, 31] },
|
|
218
|
+
{ field: 'month', value: month, range: [1, 12] },
|
|
219
|
+
{ field: 'dayOfWeek', value: dayOfWeek, range: [0, 7] }
|
|
220
|
+
];
|
|
221
|
+
|
|
222
|
+
for (const v of validations) {
|
|
223
|
+
const result = validateCronField(v.value, v.range);
|
|
224
|
+
if (!result.valid) {
|
|
225
|
+
return { valid: false, error: `Invalid ${v.field}: ${result.error}` };
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
valid: true,
|
|
231
|
+
description: describeCronExpression(expression),
|
|
232
|
+
nextExecutions: getNextCronExecutions(expression, 5)
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Get human-readable description
|
|
237
|
+
function describeCronExpression(expression: string): string {
|
|
238
|
+
// Common patterns
|
|
239
|
+
const patterns: Record<string, string> = {
|
|
240
|
+
'* * * * *': 'Every minute',
|
|
241
|
+
'*/5 * * * *': 'Every 5 minutes',
|
|
242
|
+
'0 * * * *': 'Every hour',
|
|
243
|
+
'0 0 * * *': 'Every day at midnight',
|
|
244
|
+
'0 9 * * 1-5': 'Weekdays at 9:00 AM',
|
|
245
|
+
'0 0 1 * *': 'First day of every month',
|
|
246
|
+
'0 0 * * 0': 'Every Sunday at midnight'
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
return patterns[expression] || 'Custom schedule';
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Calculate next execution times
|
|
253
|
+
function getNextCronExecutions(expression: string, count: number): Date[] {
|
|
254
|
+
const executions: Date[] = [];
|
|
255
|
+
let current = new Date();
|
|
256
|
+
|
|
257
|
+
// Simple implementation - use cron-parser library in production
|
|
258
|
+
for (let i = 0; i < count; i++) {
|
|
259
|
+
const next = calculateNextCronExecution(expression, current);
|
|
260
|
+
executions.push(next);
|
|
261
|
+
current = new Date(next.getTime() + 60000); // Move past this execution
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return executions;
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Schedule Reliability Testing
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
// Test schedule trigger reliability
|
|
272
|
+
async function testScheduleReliability(triggerId: string, testDuration: number): Promise<ScheduleTestResult> {
|
|
273
|
+
const startTime = Date.now();
|
|
274
|
+
const expectedExecutions: Date[] = [];
|
|
275
|
+
const actualExecutions: Date[] = [];
|
|
276
|
+
|
|
277
|
+
// Calculate expected execution times
|
|
278
|
+
const cronExpression = await getTriggerCronExpression(triggerId);
|
|
279
|
+
let checkTime = new Date(startTime);
|
|
280
|
+
while (checkTime.getTime() < startTime + testDuration) {
|
|
281
|
+
const nextExec = calculateNextCronExecution(cronExpression, checkTime);
|
|
282
|
+
if (nextExec.getTime() < startTime + testDuration) {
|
|
283
|
+
expectedExecutions.push(nextExec);
|
|
284
|
+
}
|
|
285
|
+
checkTime = new Date(nextExec.getTime() + 60000);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Monitor actual executions
|
|
289
|
+
const executionListener = onExecutionStart(triggerId, (exec) => {
|
|
290
|
+
actualExecutions.push(new Date(exec.startedAt));
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
// Wait for test duration
|
|
294
|
+
await sleep(testDuration);
|
|
295
|
+
executionListener.stop();
|
|
296
|
+
|
|
297
|
+
// Compare expected vs actual
|
|
298
|
+
const comparison = compareExecutions(expectedExecutions, actualExecutions);
|
|
299
|
+
|
|
300
|
+
return {
|
|
301
|
+
testDuration,
|
|
302
|
+
expectedCount: expectedExecutions.length,
|
|
303
|
+
actualCount: actualExecutions.length,
|
|
304
|
+
missedExecutions: comparison.missed,
|
|
305
|
+
extraExecutions: comparison.extra,
|
|
306
|
+
timingAccuracy: comparison.timingAccuracy,
|
|
307
|
+
reliability: (actualExecutions.length / expectedExecutions.length) * 100
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## Polling Trigger Testing
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
// Test polling trigger behavior
|
|
318
|
+
async function testPollingTrigger(triggerId: string, testConfig: PollingTestConfig): Promise<PollingTestResult> {
|
|
319
|
+
const { interval, testDuration, simulateDataChanges } = testConfig;
|
|
320
|
+
|
|
321
|
+
const pollEvents: PollEvent[] = [];
|
|
322
|
+
const triggeredExecutions: Execution[] = [];
|
|
323
|
+
|
|
324
|
+
// Monitor polling events
|
|
325
|
+
const pollListener = onPoll(triggerId, (event) => {
|
|
326
|
+
pollEvents.push({
|
|
327
|
+
timestamp: new Date(),
|
|
328
|
+
dataFound: event.hasNewData,
|
|
329
|
+
itemCount: event.items?.length || 0
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
// Monitor triggered executions
|
|
334
|
+
const execListener = onExecutionStart(triggerId, (exec) => {
|
|
335
|
+
triggeredExecutions.push(exec);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// Optionally simulate data changes
|
|
339
|
+
if (simulateDataChanges) {
|
|
340
|
+
for (const change of simulateDataChanges) {
|
|
341
|
+
setTimeout(() => {
|
|
342
|
+
injectTestData(triggerId, change.data);
|
|
343
|
+
}, change.at);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Wait for test duration
|
|
348
|
+
await sleep(testDuration);
|
|
349
|
+
|
|
350
|
+
pollListener.stop();
|
|
351
|
+
execListener.stop();
|
|
352
|
+
|
|
353
|
+
// Analyze results
|
|
354
|
+
const expectedPolls = Math.floor(testDuration / interval);
|
|
355
|
+
const actualPolls = pollEvents.length;
|
|
356
|
+
|
|
357
|
+
return {
|
|
358
|
+
interval,
|
|
359
|
+
testDuration,
|
|
360
|
+
expectedPolls,
|
|
361
|
+
actualPolls,
|
|
362
|
+
pollAccuracy: (actualPolls / expectedPolls) * 100,
|
|
363
|
+
averageInterval: calculateAverageInterval(pollEvents),
|
|
364
|
+
executionsTriggered: triggeredExecutions.length,
|
|
365
|
+
deduplicationWorking: checkDeduplication(triggeredExecutions),
|
|
366
|
+
pollEvents
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Check if deduplication is working
|
|
371
|
+
function checkDeduplication(executions: Execution[]): boolean {
|
|
372
|
+
const processedIds = new Set();
|
|
373
|
+
|
|
374
|
+
for (const exec of executions) {
|
|
375
|
+
const itemIds = exec.data?.resultData?.runData?.Trigger?.[0]?.data?.main?.[0]
|
|
376
|
+
?.map(item => item.json?.id);
|
|
377
|
+
|
|
378
|
+
if (itemIds) {
|
|
379
|
+
for (const id of itemIds) {
|
|
380
|
+
if (processedIds.has(id)) {
|
|
381
|
+
return false; // Duplicate found
|
|
382
|
+
}
|
|
383
|
+
processedIds.add(id);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return true;
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## Event Trigger Testing
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
// Test event-driven triggers
|
|
398
|
+
async function testEventTrigger(triggerId: string, eventConfig: EventTestConfig): Promise<EventTestResult> {
|
|
399
|
+
const { eventType, testEvents, timeout } = eventConfig;
|
|
400
|
+
|
|
401
|
+
const results: EventResult[] = [];
|
|
402
|
+
|
|
403
|
+
for (const testEvent of testEvents) {
|
|
404
|
+
// Emit test event
|
|
405
|
+
const startTime = Date.now();
|
|
406
|
+
await emitTestEvent(eventType, testEvent.payload);
|
|
407
|
+
|
|
408
|
+
// Wait for trigger
|
|
409
|
+
try {
|
|
410
|
+
const execution = await waitForTrigger(triggerId, timeout);
|
|
411
|
+
|
|
412
|
+
results.push({
|
|
413
|
+
eventType: testEvent.type,
|
|
414
|
+
triggered: true,
|
|
415
|
+
latency: Date.now() - startTime,
|
|
416
|
+
payloadReceived: execution.data?.inputData
|
|
417
|
+
});
|
|
418
|
+
} catch (error) {
|
|
419
|
+
results.push({
|
|
420
|
+
eventType: testEvent.type,
|
|
421
|
+
triggered: false,
|
|
422
|
+
error: error.message
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return {
|
|
428
|
+
eventType,
|
|
429
|
+
testsRun: testEvents.length,
|
|
430
|
+
triggered: results.filter(r => r.triggered).length,
|
|
431
|
+
averageLatency: average(results.filter(r => r.triggered).map(r => r.latency)),
|
|
432
|
+
results
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
## Trigger Response Testing
|
|
440
|
+
|
|
441
|
+
```typescript
|
|
442
|
+
// Test trigger response modes
|
|
443
|
+
async function testTriggerResponses(webhookUrl: string): Promise<ResponseTestResult> {
|
|
444
|
+
// Test immediate response
|
|
445
|
+
const immediateStart = Date.now();
|
|
446
|
+
const immediateResponse = await fetch(webhookUrl, {
|
|
447
|
+
method: 'POST',
|
|
448
|
+
headers: { 'Content-Type': 'application/json' },
|
|
449
|
+
body: '{"test": "immediate"}'
|
|
450
|
+
});
|
|
451
|
+
const immediateTime = Date.now() - immediateStart;
|
|
452
|
+
|
|
453
|
+
// Test with workflow execution
|
|
454
|
+
const workflowStart = Date.now();
|
|
455
|
+
const workflowResponse = await fetch(`${webhookUrl}?waitForResponse=true`, {
|
|
456
|
+
method: 'POST',
|
|
457
|
+
headers: { 'Content-Type': 'application/json' },
|
|
458
|
+
body: '{"test": "workflow"}'
|
|
459
|
+
});
|
|
460
|
+
const workflowTime = Date.now() - workflowStart;
|
|
461
|
+
|
|
462
|
+
return {
|
|
463
|
+
immediateResponse: {
|
|
464
|
+
status: immediateResponse.status,
|
|
465
|
+
time: immediateTime,
|
|
466
|
+
body: await immediateResponse.text()
|
|
467
|
+
},
|
|
468
|
+
workflowResponse: {
|
|
469
|
+
status: workflowResponse.status,
|
|
470
|
+
time: workflowTime,
|
|
471
|
+
body: await workflowResponse.text()
|
|
472
|
+
},
|
|
473
|
+
responseMode: workflowTime > immediateTime + 100 ? 'workflow' : 'immediate'
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
## Test Scenarios
|
|
481
|
+
|
|
482
|
+
```yaml
|
|
483
|
+
Webhook Scenarios:
|
|
484
|
+
- name: Valid JSON POST
|
|
485
|
+
method: POST
|
|
486
|
+
payload: {"event": "test"}
|
|
487
|
+
expected: 200 OK
|
|
488
|
+
|
|
489
|
+
- name: Invalid JSON
|
|
490
|
+
method: POST
|
|
491
|
+
payload: "not valid json"
|
|
492
|
+
expected: 400 Bad Request
|
|
493
|
+
|
|
494
|
+
- name: Missing auth
|
|
495
|
+
method: POST
|
|
496
|
+
headers: {}
|
|
497
|
+
expected: 401 Unauthorized
|
|
498
|
+
|
|
499
|
+
- name: Large payload
|
|
500
|
+
method: POST
|
|
501
|
+
payload: [10MB of data]
|
|
502
|
+
expected: 413 Payload Too Large
|
|
503
|
+
|
|
504
|
+
Schedule Scenarios:
|
|
505
|
+
- name: Every 5 minutes
|
|
506
|
+
cron: "*/5 * * * *"
|
|
507
|
+
verify: 12 executions per hour
|
|
508
|
+
|
|
509
|
+
- name: Weekdays at 9 AM
|
|
510
|
+
cron: "0 9 * * 1-5"
|
|
511
|
+
verify: 5 executions per week
|
|
512
|
+
|
|
513
|
+
Polling Scenarios:
|
|
514
|
+
- name: 1 minute interval
|
|
515
|
+
interval: 60000
|
|
516
|
+
verify: ~60 polls per hour
|
|
517
|
+
|
|
518
|
+
- name: Deduplication
|
|
519
|
+
interval: 60000
|
|
520
|
+
inject_duplicate: true
|
|
521
|
+
verify: No duplicate processing
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
---
|
|
525
|
+
|
|
526
|
+
## Related Skills
|
|
527
|
+
- [n8n-workflow-testing-fundamentals](../n8n-workflow-testing-fundamentals/)
|
|
528
|
+
- [n8n-integration-testing-patterns](../n8n-integration-testing-patterns/)
|
|
529
|
+
- [n8n-security-testing](../n8n-security-testing/)
|
|
530
|
+
|
|
531
|
+
---
|
|
532
|
+
|
|
533
|
+
## Remember
|
|
534
|
+
|
|
535
|
+
**n8n triggers are the entry points** to workflows. Testing requires:
|
|
536
|
+
- Webhook: Payload handling, auth, HTTP methods
|
|
537
|
+
- Schedule: Cron accuracy, timezone handling
|
|
538
|
+
- Polling: Interval accuracy, deduplication
|
|
539
|
+
- Event: Event handling, filtering
|
|
540
|
+
|
|
541
|
+
**Key patterns:** Test with various payloads (valid, invalid, edge cases). Verify authentication enforcement. Check response times and reliability over time.
|