Skip to main content 홈 크리에이터 proffesor-for-testing agentic-qe n8n-trigger-testing-strategies
n8n-trigger-testing-strategies Webhook testing, schedule validation, event-driven triggers, and polling mechanism testing for n8n workflows. Use when testing how workflows are triggered.
설치로 이동 Skills Marketplace 커뮤니티가 만든 AI 스킬을 발견하고 탐색하세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/proffesor-for-testing/agentic-qe --skill n8n-trigger-testing-strategies명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
Zip 다운로드 다운로드 중... 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.
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.