n8n-integration-testing-patterns
API contract testing, authentication flows, rate limit handling, and error scenario coverage for n8n integrations with external services. Use when testing n8n node integrations.
What this skill does
# 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
| Category | Services | Auth Type |
|----------|----------|-----------|
| **Communication** | Slack, Teams, Discord | OAuth2, Webhook |
| **Data Storage** | Google Sheets, Airtable | OAuth2, API Key |
| **CRM** | Salesforce, HubSpot | OAuth2 |
| **Dev Tools** | GitHub, Jira, Linear | OAuth2, API Key |
| **Marketing** | Mailchimp, SendGrid | API Key |
### Authentication Types
| Type | Setup | Refresh |
|------|-------|---------|
| **OAuth2** | User authorization flow | Automatic token refresh |
| **API Key** | Manual key entry | Manual rotation |
| **Basic Auth** | Username/password | No refresh needed |
| **Header Auth** | Custom header | Manual 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, requestCRelated in n8n-testing
n8n-expression-testing
Includedn8n expression syntax validation, context-aware testing, common pitfalls detection, and performance optimization. Use when validating n8n expressions and data transformations.
n8n-security-testing
IncludedCredential exposure detection, OAuth flow validation, API key management testing, and data sanitization verification for n8n workflows. Use when validating n8n workflow security.
n8n-trigger-testing-strategies
IncludedWebhook testing, schedule validation, event-driven triggers, and polling mechanism testing for n8n workflows. Use when testing how workflows are triggered.
n8n-workflow-testing-fundamentals
IncludedComprehensive n8n workflow testing including execution lifecycle, node connection patterns, data flow validation, and error handling strategies. Use when testing n8n workflow automation applications.