rwadurian/backend/services/presence-service/test/integration/application/queries/get-online-count.handler.sp...

119 lines
4.3 KiB
TypeScript

import { Test, TestingModule } from '@nestjs/testing';
import { GetOnlineCountHandler } from '../../../../src/application/queries/get-online-count/get-online-count.handler';
import { GetOnlineCountQuery } from '../../../../src/application/queries/get-online-count/get-online-count.query';
import { PresenceRedisRepository } from '../../../../src/infrastructure/redis/presence-redis.repository';
import { OnlineDetectionService } from '../../../../src/domain/services/online-detection.service';
import { TimeWindow } from '../../../../src/domain/value-objects/time-window.vo';
describe('GetOnlineCountHandler', () => {
let handler: GetOnlineCountHandler;
let presenceRedisRepository: jest.Mocked<PresenceRedisRepository>;
let onlineDetectionService: OnlineDetectionService;
beforeEach(async () => {
const mockPresenceRedisRepository = {
updateUserPresence: jest.fn(),
countOnlineUsers: jest.fn(),
getOnlineUsers: jest.fn(),
removeExpiredUsers: jest.fn(),
};
const module: TestingModule = await Test.createTestingModule({
providers: [
GetOnlineCountHandler,
{
provide: PresenceRedisRepository,
useValue: mockPresenceRedisRepository,
},
OnlineDetectionService,
],
}).compile();
handler = module.get<GetOnlineCountHandler>(GetOnlineCountHandler);
presenceRedisRepository = module.get(PresenceRedisRepository);
onlineDetectionService = module.get(OnlineDetectionService);
});
afterEach(() => {
jest.clearAllMocks();
});
describe('execute', () => {
it('should return online count', async () => {
presenceRedisRepository.countOnlineUsers.mockResolvedValue(1500);
const query = new GetOnlineCountQuery();
const result = await handler.execute(query);
expect(result.count).toBe(1500);
});
it('should return window seconds from OnlineDetectionService', async () => {
presenceRedisRepository.countOnlineUsers.mockResolvedValue(100);
const query = new GetOnlineCountQuery();
const result = await handler.execute(query);
expect(result.windowSeconds).toBe(TimeWindow.DEFAULT_ONLINE_WINDOW_SECONDS);
});
it('should return queriedAt timestamp', async () => {
presenceRedisRepository.countOnlineUsers.mockResolvedValue(100);
const beforeQuery = new Date();
const query = new GetOnlineCountQuery();
const result = await handler.execute(query);
const afterQuery = new Date();
expect(result.queriedAt).toBeInstanceOf(Date);
expect(result.queriedAt.getTime()).toBeGreaterThanOrEqual(beforeQuery.getTime());
expect(result.queriedAt.getTime()).toBeLessThanOrEqual(afterQuery.getTime());
});
it('should call countOnlineUsers with correct threshold', async () => {
presenceRedisRepository.countOnlineUsers.mockResolvedValue(500);
const query = new GetOnlineCountQuery();
await handler.execute(query);
expect(presenceRedisRepository.countOnlineUsers).toHaveBeenCalledWith(
expect.any(Number),
);
// Verify threshold is approximately (now - 180 seconds)
const calledThreshold = presenceRedisRepository.countOnlineUsers.mock.calls[0][0];
const expectedThreshold = Math.floor(Date.now() / 1000) - 180;
expect(Math.abs(calledThreshold - expectedThreshold)).toBeLessThanOrEqual(1);
});
it('should handle zero online users', async () => {
presenceRedisRepository.countOnlineUsers.mockResolvedValue(0);
const query = new GetOnlineCountQuery();
const result = await handler.execute(query);
expect(result.count).toBe(0);
});
it('should handle large number of online users', async () => {
presenceRedisRepository.countOnlineUsers.mockResolvedValue(1000000);
const query = new GetOnlineCountQuery();
const result = await handler.execute(query);
expect(result.count).toBe(1000000);
});
it('should throw error when Redis fails', async () => {
presenceRedisRepository.countOnlineUsers.mockRejectedValue(
new Error('Redis connection timeout'),
);
const query = new GetOnlineCountQuery();
await expect(handler.execute(query)).rejects.toThrow('Redis connection timeout');
});
});
});