import { createServer } from 'node:http'; import { WebhookDispatcher } from '../src/index.js'; describe('WebhookDispatcher', () => { it('delivers signed webhook payloads', async () => { const payloads: string[] = []; const headers: string[] = []; const server = createServer((request, response) => { let body = ''; request.on('data', (chunk) => { body += chunk.toString(); }); request.on('end', () => { payloads.push(body); headers.push(String(request.headers['x-jobqueue-signature'])); response.writeHead(202).end(); }); }); await new Promise((resolve) => { server.listen(0, '127.0.0.1', () => resolve()); }); const address = server.address(); if (!address || typeof address === 'string') { throw new Error('Server address unavailable'); } const dispatcher = new WebhookDispatcher({ url: `http://127.0.0.1:${address.port}/hook`, secret: 'top-secret', events: ['job:completed'], }); try { const result = await dispatcher.dispatch('job:completed', { id: 'job-1', status: 'completed', data: { url: 'https://example.com' }, currentPhase: null, phases: [], phaseResults: {}, progress: 100, progressMessage: null, error: null, retryCount: 0, maxAttempts: 1, webhookUrl: null, webhookSent: false, createdAt: new Date().toISOString(), startedAt: null, completedAt: new Date().toISOString(), updatedAt: new Date().toISOString(), scheduledAt: null, cancelledAt: null, }); expect(result.status).toBe(202); expect(payloads).toHaveLength(1); expect(payloads[0]).toContain('"event":"job:completed"'); expect(headers[0]).toMatch(/^[a-f0-9]{64}$/); } finally { await new Promise((resolve, reject) => { server.close((error) => { if (error) { reject(error); return; } resolve(); }); }); } }); });