Use when running comprehensive WCAG accessibility audits with axe-core + pa11y + Lighthouse, generating context-aware remediation, or testing video accessibility. Supports 3-tier browser cascade with graceful degradation.
中文简介正在准备中。当前显示原文说明。
Webhook testing, schedule validation, event-driven triggers, and polling mechanism testing for n8n workflows. Use when testing how workflows are triggered.
中文简介正在准备中。当前显示原文说明。
实测评分 未实测
查看安装方法安装前可以查看交给 AI 代理的指令内容。
<default_to_action> When testing n8n triggers:
Quick Trigger Checklist:
Critical Success Factors:
| 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 |
| 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 |
// Test webhook with various payloads
async function testWebhook(webhookUrl: string): Promise<WebhookTestResult> {
const testPayloads = [
// Valid JSON
{ type: 'json', data: { event: 'test', timestamp: Date.now() } },
// Empty object
{ type: 'empty', data: {} },
// Large payload
{ type: 'large', data: { items: Array(1000).fill({ id: 1, name: 'test' }) } },
// Nested data
{ type: 'nested', data: { level1: { level2: { level3: { value: 'deep' } } } } },
// Special characters
{ type: 'special', data: { text: 'Hello <script>alert("xss")</script>' } }
];
const results: PayloadTestResult[] = [];
for (const payload of testPayloads) {
const startTime = Date.now();
try {
const response = await fetch(webhookUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload.data)
});
results.push({
payloadType: payload.type,
success: response.ok,
status: response.status,
responseTime: Date.now() - startTime,
responseBody: await response.text()
});
} catch (error) {
results.push({
payloadType: payload.type,
success: false,
error: error.message
});
}
}
return { webhookUrl, results };
}
// Test all HTTP methods
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;
}
// Test webhook authentication
async function testWebhookAuth(webhookUrl: string, authConfig: AuthConfig): Promise<AuthTestResult> {
const scenarios = [
// No auth
{ name: 'no-auth', headers: {} },
// Invalid auth
{ name: 'invalid-auth', headers: { 'Authorization': 'Bearer invalid-token' } },
// Valid auth
{ name: 'valid-auth', headers: { 'Authorization': `Bearer ${authConfig.token}` } },
// Expired auth
{ 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
};
}
// Validate cron expression
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)
};
}
// Get human-readable description
function describeCronExpression(expression: string): string {
// Common patterns
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';
}
// Calculate next execution times
function getNextCronExecutions(expression: string, count: number): Date[] {
const executions: Date[] = [];
let current = new Date();
// Simple implementation - use cron-parser library in production
for (let i = 0; i < count; i++) {
const next = calculateNextCronExecution(expression, current);
executions.push(next);
current = new Date(next.getTime() + 60000); // Move past this execution
}
return executions;
}
// Test schedule trigger reliability
async function testScheduleReliability(triggerId: string, testDuration: number): Promise<ScheduleTestResult> {
const startTime = Date.now();
const expectedExecutions: Date[] = [];
const actualExecutions: Date[] = [];
// Calculate expected execution times
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);
}
// Monitor actual executions
const executionListener = onExecutionStart(triggerId, (exec) => {
actualExecutions.push(new Date(exec.startedAt));
});
// Wait for test duration
await sleep(testDuration);
executionListener.stop();
// Compare expected vs actual
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
};
}
// Test polling trigger behavior
async function testPollingTrigger(triggerId: string, testConfig: PollingTestConfig): Promise<PollingTestResult> {
const { interval, testDuration, simulateDataChanges } = testConfig;
const pollEvents: PollEvent[] = [];
const triggeredExecutions: Execution[] = [];
// Monitor polling events
const pollListener = onPoll(triggerId, (event) => {
pollEvents.push({
timestamp: new Date(),
dataFound: event.hasNewData,
itemCount: event.items?.length || 0
});
});
// Monitor triggered executions
const execListener = onExecutionStart(triggerId, (exec) => {
triggeredExecutions.push(exec);
});
// Optionally simulate data changes
if (simulateDataChanges) {
for (const change of simulateDataChanges) {
setTimeout(() => {
injectTestData(triggerId, change.data);
}, change.at);
}
}
// Wait for test duration
await sleep(testDuration);
pollListener.stop();
execListener.stop();
// Analyze results
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
};
}
// Check if deduplication is working
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; // Duplicate found
}
processedIds.add(id);
}
}
}
return true;
}
// Test event-driven triggers
async function testEventTrigger(triggerId: string, eventConfig: EventTestConfig): Promise<EventTestResult> {
const { eventType, testEvents, timeout } = eventConfig;
const results: EventResult[] = [];
for (const testEvent of testEvents) {
// Emit test event
const startTime = Date.now();
await emitTestEvent(eventType, testEvent.payload);
// Wait for trigger
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
};
}
// Test trigger response modes
async function testTriggerResponses(webhookUrl: string): Promise<ResponseTestResult> {
// Test immediate response
const immediateStart = Date.now();
const immediateResponse = await fetch(webhookUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: '{"test": "immediate"}'
});
const immediateTime = Date.now() - immediateStart;
// Test with workflow execution
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'
};
}
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
n8n triggers are the entry points to workflows. Testing requires:
Key patterns: Test with various payloads (valid, invalid, edge cases). Verify authentication enforcement. Check response times and reliability over time.
还没有评价。欢迎分享你的使用感受。
无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。
还没有评论。来写第一条吧。
Use when running comprehensive WCAG accessibility audits with axe-core + pa11y + Lighthouse, generating context-aware remediation, or testing video accessibility. Supports 3-tier browser cascade with graceful degradation.
中文简介正在准备中。当前显示原文说明。
WCAG 2.2 compliance testing, screen reader validation, and inclusive design verification. Use when ensuring legal compliance (ADA, Section 508), testing for disabilities, or building accessible applications for 1 billion disabled users globally.
中文简介正在准备中。当前显示原文说明。
Master advanced AgentDB features including QUIC synchronization, multi-database management, custom distance metrics, hybrid search, and distributed systems integration. Use when building distributed AI systems, multi-agent coordination, or advanced vector search applications.
中文简介正在准备中。当前显示原文说明。
Create and train AI learning plugins with AgentDB's 9 reinforcement learning algorithms. Includes Decision Transformer, Q-Learning, SARSA, Actor-Critic, and more. Use when building self-learning agents, implementing RL, or optimizing agent behavior through experience.
中文简介正在准备中。当前显示原文说明。
Implement persistent memory patterns for AI agents using AgentDB. Includes session memory, long-term storage, pattern learning, and context management. Use when building stateful agents, chat systems, or intelligent assistants.
中文简介正在准备中。当前显示原文说明。
Optimize AgentDB performance with quantization (4-32x memory reduction), HNSW indexing (150x faster search), caching, and batch operations. Use when optimizing memory usage, improving search speed, or scaling to millions of vectors.
中文简介正在准备中。当前显示原文说明。