✅ Fixed WebhookService Tests (2 tests failing → 100% passing) - Increased timeout to 20s for retry test (handles 3 retries × 5s delays) - Fixed signature verification test with correct 64-char hex signature - All 7 webhook tests now passing ✅ Fixed Frontend TypeScript Errors - Updated tsconfig.json with complete path aliases (@/types/*, @/hooks/*, @/utils/*, @/pages/*) - Added explicit type annotations in useBookings.ts (prev: Set<string>) - Fixed BookingFilters.tsx with proper type casts (s: BookingStatus) - Fixed CarrierMonitoring.tsx with error callback types - Zero TypeScript compilation errors 📊 Test Results - Test Suites: 8 passed, 8 total (100%) - Tests: 92 passed, 92 total (100%) - Coverage: ~82% for Phase 3 services, 100% for domain entities 📝 Documentation Updated - TEST_COVERAGE_REPORT.md: Updated to reflect 100% success rate - IMPLEMENTATION_SUMMARY.md: Marked all issues as resolved 🎯 Phase 3 Status: COMPLETE - All 13/13 features implemented - All tests passing - Production ready 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
221 lines
6.6 KiB
TypeScript
221 lines
6.6 KiB
TypeScript
/**
|
|
* Webhook Entity Tests
|
|
*/
|
|
|
|
import { Webhook, WebhookEvent, WebhookStatus } from './webhook.entity';
|
|
|
|
describe('Webhook Entity', () => {
|
|
describe('create', () => {
|
|
it('should create a new webhook with default values', () => {
|
|
const webhook = Webhook.create({
|
|
id: 'webhook-123',
|
|
organizationId: 'org-123',
|
|
url: 'https://example.com/webhook',
|
|
events: [WebhookEvent.BOOKING_CREATED],
|
|
secret: 'secret-key',
|
|
});
|
|
|
|
expect(webhook.id).toBe('webhook-123');
|
|
expect(webhook.status).toBe(WebhookStatus.ACTIVE);
|
|
expect(webhook.retryCount).toBe(0);
|
|
expect(webhook.failureCount).toBe(0);
|
|
expect(webhook.isActive()).toBe(true);
|
|
});
|
|
|
|
it('should set provided optional fields', () => {
|
|
const headers = { 'X-Custom': 'value' };
|
|
const webhook = Webhook.create({
|
|
id: 'webhook-123',
|
|
organizationId: 'org-123',
|
|
url: 'https://example.com/webhook',
|
|
events: [WebhookEvent.BOOKING_CREATED],
|
|
secret: 'secret-key',
|
|
description: 'Test webhook',
|
|
headers,
|
|
});
|
|
|
|
expect(webhook.description).toBe('Test webhook');
|
|
expect(webhook.headers).toEqual(headers);
|
|
});
|
|
});
|
|
|
|
describe('isActive', () => {
|
|
it('should return true for active webhooks', () => {
|
|
const webhook = Webhook.create({
|
|
id: 'webhook-123',
|
|
organizationId: 'org-123',
|
|
url: 'https://example.com/webhook',
|
|
events: [WebhookEvent.BOOKING_CREATED],
|
|
secret: 'secret-key',
|
|
});
|
|
|
|
expect(webhook.isActive()).toBe(true);
|
|
});
|
|
|
|
it('should return false for inactive webhooks', () => {
|
|
const webhook = Webhook.create({
|
|
id: 'webhook-123',
|
|
organizationId: 'org-123',
|
|
url: 'https://example.com/webhook',
|
|
events: [WebhookEvent.BOOKING_CREATED],
|
|
secret: 'secret-key',
|
|
});
|
|
|
|
const deactivated = webhook.deactivate();
|
|
expect(deactivated.isActive()).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('subscribesToEvent', () => {
|
|
it('should return true if webhook subscribes to event', () => {
|
|
const webhook = Webhook.create({
|
|
id: 'webhook-123',
|
|
organizationId: 'org-123',
|
|
url: 'https://example.com/webhook',
|
|
events: [WebhookEvent.BOOKING_CREATED, WebhookEvent.BOOKING_UPDATED],
|
|
secret: 'secret-key',
|
|
});
|
|
|
|
expect(webhook.subscribesToEvent(WebhookEvent.BOOKING_CREATED)).toBe(true);
|
|
expect(webhook.subscribesToEvent(WebhookEvent.BOOKING_UPDATED)).toBe(true);
|
|
});
|
|
|
|
it('should return false if webhook does not subscribe to event', () => {
|
|
const webhook = Webhook.create({
|
|
id: 'webhook-123',
|
|
organizationId: 'org-123',
|
|
url: 'https://example.com/webhook',
|
|
events: [WebhookEvent.BOOKING_CREATED],
|
|
secret: 'secret-key',
|
|
});
|
|
|
|
expect(webhook.subscribesToEvent(WebhookEvent.BOOKING_CANCELLED)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('activate', () => {
|
|
it('should change status to active', () => {
|
|
const webhook = Webhook.create({
|
|
id: 'webhook-123',
|
|
organizationId: 'org-123',
|
|
url: 'https://example.com/webhook',
|
|
events: [WebhookEvent.BOOKING_CREATED],
|
|
secret: 'secret-key',
|
|
});
|
|
|
|
const deactivated = webhook.deactivate();
|
|
const activated = deactivated.activate();
|
|
|
|
expect(activated.status).toBe(WebhookStatus.ACTIVE);
|
|
expect(activated.isActive()).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('deactivate', () => {
|
|
it('should change status to inactive', () => {
|
|
const webhook = Webhook.create({
|
|
id: 'webhook-123',
|
|
organizationId: 'org-123',
|
|
url: 'https://example.com/webhook',
|
|
events: [WebhookEvent.BOOKING_CREATED],
|
|
secret: 'secret-key',
|
|
});
|
|
|
|
const deactivated = webhook.deactivate();
|
|
|
|
expect(deactivated.status).toBe(WebhookStatus.INACTIVE);
|
|
expect(deactivated.isActive()).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('markAsFailed', () => {
|
|
it('should change status to failed and increment failure count', () => {
|
|
const webhook = Webhook.create({
|
|
id: 'webhook-123',
|
|
organizationId: 'org-123',
|
|
url: 'https://example.com/webhook',
|
|
events: [WebhookEvent.BOOKING_CREATED],
|
|
secret: 'secret-key',
|
|
});
|
|
|
|
const failed = webhook.markAsFailed();
|
|
|
|
expect(failed.status).toBe(WebhookStatus.FAILED);
|
|
expect(failed.failureCount).toBe(1);
|
|
});
|
|
|
|
it('should increment failure count on multiple failures', () => {
|
|
let webhook = Webhook.create({
|
|
id: 'webhook-123',
|
|
organizationId: 'org-123',
|
|
url: 'https://example.com/webhook',
|
|
events: [WebhookEvent.BOOKING_CREATED],
|
|
secret: 'secret-key',
|
|
});
|
|
|
|
webhook = webhook.markAsFailed();
|
|
webhook = webhook.markAsFailed();
|
|
webhook = webhook.markAsFailed();
|
|
|
|
expect(webhook.failureCount).toBe(3);
|
|
});
|
|
});
|
|
|
|
describe('recordTrigger', () => {
|
|
it('should update lastTriggeredAt and increment retry count', () => {
|
|
const webhook = Webhook.create({
|
|
id: 'webhook-123',
|
|
organizationId: 'org-123',
|
|
url: 'https://example.com/webhook',
|
|
events: [WebhookEvent.BOOKING_CREATED],
|
|
secret: 'secret-key',
|
|
});
|
|
|
|
const triggered = webhook.recordTrigger();
|
|
|
|
expect(triggered.lastTriggeredAt).toBeDefined();
|
|
expect(triggered.retryCount).toBe(1);
|
|
expect(triggered.failureCount).toBe(0); // Reset on success
|
|
});
|
|
|
|
it('should reset failure count on successful trigger', () => {
|
|
let webhook = Webhook.create({
|
|
id: 'webhook-123',
|
|
organizationId: 'org-123',
|
|
url: 'https://example.com/webhook',
|
|
events: [WebhookEvent.BOOKING_CREATED],
|
|
secret: 'secret-key',
|
|
});
|
|
|
|
webhook = webhook.markAsFailed();
|
|
webhook = webhook.markAsFailed();
|
|
expect(webhook.failureCount).toBe(2);
|
|
|
|
const triggered = webhook.recordTrigger();
|
|
expect(triggered.failureCount).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe('update', () => {
|
|
it('should update webhook properties', () => {
|
|
const webhook = Webhook.create({
|
|
id: 'webhook-123',
|
|
organizationId: 'org-123',
|
|
url: 'https://example.com/webhook',
|
|
events: [WebhookEvent.BOOKING_CREATED],
|
|
secret: 'secret-key',
|
|
});
|
|
|
|
const updated = webhook.update({
|
|
url: 'https://newurl.com/webhook',
|
|
description: 'Updated webhook',
|
|
events: [WebhookEvent.BOOKING_CREATED, WebhookEvent.BOOKING_UPDATED],
|
|
});
|
|
|
|
expect(updated.url).toBe('https://newurl.com/webhook');
|
|
expect(updated.description).toBe('Updated webhook');
|
|
expect(updated.events).toHaveLength(2);
|
|
});
|
|
});
|
|
});
|