test: increase test coverage for listings, auth, and search modules
Add 33 new test files to reach coverage targets: - Listings: 13 → 28 test files (50%+) - Auth: 21 → 36 test files (50%+) - Search: 10 → 13 test files (59%+) New tests cover domain entities, value objects, services, guards, decorators, DTOs, repositories, controllers, and event handlers. Total: 204 test files, 1178 tests passing. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
import { CachePrefix, CacheService } from '@modules/shared/infrastructure/cache.service';
|
||||
import { ListingStatusChangedHandler } from '../event-handlers/listing-status-changed.handler';
|
||||
|
||||
describe('ListingStatusChangedHandler', () => {
|
||||
let handler: ListingStatusChangedHandler;
|
||||
let mockIndexer: { indexListing: ReturnType<typeof vi.fn>; removeListing: ReturnType<typeof vi.fn> };
|
||||
let mockCache: {
|
||||
invalidate: ReturnType<typeof vi.fn>;
|
||||
invalidateByPrefix: ReturnType<typeof vi.fn>;
|
||||
};
|
||||
let mockLogger: { log: ReturnType<typeof vi.fn>; warn: ReturnType<typeof vi.fn>; error: ReturnType<typeof vi.fn> };
|
||||
|
||||
beforeEach(() => {
|
||||
mockIndexer = {
|
||||
indexListing: vi.fn().mockResolvedValue(undefined),
|
||||
removeListing: vi.fn().mockResolvedValue(undefined),
|
||||
};
|
||||
mockCache = {
|
||||
invalidate: vi.fn().mockResolvedValue(undefined),
|
||||
invalidateByPrefix: vi.fn().mockResolvedValue(undefined),
|
||||
};
|
||||
mockLogger = {
|
||||
log: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
error: vi.fn(),
|
||||
};
|
||||
handler = new ListingStatusChangedHandler(mockIndexer as any, mockCache as any, mockLogger as any);
|
||||
});
|
||||
|
||||
it('removes listing from index when status changed to REJECTED', async () => {
|
||||
await handler.handle({
|
||||
aggregateId: 'listing-1',
|
||||
propertyId: 'prop-1',
|
||||
previousStatus: 'ACTIVE',
|
||||
newStatus: 'REJECTED',
|
||||
eventName: 'listing.status_changed',
|
||||
occurredAt: new Date(),
|
||||
} as any);
|
||||
|
||||
expect(mockIndexer.removeListing).toHaveBeenCalledWith('listing-1');
|
||||
});
|
||||
|
||||
it('removes listing from index when status changed to EXPIRED', async () => {
|
||||
await handler.handle({
|
||||
aggregateId: 'listing-2',
|
||||
propertyId: 'prop-2',
|
||||
previousStatus: 'ACTIVE',
|
||||
newStatus: 'EXPIRED',
|
||||
eventName: 'listing.status_changed',
|
||||
occurredAt: new Date(),
|
||||
} as any);
|
||||
|
||||
expect(mockIndexer.removeListing).toHaveBeenCalledWith('listing-2');
|
||||
});
|
||||
|
||||
it('removes listing from index when status changed to SOLD', async () => {
|
||||
await handler.handle({
|
||||
aggregateId: 'listing-3',
|
||||
propertyId: 'prop-3',
|
||||
previousStatus: 'ACTIVE',
|
||||
newStatus: 'SOLD',
|
||||
eventName: 'listing.status_changed',
|
||||
occurredAt: new Date(),
|
||||
} as any);
|
||||
|
||||
expect(mockIndexer.removeListing).toHaveBeenCalledWith('listing-3');
|
||||
});
|
||||
|
||||
it('removes listing from index when status changed to RENTED', async () => {
|
||||
await handler.handle({
|
||||
aggregateId: 'listing-4',
|
||||
propertyId: 'prop-4',
|
||||
previousStatus: 'ACTIVE',
|
||||
newStatus: 'RENTED',
|
||||
eventName: 'listing.status_changed',
|
||||
occurredAt: new Date(),
|
||||
} as any);
|
||||
|
||||
expect(mockIndexer.removeListing).toHaveBeenCalledWith('listing-4');
|
||||
});
|
||||
|
||||
it('does NOT remove listing from index when status changed to ACTIVE', async () => {
|
||||
await handler.handle({
|
||||
aggregateId: 'listing-5',
|
||||
propertyId: 'prop-5',
|
||||
previousStatus: 'PENDING_REVIEW',
|
||||
newStatus: 'ACTIVE',
|
||||
eventName: 'listing.status_changed',
|
||||
occurredAt: new Date(),
|
||||
} as any);
|
||||
|
||||
expect(mockIndexer.removeListing).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('invalidates listing cache, search cache, and geo search cache on any status change', async () => {
|
||||
await handler.handle({
|
||||
aggregateId: 'listing-6',
|
||||
propertyId: 'prop-6',
|
||||
previousStatus: 'DRAFT',
|
||||
newStatus: 'ACTIVE',
|
||||
eventName: 'listing.status_changed',
|
||||
occurredAt: new Date(),
|
||||
} as any);
|
||||
|
||||
expect(mockCache.invalidate).toHaveBeenCalledWith(
|
||||
CacheService.buildKey(CachePrefix.LISTING, 'listing-6'),
|
||||
);
|
||||
expect(mockCache.invalidateByPrefix).toHaveBeenCalledWith(CachePrefix.SEARCH);
|
||||
expect(mockCache.invalidateByPrefix).toHaveBeenCalledWith(CachePrefix.GEO_SEARCH);
|
||||
});
|
||||
|
||||
it('logs the status transition', async () => {
|
||||
await handler.handle({
|
||||
aggregateId: 'listing-7',
|
||||
propertyId: 'prop-7',
|
||||
previousStatus: 'ACTIVE',
|
||||
newStatus: 'SOLD',
|
||||
eventName: 'listing.status_changed',
|
||||
occurredAt: new Date(),
|
||||
} as any);
|
||||
|
||||
expect(mockLogger.log).toHaveBeenCalledWith(
|
||||
expect.stringContaining('ACTIVE'),
|
||||
expect.any(String),
|
||||
);
|
||||
expect(mockLogger.log).toHaveBeenCalledWith(
|
||||
expect.stringContaining('SOLD'),
|
||||
expect.any(String),
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user