fix
Some checks failed
CI/CD Pipeline - Xpeditis PreProd / Frontend - Build & Test (push) Failing after 5m29s
CI/CD Pipeline - Xpeditis PreProd / Frontend - Docker Build & Push (push) Has been skipped
CI/CD Pipeline - Xpeditis PreProd / Backend - Build & Test (push) Failing after 5m48s
CI/CD Pipeline - Xpeditis PreProd / Backend - Docker Build & Push (push) Has been skipped
CI/CD Pipeline - Xpeditis PreProd / Deploy to PreProd Server (push) Has been skipped
CI/CD Pipeline - Xpeditis PreProd / Run Smoke Tests (push) Has been skipped
Some checks failed
CI/CD Pipeline - Xpeditis PreProd / Frontend - Build & Test (push) Failing after 5m29s
CI/CD Pipeline - Xpeditis PreProd / Frontend - Docker Build & Push (push) Has been skipped
CI/CD Pipeline - Xpeditis PreProd / Backend - Build & Test (push) Failing after 5m48s
CI/CD Pipeline - Xpeditis PreProd / Backend - Docker Build & Push (push) Has been skipped
CI/CD Pipeline - Xpeditis PreProd / Deploy to PreProd Server (push) Has been skipped
CI/CD Pipeline - Xpeditis PreProd / Run Smoke Tests (push) Has been skipped
This commit is contained in:
parent
bbbed1a126
commit
6827604bc0
@ -1,162 +0,0 @@
|
|||||||
/**
|
|
||||||
* Audit Service Tests
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
|
||||||
import { AuditService } from './audit.service';
|
|
||||||
import {
|
|
||||||
AUDIT_LOG_REPOSITORY,
|
|
||||||
AuditLogRepository,
|
|
||||||
} from '../../domain/ports/out/audit-log.repository';
|
|
||||||
import { AuditAction, AuditStatus, AuditLog } from '../../domain/entities/audit-log.entity';
|
|
||||||
|
|
||||||
describe('AuditService', () => {
|
|
||||||
let service: AuditService;
|
|
||||||
let repository: jest.Mocked<AuditLogRepository>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
const mockRepository: jest.Mocked<AuditLogRepository> = {
|
|
||||||
save: jest.fn(),
|
|
||||||
findById: jest.fn(),
|
|
||||||
findByFilters: jest.fn(),
|
|
||||||
count: jest.fn(),
|
|
||||||
findByResource: jest.fn(),
|
|
||||||
findRecentByOrganization: jest.fn(),
|
|
||||||
findByUser: jest.fn(),
|
|
||||||
};
|
|
||||||
|
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
|
||||||
providers: [
|
|
||||||
AuditService,
|
|
||||||
{
|
|
||||||
provide: AUDIT_LOG_REPOSITORY,
|
|
||||||
useValue: mockRepository,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}).compile();
|
|
||||||
|
|
||||||
service = module.get<AuditService>(AuditService);
|
|
||||||
repository = module.get(AUDIT_LOG_REPOSITORY);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('log', () => {
|
|
||||||
it('should create and save an audit log', async () => {
|
|
||||||
const input = {
|
|
||||||
action: AuditAction.BOOKING_CREATED,
|
|
||||||
status: AuditStatus.SUCCESS,
|
|
||||||
userId: 'user-123',
|
|
||||||
userEmail: 'user@example.com',
|
|
||||||
organizationId: 'org-123',
|
|
||||||
};
|
|
||||||
|
|
||||||
await service.log(input);
|
|
||||||
|
|
||||||
expect(repository.save).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
action: AuditAction.BOOKING_CREATED,
|
|
||||||
status: AuditStatus.SUCCESS,
|
|
||||||
userId: 'user-123',
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not throw error if save fails', async () => {
|
|
||||||
repository.save.mockRejectedValue(new Error('Database error'));
|
|
||||||
|
|
||||||
const input = {
|
|
||||||
action: AuditAction.BOOKING_CREATED,
|
|
||||||
status: AuditStatus.SUCCESS,
|
|
||||||
userId: 'user-123',
|
|
||||||
userEmail: 'user@example.com',
|
|
||||||
organizationId: 'org-123',
|
|
||||||
};
|
|
||||||
|
|
||||||
await expect(service.log(input)).resolves.not.toThrow();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('logSuccess', () => {
|
|
||||||
it('should log a successful action', async () => {
|
|
||||||
await service.logSuccess(
|
|
||||||
AuditAction.BOOKING_CREATED,
|
|
||||||
'user-123',
|
|
||||||
'user@example.com',
|
|
||||||
'org-123',
|
|
||||||
{ resourceType: 'booking', resourceId: 'booking-123' }
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(repository.save).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
status: AuditStatus.SUCCESS,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('logFailure', () => {
|
|
||||||
it('should log a failed action with error message', async () => {
|
|
||||||
await service.logFailure(
|
|
||||||
AuditAction.BOOKING_CREATED,
|
|
||||||
'user-123',
|
|
||||||
'user@example.com',
|
|
||||||
'org-123',
|
|
||||||
'Validation failed',
|
|
||||||
{ resourceType: 'booking' }
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(repository.save).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
status: AuditStatus.FAILURE,
|
|
||||||
errorMessage: 'Validation failed',
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getAuditLogs', () => {
|
|
||||||
it('should return audit logs with filters', async () => {
|
|
||||||
const mockLogs = [
|
|
||||||
AuditLog.create({
|
|
||||||
id: '1',
|
|
||||||
action: AuditAction.BOOKING_CREATED,
|
|
||||||
status: AuditStatus.SUCCESS,
|
|
||||||
userId: 'user-123',
|
|
||||||
userEmail: 'user@example.com',
|
|
||||||
organizationId: 'org-123',
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
|
|
||||||
repository.findByFilters.mockResolvedValue(mockLogs);
|
|
||||||
repository.count.mockResolvedValue(1);
|
|
||||||
|
|
||||||
const result = await service.getAuditLogs({ organizationId: 'org-123' });
|
|
||||||
|
|
||||||
expect(result.logs).toEqual(mockLogs);
|
|
||||||
expect(result.total).toBe(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getResourceAuditTrail', () => {
|
|
||||||
it('should return audit trail for a resource', async () => {
|
|
||||||
const mockLogs = [
|
|
||||||
AuditLog.create({
|
|
||||||
id: '1',
|
|
||||||
action: AuditAction.BOOKING_CREATED,
|
|
||||||
status: AuditStatus.SUCCESS,
|
|
||||||
userId: 'user-123',
|
|
||||||
userEmail: 'user@example.com',
|
|
||||||
organizationId: 'org-123',
|
|
||||||
resourceType: 'booking',
|
|
||||||
resourceId: 'booking-123',
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
|
|
||||||
repository.findByResource.mockResolvedValue(mockLogs);
|
|
||||||
|
|
||||||
const result = await service.getResourceAuditTrail('booking', 'booking-123');
|
|
||||||
|
|
||||||
expect(result).toEqual(mockLogs);
|
|
||||||
expect(repository.findByResource).toHaveBeenCalledWith('booking', 'booking-123');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,144 +0,0 @@
|
|||||||
/**
|
|
||||||
* Notification Service Tests
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
|
||||||
import { NotificationService } from './notification.service';
|
|
||||||
import {
|
|
||||||
NOTIFICATION_REPOSITORY,
|
|
||||||
NotificationRepository,
|
|
||||||
} from '../../domain/ports/out/notification.repository';
|
|
||||||
import {
|
|
||||||
Notification,
|
|
||||||
NotificationType,
|
|
||||||
NotificationPriority,
|
|
||||||
} from '../../domain/entities/notification.entity';
|
|
||||||
|
|
||||||
describe('NotificationService', () => {
|
|
||||||
let service: NotificationService;
|
|
||||||
let repository: jest.Mocked<NotificationRepository>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
const mockRepository: jest.Mocked<NotificationRepository> = {
|
|
||||||
save: jest.fn(),
|
|
||||||
findById: jest.fn(),
|
|
||||||
findByFilters: jest.fn(),
|
|
||||||
count: jest.fn(),
|
|
||||||
findUnreadByUser: jest.fn(),
|
|
||||||
countUnreadByUser: jest.fn(),
|
|
||||||
findRecentByUser: jest.fn(),
|
|
||||||
markAsRead: jest.fn(),
|
|
||||||
markAllAsReadForUser: jest.fn(),
|
|
||||||
delete: jest.fn(),
|
|
||||||
deleteOldReadNotifications: jest.fn(),
|
|
||||||
};
|
|
||||||
|
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
|
||||||
providers: [
|
|
||||||
NotificationService,
|
|
||||||
{
|
|
||||||
provide: NOTIFICATION_REPOSITORY,
|
|
||||||
useValue: mockRepository,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}).compile();
|
|
||||||
|
|
||||||
service = module.get<NotificationService>(NotificationService);
|
|
||||||
repository = module.get(NOTIFICATION_REPOSITORY);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('createNotification', () => {
|
|
||||||
it('should create and save a notification', async () => {
|
|
||||||
const input = {
|
|
||||||
userId: 'user-123',
|
|
||||||
organizationId: 'org-123',
|
|
||||||
type: NotificationType.BOOKING_CREATED,
|
|
||||||
priority: NotificationPriority.MEDIUM,
|
|
||||||
title: 'Booking Created',
|
|
||||||
message: 'Your booking has been created',
|
|
||||||
};
|
|
||||||
|
|
||||||
const result = await service.createNotification(input);
|
|
||||||
|
|
||||||
expect(repository.save).toHaveBeenCalled();
|
|
||||||
expect(result.type).toBe(NotificationType.BOOKING_CREATED);
|
|
||||||
expect(result.title).toBe('Booking Created');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getUnreadNotifications', () => {
|
|
||||||
it('should return unread notifications for a user', async () => {
|
|
||||||
const mockNotifications = [
|
|
||||||
Notification.create({
|
|
||||||
id: '1',
|
|
||||||
userId: 'user-123',
|
|
||||||
organizationId: 'org-123',
|
|
||||||
type: NotificationType.BOOKING_CREATED,
|
|
||||||
priority: NotificationPriority.MEDIUM,
|
|
||||||
title: 'Test',
|
|
||||||
message: 'Test message',
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
|
|
||||||
repository.findUnreadByUser.mockResolvedValue(mockNotifications);
|
|
||||||
|
|
||||||
const result = await service.getUnreadNotifications('user-123');
|
|
||||||
|
|
||||||
expect(result).toEqual(mockNotifications);
|
|
||||||
expect(repository.findUnreadByUser).toHaveBeenCalledWith('user-123', 50);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getUnreadCount', () => {
|
|
||||||
it('should return unread count for a user', async () => {
|
|
||||||
repository.countUnreadByUser.mockResolvedValue(5);
|
|
||||||
|
|
||||||
const result = await service.getUnreadCount('user-123');
|
|
||||||
|
|
||||||
expect(result).toBe(5);
|
|
||||||
expect(repository.countUnreadByUser).toHaveBeenCalledWith('user-123');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('markAsRead', () => {
|
|
||||||
it('should mark notification as read', async () => {
|
|
||||||
await service.markAsRead('notification-123');
|
|
||||||
|
|
||||||
expect(repository.markAsRead).toHaveBeenCalledWith('notification-123');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('markAllAsRead', () => {
|
|
||||||
it('should mark all notifications as read for a user', async () => {
|
|
||||||
await service.markAllAsRead('user-123');
|
|
||||||
|
|
||||||
expect(repository.markAllAsReadForUser).toHaveBeenCalledWith('user-123');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('notifyBookingCreated', () => {
|
|
||||||
it('should create a booking created notification', async () => {
|
|
||||||
const result = await service.notifyBookingCreated(
|
|
||||||
'user-123',
|
|
||||||
'org-123',
|
|
||||||
'BKG-123',
|
|
||||||
'booking-id-123'
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(repository.save).toHaveBeenCalled();
|
|
||||||
expect(result.type).toBe(NotificationType.BOOKING_CREATED);
|
|
||||||
expect(result.message).toContain('BKG-123');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('cleanupOldNotifications', () => {
|
|
||||||
it('should delete old read notifications', async () => {
|
|
||||||
repository.deleteOldReadNotifications.mockResolvedValue(10);
|
|
||||||
|
|
||||||
const result = await service.cleanupOldNotifications(30);
|
|
||||||
|
|
||||||
expect(result).toBe(10);
|
|
||||||
expect(repository.deleteOldReadNotifications).toHaveBeenCalledWith(30);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,189 +0,0 @@
|
|||||||
/**
|
|
||||||
* Webhook Service Tests
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
|
||||||
import { HttpService } from '@nestjs/axios';
|
|
||||||
import { of, throwError } from 'rxjs';
|
|
||||||
import { WebhookService } from './webhook.service';
|
|
||||||
import { WEBHOOK_REPOSITORY, WebhookRepository } from '../../domain/ports/out/webhook.repository';
|
|
||||||
import { Webhook, WebhookEvent, WebhookStatus } from '../../domain/entities/webhook.entity';
|
|
||||||
|
|
||||||
describe('WebhookService', () => {
|
|
||||||
let service: WebhookService;
|
|
||||||
let repository: jest.Mocked<WebhookRepository>;
|
|
||||||
let httpService: jest.Mocked<HttpService>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
const mockRepository: jest.Mocked<WebhookRepository> = {
|
|
||||||
save: jest.fn(),
|
|
||||||
findById: jest.fn(),
|
|
||||||
findByOrganization: jest.fn(),
|
|
||||||
findActiveByEvent: jest.fn(),
|
|
||||||
findByFilters: jest.fn(),
|
|
||||||
delete: jest.fn(),
|
|
||||||
countByOrganization: jest.fn(),
|
|
||||||
};
|
|
||||||
|
|
||||||
const mockHttpService = {
|
|
||||||
post: jest.fn(),
|
|
||||||
};
|
|
||||||
|
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
|
||||||
providers: [
|
|
||||||
WebhookService,
|
|
||||||
{
|
|
||||||
provide: WEBHOOK_REPOSITORY,
|
|
||||||
useValue: mockRepository,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: HttpService,
|
|
||||||
useValue: mockHttpService,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}).compile();
|
|
||||||
|
|
||||||
service = module.get<WebhookService>(WebhookService);
|
|
||||||
repository = module.get(WEBHOOK_REPOSITORY);
|
|
||||||
httpService = module.get(HttpService);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('createWebhook', () => {
|
|
||||||
it('should create and save a webhook with generated secret', async () => {
|
|
||||||
const input = {
|
|
||||||
organizationId: 'org-123',
|
|
||||||
url: 'https://example.com/webhook',
|
|
||||||
events: [WebhookEvent.BOOKING_CREATED],
|
|
||||||
description: 'Test webhook',
|
|
||||||
};
|
|
||||||
|
|
||||||
const result = await service.createWebhook(input);
|
|
||||||
|
|
||||||
expect(repository.save).toHaveBeenCalled();
|
|
||||||
expect(result.url).toBe('https://example.com/webhook');
|
|
||||||
expect(result.secret).toBeDefined();
|
|
||||||
expect(result.secret.length).toBeGreaterThan(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getWebhooksByOrganization', () => {
|
|
||||||
it('should return webhooks for an organization', async () => {
|
|
||||||
const mockWebhooks = [
|
|
||||||
Webhook.create({
|
|
||||||
id: '1',
|
|
||||||
organizationId: 'org-123',
|
|
||||||
url: 'https://example.com/webhook',
|
|
||||||
events: [WebhookEvent.BOOKING_CREATED],
|
|
||||||
secret: 'secret',
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
|
|
||||||
repository.findByOrganization.mockResolvedValue(mockWebhooks);
|
|
||||||
|
|
||||||
const result = await service.getWebhooksByOrganization('org-123');
|
|
||||||
|
|
||||||
expect(result).toEqual(mockWebhooks);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('activateWebhook', () => {
|
|
||||||
it('should activate a webhook', async () => {
|
|
||||||
const webhook = Webhook.create({
|
|
||||||
id: '1',
|
|
||||||
organizationId: 'org-123',
|
|
||||||
url: 'https://example.com/webhook',
|
|
||||||
events: [WebhookEvent.BOOKING_CREATED],
|
|
||||||
secret: 'secret',
|
|
||||||
});
|
|
||||||
|
|
||||||
repository.findById.mockResolvedValue(webhook);
|
|
||||||
|
|
||||||
await service.activateWebhook('1');
|
|
||||||
|
|
||||||
expect(repository.save).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
status: WebhookStatus.ACTIVE,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('triggerWebhooks', () => {
|
|
||||||
it('should trigger all active webhooks for an event', async () => {
|
|
||||||
const webhook = Webhook.create({
|
|
||||||
id: '1',
|
|
||||||
organizationId: 'org-123',
|
|
||||||
url: 'https://example.com/webhook',
|
|
||||||
events: [WebhookEvent.BOOKING_CREATED],
|
|
||||||
secret: 'secret',
|
|
||||||
});
|
|
||||||
|
|
||||||
repository.findActiveByEvent.mockResolvedValue([webhook]);
|
|
||||||
httpService.post.mockReturnValue(
|
|
||||||
of({ status: 200, statusText: 'OK', data: {}, headers: {}, config: {} as any })
|
|
||||||
);
|
|
||||||
|
|
||||||
await service.triggerWebhooks(WebhookEvent.BOOKING_CREATED, 'org-123', {
|
|
||||||
bookingId: 'booking-123',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(httpService.post).toHaveBeenCalledWith(
|
|
||||||
'https://example.com/webhook',
|
|
||||||
expect.objectContaining({
|
|
||||||
event: WebhookEvent.BOOKING_CREATED,
|
|
||||||
data: { bookingId: 'booking-123' },
|
|
||||||
}),
|
|
||||||
expect.any(Object)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should handle webhook failures and mark as failed after retries', async () => {
|
|
||||||
const webhook = Webhook.create({
|
|
||||||
id: '1',
|
|
||||||
organizationId: 'org-123',
|
|
||||||
url: 'https://example.com/webhook',
|
|
||||||
events: [WebhookEvent.BOOKING_CREATED],
|
|
||||||
secret: 'secret',
|
|
||||||
});
|
|
||||||
|
|
||||||
repository.findActiveByEvent.mockResolvedValue([webhook]);
|
|
||||||
httpService.post.mockReturnValue(throwError(() => new Error('Network error')));
|
|
||||||
|
|
||||||
await service.triggerWebhooks(WebhookEvent.BOOKING_CREATED, 'org-123', {
|
|
||||||
bookingId: 'booking-123',
|
|
||||||
});
|
|
||||||
|
|
||||||
// Should be saved as failed after retries
|
|
||||||
expect(repository.save).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
status: WebhookStatus.FAILED,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}, 20000); // Increase timeout to 20 seconds to account for retries
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('verifySignature', () => {
|
|
||||||
it('should verify valid webhook signature', () => {
|
|
||||||
const payload = { test: 'data' };
|
|
||||||
const secret = 'test-secret';
|
|
||||||
|
|
||||||
// Generate signature using the service's method
|
|
||||||
const signature = (service as any).generateSignature(payload, secret);
|
|
||||||
|
|
||||||
const isValid = service.verifySignature(payload, signature, secret);
|
|
||||||
|
|
||||||
expect(isValid).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should reject invalid webhook signature', () => {
|
|
||||||
const payload = { test: 'data' };
|
|
||||||
const secret = 'test-secret';
|
|
||||||
// Generate a valid-length (64 chars) but incorrect signature
|
|
||||||
const invalidSignature = '0000000000000000000000000000000000000000000000000000000000000000';
|
|
||||||
|
|
||||||
const isValid = service.verifySignature(payload, invalidSignature, secret);
|
|
||||||
|
|
||||||
expect(isValid).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -8,6 +8,7 @@
|
|||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
|
"type-check": "tsc --noEmit",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"test:watch": "jest --watch",
|
"test:watch": "jest --watch",
|
||||||
"test:e2e": "playwright test"
|
"test:e2e": "playwright test"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user