proffesor-for-testing/agentic-qe/n8n-integration-testing-patterns

Claude Code and agent skill by proffesor-for-testing/agentic-qe

Trust tier 2
  • community
LLM review pending
Source check pending

Checking that the SKILL.md file is still in the repository.

API contract testing, authentication flows, rate limit handling, and error scenario coverage for n8n integrations with external services. Use when testing n8n node integrations.

Install

npx vskill@latest install proffesor-for-testing/agentic-qe/n8n-integration-testing-patterns

SKILL.md

n8n Integration Testing Patterns

<default_to_action> When testing n8n integrations:

  1. VERIFY connectivity and authentication
  2. TEST all configured operations
  3. VALIDATE API response handling
  4. CHECK rate limit behavior
  5. CONFIRM error handling works

Quick Integration Checklist:

  • Credentials valid and not expired
  • API permissions sufficient for operations
  • Rate limits understood and respected
  • Error responses properly handled
  • Data formats match API expectations

Critical Success Factors:

  • Test in isolation before workflow integration
  • Verify OAuth token refresh works
  • Check API version compatibility
  • Monitor rate limit headers

</default_to_action>

Quick Reference Card

Common n8n Integrations
CategoryServicesAuth Type
CommunicationSlack, Teams, DiscordOAuth2, Webhook
Data StorageGoogle Sheets, AirtableOAuth2, API Key
CRMSalesforce, HubSpotOAuth2
Dev ToolsGitHub, Jira, LinearOAuth2, API Key
MarketingMailchimp, SendGridAPI Key
Authentication Types
TypeSetupRefresh
OAuth2User authorization flowAutomatic token refresh
API KeyManual key entryManual rotation
Basic AuthUsername/passwordNo refresh needed
Header AuthCustom headerManual rotation

Connectivity Testing

typescript
// Test integration connectivity
async function testIntegrationConnectivity(nodeName: string): Promise<ConnectivityResult> {
const node = await getNodeConfig(nodeName);
// Check credential exists
if (!node.credentials) {
return { connected: false, error: 'No credentials configured' };
}
// Test based on integration type
switch (getIntegrationType(node.type)) {
case 'slack':
return await testSlackConnectivity(node.credentials);
case 'google-sheets':
return await testGoogleSheetsConnectivity(node.credentials);
case 'jira':
return await testJiraConnectivity(node.credentials);
case 'github':
return await testGitHubConnectivity(node.credentials);
default:
return await testGenericAPIConnectivity(node);
}
}
// Slack connectivity test
async function testSlackConnectivity(credentials: any): Promise<ConnectivityResult> {
try {
const response = await fetch('https://slack.com/api/auth.test', {
headers: { 'Authorization': `Bearer ${credentials.accessToken}` }
});
const data = await response.json();
return {
connected: data.ok,
workspace: data.team,
user: data.user,
scopes: data.response_metadata?.scopes || []
};
} catch (error) {
return { connected: false, error: error.message };
}
}
// Google Sheets connectivity test
async function testGoogleSheetsConnectivity(credentials: any): Promise<ConnectivityResult> {
try {
const response = await fetch('https://www.googleapis.com/drive/v3/about?fields=user', {
headers: { 'Authorization': `Bearer ${credentials.accessToken}` }
});
if (response.status === 401) {
// Try refresh
const refreshed = await refreshOAuthToken(credentials);
if (refreshed) {
return testGoogleSheetsConnectivity({ ...credentials, accessToken: refreshed });
}
return { connected: false, error: 'Token expired, refresh failed' };
}
const data = await response.json();
return { connected: true, user: data.user };
} catch (error) {
return { connected: false, error: error.message };
}
}

API Operation Testing

typescript
// Test integration operations
async function testIntegrationOperations(nodeName: string): Promise<OperationResult[]> {
const node = await getNodeConfig(nodeName);
const operations = getNodeOperations(node.type);
const results: OperationResult[] = [];
for (const operation of operations) {
const testData = generateTestData(node.type, operation);
try {
const startTime = Date.now();
const response = await executeOperation(node, operation, testData);
results.push({
operation,
success: true,
responseTime: Date.now() - startTime,
responseStatus: response.status,
dataValid: validateResponseData(response.data, operation)
});
} catch (error) {
results.push({
operation,
success: false,
error: error.message,
errorType: classifyError(error)
});
}
}
return results;
}
// Generate test data for operations
function generateTestData(nodeType: string, operation: string): any {
const testDataMap = {
'slack': {
'postMessage': {
channel: 'C123456',
text: 'Test message from n8n integration test'
},
'uploadFile': {
channels: 'C123456',
content: 'Test file content',
filename: 'test.txt'
}
},
'google-sheets': {
'appendData': {
spreadsheetId: 'test-spreadsheet-id',
range: 'Sheet1!A:Z',
values: [['Test', 'Data', new Date().toISOString()]]
},
'readRows': {
spreadsheetId: 'test-spreadsheet-id',
range: 'Sheet1!A1:Z10'
}
},
'jira': {
'createIssue': {
project: 'TEST',
issueType: 'Task',
summary: 'Test issue from n8n',
description: 'Created by integration test'
},
'updateIssue': {
issueKey: 'TEST-1',
fields: { summary: 'Updated by n8n test' }
}
}
};
return testDataMap[nodeType]?.[operation] || {};
}

Authentication Testing

OAuth2 Flow Testing
typescript
// Test OAuth2 authentication
async function testOAuth2Authentication(credentials: any): Promise<OAuth2Result> {
const result: OAuth2Result = {
tokenValid: false,
refreshWorking: false,
scopes: [],
expiresIn: 0
};
// Test current token
const tokenTest = await testAccessToken(credentials.accessToken);
result.tokenValid = tokenTest.valid;
result.scopes = tokenTest.scopes;
// Check expiration
if (credentials.expiresAt) {
result.expiresIn = new Date(credentials.expiresAt).getTime() - Date.now();
result.expiresSoon = result.expiresIn < 3600000; // Less than 1 hour
}
// Test refresh token
if (credentials.refreshToken) {
try {
const newToken = await refreshOAuthToken(credentials);
result.refreshWorking = !!newToken;
} catch (error) {
result.refreshError = error.message;
}
}
return result;
}
// Test required scopes
async function testRequiredScopes(credentials: any, requiredScopes: string[]): Promise<ScopeResult> {
const currentScopes = await getTokenScopes(credentials.accessToken);
const missingScopes = requiredScopes.filter(s => !currentScopes.includes(s));
return {
hasAllScopes: missingScopes.length === 0,
currentScopes,
missingScopes,
recommendation: missingScopes.length > 0
? `Re-authorize with scopes: ${missingScopes.join(', ')}`
: null
};
}
API Key Testing
typescript
// Test API key validity
async function testAPIKey(integration: string, apiKey: string): Promise<APIKeyResult> {
const endpoints = {
'sendgrid': 'https://api.sendgrid.com/v3/user/profile',
'mailchimp': 'https://us1.api.mailchimp.com/3.0/ping',
'airtable': 'https://api.airtable.com/v0/meta/whoami'
};
const endpoint = endpoints[integration];
if (!endpoint) {
return { valid: false, error: 'Unknown integration' };
}
try {
const response = await fetch(endpoint, {
headers: { 'Authorization': `Bearer ${apiKey}` }
});
return {
valid: response.status === 200,
status: response.status,
rateLimit: extractRateLimitInfo(response.headers)
};
} catch (error) {
return { valid: false, error: error.message };
}
}

Rate Limit Testing

typescript
// Test rate limit handling
async function testRateLimits(nodeName: string, requestCount: number): Promise<RateLimitResult> {
const results: RequestResult[] = [];
let rateLimitHit = false;
let retryAfter = 0;
for (let i = 0; i < requestCount; i++) {
const startTime = Date.now();
const response = await makeRequest(nodeName);
results.push({
requestNumber: i + 1,
status: response.status,
responseTime: Date.now() - startTime,
rateLimitRemaining: response.headers['x-ratelimit-remaining'],
rateLimitLimit: response.headers['x-ratelimit-limit']
});
if (response.status === 429) {
rateLimitHit = true;
retryAfter = parseInt(response.headers['retry-after'] || '60');
break;
}
// Small delay between requests
await sleep(100);
}
return {
requestsMade: results.length,
rateLimitHit,
retryAfter,
results,
recommendation: rateLimitHit
? `Implement exponential backoff, retry after ${retryAfter}s`
: 'Rate limit not reached, consider increasing request count for thorough testing'
};
}
// Extract rate limit info from headers
function extractRateLimitInfo(headers: Headers): RateLimitInfo {
return {
limit: headers.get('x-ratelimit-limit'),
remaining: headers.get('x-ratelimit-remaining'),
reset: headers.get('x-ratelimit-reset'),
retryAfter: headers.get('retry-after')
};
}

Error Handling Testing

typescript
// Test error scenarios
async function testErrorScenarios(nodeName: string): Promise<ErrorTestResult[]> {
const scenarios = [
{ name: 'Invalid credentials', modify: { credentials: null } },
{ name: 'Invalid endpoint', modify: { url: 'https://invalid.example.com' } },
{ name: 'Timeout', modify: { timeout: 1 } },
{ name: 'Invalid data', modify: { data: { invalid: true } } },
{ name: 'Not found', modify: { resourceId: 'nonexistent-123' } },
{ name: 'Permission denied', modify: { scope: 'read-only' } }
];
const results: ErrorTestResult[] = [];
for (const scenario of scenarios) {
try {
const response = await executeWithModification(nodeName, scenario.modify);
results.push({
scenario: scenario.name,
errorHandled: response.status >= 400,
errorCode: response.status,
errorMessage: response.data?.error?.message,
retried: response.metadata?.retryCount > 0
});
} catch (error) {
results.push({
scenario: scenario.name,
errorHandled: true,
exceptionThrown: true,
errorType: error.constructor.name,
errorMessage: error.message
});
}
}
return results;
}
// Classify error types
function classifyError(error: any): string {
if (error.status === 401 || error.status === 403) return 'authentication';
if (error.status === 404) return 'not-found';
if (error.status === 429) return 'rate-limit';
if (error.status >= 500) return 'server-error';
if (error.code === 'ETIMEDOUT') return 'timeout';
if (error.code === 'ECONNREFUSED') return 'connection';
return 'unknown';
}

Integration-Specific Patterns

Slack Integration
typescript
const slackTestPatterns = {
// Test message posting
testPostMessage: async (credentials) => {
return await fetch('https://slack.com/api/chat.postMessage', {
method: 'POST',
headers: {
'Authorization': `Bearer ${credentials.accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
channel: 'C123456',
text: 'Integration test message'
})
});
},
// Test file upload
testFileUpload: async (credentials) => {
const formData = new FormData();
formData.append('channels', 'C123456');
formData.append('content', 'Test file content');
formData.append('filename', 'test.txt');
return await fetch('https://slack.com/api/files.upload', {
method: 'POST',
headers: { 'Authorization': `Bearer ${credentials.accessToken}` },
body: formData
});
},

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 96 of 100Pattern checks on the skill's files.
  • Model reviewNot runA model review is scheduled for the next rescan.

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
464
Repository forks
87
Repository npm downloads, 7 days
10,925
7-day trend score
53

Stars and forks are for the whole GitHub repository, not this skill alone. Downloads are for the repository's npm package. Refreshed 25 Aug 2026, 2 months ago.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/proffesor-for-testing/agentic-qe/n8n-integration-testing-patterns/badge)](https://verified-skill.com/skills/proffesor-for-testing/agentic-qe/n8n-integration-testing-patterns)

Something wrong with this skill or its page? Tell us.