test(api): add unit tests for analytics, metrics, notifications, payments, and search modules

New test coverage for infrastructure and presentation layers across
multiple modules including Momo/ZaloPay payment services, Typesense
search repository, listing indexer, and notification handlers.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Ho Ngoc Hai
2026-04-08 23:07:14 +07:00
parent 7fb25eb2b1
commit c9782fd48d
18 changed files with 2097 additions and 0 deletions

View File

@@ -0,0 +1,95 @@
import { NotificationsController } from '../controllers/notifications.controller';
describe('NotificationsController', () => {
let controller: NotificationsController;
let mockNotificationRepo: { findByUserId: ReturnType<typeof vi.fn> };
let mockPreferenceRepo: { findByUserId: ReturnType<typeof vi.fn>; upsert: ReturnType<typeof vi.fn> };
let mockTemplateService: { getTemplateKeys: ReturnType<typeof vi.fn> };
const mockUser = { sub: 'user-1', phone: '0901234567', role: 'BUYER' };
const mockNotification = {
id: 'notif-1',
userId: 'user-1',
channel: 'EMAIL' as const,
templateKey: 'user.registered',
subject: 'Welcome',
body: '<p>Hello</p>',
metadata: null,
status: 'SENT' as const,
errorDetail: null,
sentAt: new Date(),
createdAt: new Date(),
};
const mockPreference = {
id: 'pref-1',
userId: 'user-1',
channel: 'EMAIL' as const,
eventType: 'user.registered',
enabled: true,
createdAt: new Date(),
updatedAt: new Date(),
};
beforeEach(() => {
mockNotificationRepo = { findByUserId: vi.fn() };
mockPreferenceRepo = { findByUserId: vi.fn(), upsert: vi.fn() };
mockTemplateService = { getTemplateKeys: vi.fn() };
controller = new NotificationsController(
mockNotificationRepo as any,
mockPreferenceRepo as any,
mockTemplateService as any,
);
});
it('getHistory calls notificationRepo.findByUserId with user sub and default limit', async () => {
mockNotificationRepo.findByUserId.mockResolvedValue([mockNotification]);
const result = await controller.getHistory(mockUser as any, undefined);
expect(mockNotificationRepo.findByUserId).toHaveBeenCalledWith('user-1', 50);
expect(result).toEqual([mockNotification]);
});
it('getHistory passes custom limit', async () => {
mockNotificationRepo.findByUserId.mockResolvedValue([mockNotification]);
await controller.getHistory(mockUser as any, 10);
expect(mockNotificationRepo.findByUserId).toHaveBeenCalledWith('user-1', 10);
});
it('getPreferences calls preferenceRepo.findByUserId', async () => {
mockPreferenceRepo.findByUserId.mockResolvedValue([mockPreference]);
const result = await controller.getPreferences(mockUser as any);
expect(mockPreferenceRepo.findByUserId).toHaveBeenCalledWith('user-1');
expect(result).toEqual([mockPreference]);
});
it('updatePreference calls preferenceRepo.upsert with correct params', async () => {
mockPreferenceRepo.upsert.mockResolvedValue({ ...mockPreference, enabled: false });
const result = await controller.updatePreference(mockUser as any, {
channel: 'EMAIL' as any,
eventType: 'user.registered',
enabled: false,
});
expect(mockPreferenceRepo.upsert).toHaveBeenCalledWith('user-1', 'EMAIL', 'user.registered', false);
expect(result.enabled).toBe(false);
});
it('getTemplates returns template keys from templateService', async () => {
const keys = ['user.registered', 'agent.verified', 'listing.approved', 'inquiry.received', 'quota.exceeded', 'password.reset'];
mockTemplateService.getTemplateKeys.mockReturnValue(keys);
const result = await controller.getTemplates();
expect(mockTemplateService.getTemplateKeys).toHaveBeenCalled();
expect(result).toEqual({ templates: keys });
});
});