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,104 @@
import { SearchController } from '../controllers/search.controller';
import { ReindexAllCommand } from '../../application/commands/reindex-all/reindex-all.command';
import { GeoSearchQuery } from '../../application/queries/geo-search/geo-search.query';
import { SearchPropertiesQuery } from '../../application/queries/search-properties/search-properties.query';
describe('SearchController', () => {
let controller: SearchController;
let mockCommandBus: { execute: ReturnType<typeof vi.fn> };
let mockQueryBus: { execute: ReturnType<typeof vi.fn> };
beforeEach(() => {
mockCommandBus = { execute: vi.fn() };
mockQueryBus = { execute: vi.fn() };
controller = new SearchController(mockCommandBus as any, mockQueryBus as any);
});
it('search executes SearchPropertiesQuery with correct params', async () => {
const mockResult = { hits: [], totalFound: 0, page: 1, perPage: 20, totalPages: 0, searchTimeMs: 1 };
mockQueryBus.execute.mockResolvedValue(mockResult);
const dto = {
q: 'căn hộ Quận 7',
propertyType: 'APARTMENT',
transactionType: 'SALE',
priceMin: 1000000000,
priceMax: 5000000000,
areaMin: 50,
areaMax: 200,
bedrooms: 2,
district: 'Quận 7',
city: 'Hồ Chí Minh',
sortBy: 'price_asc',
page: 1,
perPage: 20,
};
const result = await controller.search(dto as any);
expect(mockQueryBus.execute).toHaveBeenCalledWith(
new SearchPropertiesQuery(
dto.q,
dto.propertyType,
dto.transactionType,
dto.priceMin,
dto.priceMax,
dto.areaMin,
dto.areaMax,
dto.bedrooms,
dto.district,
dto.city,
dto.sortBy,
dto.page,
dto.perPage,
),
);
expect(result).toBe(mockResult);
});
it('geoSearch executes GeoSearchQuery with correct params', async () => {
const mockResult = { hits: [], totalFound: 0, page: 1, perPage: 20, totalPages: 0, searchTimeMs: 2 };
mockQueryBus.execute.mockResolvedValue(mockResult);
const dto = {
lat: 10.776,
lng: 106.700,
radiusKm: 5,
propertyType: 'HOUSE',
transactionType: 'RENT',
priceMin: 5000000,
priceMax: 20000000,
sortBy: 'distance',
page: 1,
perPage: 10,
};
const result = await controller.geoSearch(dto as any);
expect(mockQueryBus.execute).toHaveBeenCalledWith(
new GeoSearchQuery(
dto.lat,
dto.lng,
dto.radiusKm,
dto.propertyType,
dto.transactionType,
dto.priceMin,
dto.priceMax,
dto.sortBy,
dto.page,
dto.perPage,
),
);
expect(result).toBe(mockResult);
});
it('reindex executes ReindexAllCommand', async () => {
const mockResult = { indexed: 42, total: 42 };
mockCommandBus.execute.mockResolvedValue(mockResult);
const result = await controller.reindex();
expect(mockCommandBus.execute).toHaveBeenCalledWith(new ReindexAllCommand());
expect(result).toBe(mockResult);
});
});