Skip to main content Skills Marketplace Discover and explore AI skills built by the community.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Copy promptShow prompt details A direct command skips the review prompt. Inspect the source before running it.
npx skills add https://github.com/proffesor-for-testing/agentic-qe --skill n8n-trigger-testing-strategiesThe command stays on one line. Scroll horizontally to inspect it before copying.
Prefer a local copy? Download the files currently available to SkillsMP.
Download Zip Downloading... More from this repository Ruflo is a multi-agent orchestration platform for AI coding agents (Claude Code, Cursor, Codex, Copilot, Gemini, Amp, +12 more). Use this skill when the user wants to (1) install/init ruflo in a project, (2) run multi-agent swarms with hierarchical coordination, (3) use ruflo's 314+ MCP tools for memory, routing, hooks, sub-agents, or workflows, (4) check ruflo status/version/doctor health, or (5) discover which of ruflo's 30+ plugins fits their task.
Build dependency-aware execution plans for complex Agentic QE, Ruflo, integration, migration, or multi-stream engineering programs. Use when Codex must turn research or requirements into phased work, select a small AQE fleet, map critical paths and parallel streams, define acceptance gates, or sequence risky changes. Use aqe-plan-quality instead when the primary output is only a test or quality plan.
Conduct evidence-first technical research for Agentic QE, Ruflo, related ruvnet projects, or external tools. Use when Codex must investigate a repository, compare current upstream changes, trace dependencies and history, distinguish verified facts from inference, or synthesize findings into actionable engineering recommendations. Do not use for a simple known-answer lookup or an implementation-only task.
Related occupations SOC
Based on SOC occupation classification
name n8n-trigger-testing-strategies description Webhook testing, schedule validation, event-driven triggers, and polling mechanism testing for n8n workflows. Use when testing how workflows are triggered. category n8n-testing priority high tokenEstimate 1000 agents ["n8n-trigger-test"] implementation_status production optimization_version 1 last_optimized "2025-12-15T00:00:00.000Z" dependencies [] quick_reference_card true tags ["n8n","triggers","webhook","schedule","cron","polling","testing"] trust_tier 3 validation {"schema_path":"schemas/output.json","validator_path":"scripts/validate-config.json","eval_path":"evals/n8n-trigger-testing-strategies.yaml"}
n8n Trigger Testing Strategies
<default_to_action>
When testing n8n triggers:
IDENTIFY trigger type (webhook, schedule, polling, event)
TEST with various valid payloads
VERIFY authentication and authorization
CHECK error handling for invalid inputs
MEASURE response time and reliability
Quick Trigger Checklist:
Trigger activates workflow correctly
Payload parsed and validated
Authentication enforced (if configured)
Error responses are informative
Response time is acceptable
Critical Success Factors:
Test edge cases (empty payloads, large payloads)
Verify idempotency where needed
Check timeout handling
Monitor for missed triggers
</default_to_action>
Quick Reference Card
n8n Trigger Types
Type Use Case Testing Focus Webhook External HTTP calls Payloads, auth, methods Schedule Timed execution Cron accuracy, timezone Polling Check for changes Interval, deduplication Event Service events Event handling, filtering
Common Webhook Configurations
Setting Options Impact HTTP Method GET, POST, PUT, DELETE Request handling Authentication None, Basic, Header Security Response Mode Immediately, Last Node, Custom Response timing Path Custom URL path Endpoint identification
Webhook Testing
Basic Webhook Test
async function testWebhook ( : ): < > {
testPayloads = [
{ : , : { : , : . () } },
{ : , : {} },
{ : , : { : ( ). ({ : , : }) } },
{ : , : { : { : { : { : } } } } },
{ : , : { : } }
];
: [] = [];
( payload testPayloads) {
startTime = . ();
{
response = (webhookUrl, {
: ,
: { : },
: . (payload. )
});
results. ({
: payload. ,
: response. ,
: response. ,
: . () - startTime,
: response. ()
});
} (error) {
results. ({
: payload. ,
: ,
: error.
});
}
}
{ webhookUrl, results };
}
webhookUrl
string
Promise
WebhookTestResult
const
type
'json'
data
event
'test'
timestamp
Date
now
type
'empty'
data
type
'large'
data
items
Array
1000
fill
id
1
name
'test'
type
'nested'
data
level1
level2
level3
value
'deep'
type
'special'
data
text
'Hello <script>alert("xss")</script>'
const
results
PayloadTestResult
for
const
of
const
Date
now
try
const
await
fetch
method
'POST'
headers
'Content-Type'
'application/json'
body
JSON
stringify
data
push
payloadType
type
success
ok
status
status
responseTime
Date
now
responseBody
await
text
catch
push
payloadType
type
success
false
error
message
return
HTTP Method Testing
async function testWebhookMethods (webhookUrl : string ): Promise <MethodTestResult []> {
const methods = ['GET' , 'POST' , 'PUT' , 'PATCH' , 'DELETE' , 'HEAD' , 'OPTIONS' ];
const results : MethodTestResult [] = [];
for (const method of methods) {
try {
const response = await fetch (webhookUrl, {
method,
headers : { 'Content-Type' : 'application/json' },
body : ['GET' , 'HEAD' , 'OPTIONS' ].includes (method) ? undefined : '{}'
});
results.push ({
method,
allowed : response.ok || response.status !== 405 ,
status : response.status ,
statusText : response.statusText
});
} catch (error) {
results.push ({
method,
allowed : false ,
error : error.message
});
}
}
return results;
}
Authentication Testing
async function testWebhookAuth (webhookUrl : string , authConfig : AuthConfig ): Promise <AuthTestResult > {
const scenarios = [
{ name : 'no-auth' , headers : {} },
{ name : 'invalid-auth' , headers : { 'Authorization' : 'Bearer invalid-token' } },
{ name : 'valid-auth' , headers : { 'Authorization' : `Bearer ${authConfig.token} ` } },
{ name : 'expired-auth' , headers : { 'Authorization' : `Bearer ${authConfig.expiredToken} ` } }
];
const results : AuthScenarioResult [] = [];
for (const scenario of scenarios) {
const response = await fetch (webhookUrl, {
method : 'POST' ,
headers : {
'Content-Type' : 'application/json' ,
...scenario.headers
},
body : '{}'
});
results.push ({
scenario : scenario.name ,
status : response.status ,
authenticated : response.ok ,
errorMessage : response.ok ? null : await response.text ()
});
}
return {
authRequired : !results.find (r => r.scenario === 'no-auth' )?.authenticated ,
invalidRejected : !results.find (r => r.scenario === 'invalid-auth' )?.authenticated ,
validAccepted : results.find (r => r.scenario === 'valid-auth' )?.authenticated ,
results
};
}
Schedule Testing
Cron Expression Validation
function validateCronExpression (expression : string ): CronValidationResult {
const parts = expression.trim ().split (/\s+/ );
if (parts.length < 5 || parts.length > 6 ) {
return {
valid : false ,
error : `Expected 5-6 parts, got ${parts.length} `
};
}
const [minute, hour, dayOfMonth, month, dayOfWeek, year] = parts;
const validations = [
{ field : 'minute' , value : minute, range : [0 , 59 ] },
{ field : 'hour' , value : hour, range : [0 , 23 ] },
{ field : 'dayOfMonth' , value : dayOfMonth, range : [1 , 31 ] },
{ field : 'month' , value : month, range : [1 , 12 ] },
{ field : 'dayOfWeek' , value : dayOfWeek, range : [0 , 7 ] }
];
for (const v of validations) {
const result = validateCronField (v.value , v.range );
if (!result.valid ) {
return { valid : false , error : `Invalid ${v.field} : ${result.error} ` };
}
}
return {
valid : true ,
description : describeCronExpression (expression),
nextExecutions : getNextCronExecutions (expression, 5 )
};
}
function describeCronExpression (expression : string ): string {
const patterns : Record <string , string > = {
'* * * * *' : 'Every minute' ,
'*/5 * * * *' : 'Every 5 minutes' ,
'0 * * * *' : 'Every hour' ,
'0 0 * * *' : 'Every day at midnight' ,
'0 9 * * 1-5' : 'Weekdays at 9:00 AM' ,
'0 0 1 * *' : 'First day of every month' ,
'0 0 * * 0' : 'Every Sunday at midnight'
};
return patterns[expression] || 'Custom schedule' ;
}
function getNextCronExecutions (expression : string , count : number ): Date [] {
const executions : Date [] = [];
let current = new Date ();
for (let i = 0 ; i < count; i++) {
const next = calculateNextCronExecution (expression, current);
executions.push (next);
current = new Date (next.getTime () + 60000 );
}
return executions;
}
Schedule Reliability Testing
async function testScheduleReliability (triggerId : string , testDuration : number ): Promise <ScheduleTestResult > {
const startTime = Date .now ();
const expectedExecutions : Date [] = [];
const actualExecutions : Date [] = [];
const cronExpression = await getTriggerCronExpression (triggerId);
let checkTime = new Date (startTime);
while (checkTime.getTime () < startTime + testDuration) {
const nextExec = calculateNextCronExecution (cronExpression, checkTime);
if (nextExec.getTime () < startTime + testDuration) {
expectedExecutions.push (nextExec);
}
checkTime = new Date (nextExec.getTime () + 60000 );
}
const executionListener = onExecutionStart (triggerId, (exec ) => {
actualExecutions.push (new Date (exec.startedAt ));
});
await sleep (testDuration);
executionListener.stop ();
const comparison = compareExecutions (expectedExecutions, actualExecutions);
return {
testDuration,
expectedCount : expectedExecutions.length ,
actualCount : actualExecutions.length ,
missedExecutions : comparison.missed ,
extraExecutions : comparison.extra ,
timingAccuracy : comparison.timingAccuracy ,
reliability : (actualExecutions.length / expectedExecutions.length ) * 100
};
}
Polling Trigger Testing
async function testPollingTrigger (triggerId : string , testConfig : PollingTestConfig ): Promise <PollingTestResult > {
const { interval, testDuration, simulateDataChanges } = testConfig;
const pollEvents : PollEvent [] = [];
const triggeredExecutions : Execution [] = [];
const pollListener = onPoll (triggerId, (event ) => {
pollEvents.push ({
timestamp : new Date (),
dataFound : event.hasNewData ,
itemCount : event.items ?.length || 0
});
});
const execListener = onExecutionStart (triggerId, (exec ) => {
triggeredExecutions.push (exec);
});
if (simulateDataChanges) {
for (const change of simulateDataChanges) {
setTimeout (() => {
injectTestData (triggerId, change.data );
}, change.at );
}
}
await sleep (testDuration);
pollListener.stop ();
execListener.stop ();
const expectedPolls = Math .floor (testDuration / interval);
const actualPolls = pollEvents.length ;
return {
interval,
testDuration,
expectedPolls,
actualPolls,
pollAccuracy : (actualPolls / expectedPolls) * 100 ,
averageInterval : calculateAverageInterval (pollEvents),
executionsTriggered : triggeredExecutions.length ,
deduplicationWorking : checkDeduplication (triggeredExecutions),
pollEvents
};
}
function checkDeduplication (executions : Execution [] ): boolean {
const processedIds = new Set ();
for (const exec of executions) {
const itemIds = exec.data ?.resultData ?.runData ?.Trigger ?.[0 ]?.data ?.main ?.[0 ]
?.map (item => item.json ?.id );
if (itemIds) {
for (const id of itemIds) {
if (processedIds.has (id)) {
return false ;
}
processedIds.add (id);
}
}
}
return true ;
}
Event Trigger Testing
async function testEventTrigger (triggerId : string , eventConfig : EventTestConfig ): Promise <EventTestResult > {
const { eventType, testEvents, timeout } = eventConfig;
const results : EventResult [] = [];
for (const testEvent of testEvents) {
const startTime = Date .now ();
await emitTestEvent (eventType, testEvent.payload );
try {
const execution = await waitForTrigger (triggerId, timeout);
results.push ({
eventType : testEvent.type ,
triggered : true ,
latency : Date .now () - startTime,
payloadReceived : execution.data ?.inputData
});
} catch (error) {
results.push ({
eventType : testEvent.type ,
triggered : false ,
error : error.message
});
}
}
return {
eventType,
testsRun : testEvents.length ,
triggered : results.filter (r => r.triggered ).length ,
averageLatency : average (results.filter (r => r.triggered ).map (r => r.latency )),
results
};
}
Trigger Response Testing
async function testTriggerResponses (webhookUrl : string ): Promise <ResponseTestResult > {
const immediateStart = Date .now ();
const immediateResponse = await fetch (webhookUrl, {
method : 'POST' ,
headers : { 'Content-Type' : 'application/json' },
body : '{"test": "immediate"}'
});
const immediateTime = Date .now () - immediateStart;
const workflowStart = Date .now ();
const workflowResponse = await fetch (`${webhookUrl} ?waitForResponse=true` , {
method : 'POST' ,
headers : { 'Content-Type' : 'application/json' },
body : '{"test": "workflow"}'
});
const workflowTime = Date .now () - workflowStart;
return {
immediateResponse : {
status : immediateResponse.status ,
time : immediateTime,
body : await immediateResponse.text ()
},
workflowResponse : {
status : workflowResponse.status ,
time : workflowTime,
body : await workflowResponse.text ()
},
responseMode : workflowTime > immediateTime + 100 ? 'workflow' : 'immediate'
};
}
Test Scenarios Webhook Scenarios:
- name: Valid JSON POST
method: POST
payload: {"event": "test" }
expected: 200 OK
- name: Invalid JSON
method: POST
payload: "not valid json"
expected: 400 Bad Request
- name: Missing auth
method: POST
headers: {}
expected: 401 Unauthorized
- name: Large payload
method: POST
payload: [10MB of data ]
expected: 413 Payload Too Large
Schedule Scenarios:
- name: Every 5 minutes
cron: "*/5 * * * *"
verify: 12 executions per hour
- name: Weekdays at 9 AM
cron: "0 9 * * 1-5"
verify: 5 executions per week
Polling Scenarios:
- name: 1 minute interval
interval: 60000
verify: ~60 polls per hour
- name: Deduplication
interval: 60000
inject_duplicate: true
verify: No duplicate processing
Related Skills
Remember n8n triggers are the entry points to workflows. Testing requires:
Webhook: Payload handling, auth, HTTP methods
Schedule: Cron accuracy, timezone handling
Polling: Interval accuracy, deduplication
Event: Event handling, filtering
Key patterns: Test with various payloads (valid, invalid, edge cases). Verify authentication enforcement. Check response times and reliability over time.