#!/usr/bin/env node
/**
* Webhook Testing Script
*
* This script tests all webhook endpoints with sample payloads
* to verify they're working correctly.
*/
import axios from 'axios';
import crypto from 'crypto';
const BASE_URL = process.env.WEBHOOK_BASE_URL || 'http://localhost:3000';
// Test payloads for each webhook type
const testPayloads = {
github: {
ref: 'refs/heads/main',
repository: {
name: 'test-repo',
full_name: 'user/test-repo',
html_url: 'https://github.com/user/test-repo'
},
pusher: {
name: 'testuser',
email: 'test@example.com'
},
commits: [{
id: 'abc123',
message: 'Test commit',
author: {
name: 'Test User',
email: 'test@example.com'
}
}]
},
notion: {
object: 'event',
id: 'test-event-id',
type: 'page.created',
created_time: new Date().toISOString(),
page: {
id: 'test-page-id',
object: 'page',
created_time: new Date().toISOString(),
properties: {
title: {
type: 'title',
title: [{ text: { content: 'Test Page' } }]
}
}
}
},
calendar: {
kind: 'api#channel',
id: 'test-channel-id',
resourceId: 'test-resource-id',
type: 'web_hook',
expiration: (Date.now() + 86400000).toString()
},
slack: {
type: 'event_callback',
team_id: 'T12345678',
api_app_id: 'A12345678',
event: {
type: 'message',
channel: 'C1234567890',
user: 'U1234567890',
text: 'Hello from webhook test!',
ts: (Date.now() / 1000).toString()
}
}
};
// Generate GitHub signature
function generateGitHubSignature(payload, secret) {
return 'sha256=' + crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
}
// Test individual webhook
async function testWebhook(type, payload, headers = {}) {
const url = `${BASE_URL}/webhook/${type}`;
console.log(`\nπ§ͺ Testing ${type.toUpperCase()} webhook...`);
console.log(`π URL: ${url}`);
try {
const response = await axios.post(url, payload, {
headers: {
'Content-Type': 'application/json',
...headers
},
timeout: 10000
});
console.log(`β
${type.toUpperCase()} webhook test passed`);
console.log(`π Status: ${response.status}`);
console.log(`π Response: ${JSON.stringify(response.data, null, 2)}`);
return true;
} catch (error) {
console.log(`β ${type.toUpperCase()} webhook test failed`);
if (error.response) {
console.log(`π Status: ${error.response.status}`);
console.log(`π Error: ${JSON.stringify(error.response.data, null, 2)}`);
} else {
console.log(`π Connection Error: ${error.message}`);
}
return false;
}
}
// Test health endpoint
async function testHealth() {
console.log('\nπ₯ Testing health endpoint...');
try {
const response = await axios.get(`${BASE_URL}/health`);
console.log('β
Health check passed');
console.log(`π Status: ${response.status}`);
console.log(`π Response: ${JSON.stringify(response.data, null, 2)}`);
return true;
} catch (error) {
console.log('β Health check failed');
console.log(`π Error: ${error.message}`);
return false;
}
}
// Main test runner
async function runTests() {
console.log('π CodePilot MCP Webhook Testing');
console.log('================================');
console.log(`π― Target URL: ${BASE_URL}`);
const results = {
health: false,
github: false,
notion: false,
calendar: false,
slack: false
};
// Test health endpoint first
results.health = await testHealth();
if (!results.health) {
console.log('\nβ Health check failed. Ensure the server is running.');
process.exit(1);
}
// Test GitHub webhook
const githubSecret = process.env.GITHUB_WEBHOOK_SECRET || 'test-secret';
const githubSignature = generateGitHubSignature(testPayloads.github, githubSecret);
results.github = await testWebhook('github', testPayloads.github, {
'X-GitHub-Event': 'push',
'X-Hub-Signature-256': githubSignature,
'X-GitHub-Delivery': 'test-delivery-id'
});
// Test Notion webhook
results.notion = await testWebhook('notion', testPayloads.notion, {
'Notion-Version': '2022-06-28'
});
// Test Calendar webhook
results.calendar = await testWebhook('calendar', testPayloads.calendar, {
'X-Goog-Channel-ID': 'test-channel',
'X-Goog-Resource-ID': 'test-resource',
'X-Goog-Channel-Token': 'test-token'
});
// Test Slack webhook
results.slack = await testWebhook('slack', testPayloads.slack, {
'X-Slack-Request-Timestamp': Math.floor(Date.now() / 1000).toString(),
'X-Slack-Signature': 'v0=test-signature'
});
// Summary
console.log('\nπ Test Results Summary');
console.log('=======================');
Object.entries(results).forEach(([test, passed]) => {
const status = passed ? 'β
PASS' : 'β FAIL';
console.log(`${test.padEnd(10)} ${status}`);
});
const totalTests = Object.keys(results).length;
const passedTests = Object.values(results).filter(Boolean).length;
console.log(`\nπ Overall: ${passedTests}/${totalTests} tests passed`);
if (passedTests === totalTests) {
console.log('π All webhook tests passed!');
process.exit(0);
} else {
console.log('β οΈ Some webhook tests failed. Check the logs above.');
process.exit(1);
}
}
// Handle CLI arguments
if (process.argv.includes('--help') || process.argv.includes('-h')) {
console.log(`
CodePilot MCP Webhook Testing Script
Usage:
node scripts/test-webhooks.js [options]
Options:
--help, -h Show this help message
--url <url> Set the base URL for testing (default: http://localhost:3000)
Environment Variables:
WEBHOOK_BASE_URL Base URL for webhook testing
GITHUB_WEBHOOK_SECRET Secret for GitHub webhook signature validation
Examples:
# Test local development server
node scripts/test-webhooks.js
# Test production deployment
WEBHOOK_BASE_URL=https://your-app.run.app node scripts/test-webhooks.js
# Test with custom URL
node scripts/test-webhooks.js --url https://example.com
`);
process.exit(0);
}
// Parse URL argument
const urlArgIndex = process.argv.indexOf('--url');
if (urlArgIndex !== -1 && process.argv[urlArgIndex + 1]) {
process.env.WEBHOOK_BASE_URL = process.argv[urlArgIndex + 1];
}
// Run the tests
runTests().catch(console.error);