rwadurian/backend/services/referral-service/test/integration/repositories/team-statistics.repository....

175 lines
5.7 KiB
TypeScript

import { Test, TestingModule } from '@nestjs/testing';
import { TeamStatisticsRepository } from '../../../src/infrastructure/repositories/team-statistics.repository';
import { PrismaService } from '../../../src/infrastructure/database/prisma.service';
import { MockPrismaService } from '../mocks/prisma.mock';
import { TeamStatistics } from '../../../src/domain';
describe('TeamStatisticsRepository (Integration)', () => {
let repository: TeamStatisticsRepository;
let mockPrisma: MockPrismaService;
beforeEach(async () => {
mockPrisma = new MockPrismaService();
const module: TestingModule = await Test.createTestingModule({
providers: [
TeamStatisticsRepository,
{
provide: PrismaService,
useValue: mockPrisma,
},
],
}).compile();
repository = module.get<TeamStatisticsRepository>(TeamStatisticsRepository);
});
afterEach(() => {
mockPrisma.$cleanup();
});
describe('create', () => {
it('should create new team statistics', async () => {
const stats = await repository.create(100n);
expect(stats).toBeDefined();
expect(stats.userId).toBe(100n);
expect(stats.directReferralCount).toBe(0);
expect(stats.totalTeamCount).toBe(0);
expect(stats.leaderboardScore).toBe(0);
});
});
describe('save', () => {
it('should save team statistics', async () => {
const stats = TeamStatistics.create(100n);
stats.addPersonalPlanting(10, '110000', '110100');
const saved = await repository.save(stats);
expect(saved).toBeDefined();
expect(saved.userId).toBe(100n);
expect(saved.personalPlantingCount).toBe(10);
});
it('should update existing statistics', async () => {
// Create initial
const stats = await repository.create(100n);
// Create new instance and add planting
const updated = TeamStatistics.create(100n);
updated.addPersonalPlanting(20, '110000', '110100');
const saved = await repository.save(updated);
expect(saved.personalPlantingCount).toBe(20);
});
});
describe('findByUserId', () => {
it('should find statistics by user ID', async () => {
await repository.create(100n);
const found = await repository.findByUserId(100n);
expect(found).toBeDefined();
expect(found!.userId).toBe(100n);
});
it('should return null for non-existent user', async () => {
const found = await repository.findByUserId(999n);
expect(found).toBeNull();
});
});
describe('findByUserIds', () => {
it('should find statistics for multiple users', async () => {
await repository.create(100n);
await repository.create(101n);
await repository.create(102n);
const found = await repository.findByUserIds([100n, 101n]);
expect(found.length).toBe(2);
expect(found.map((s) => s.userId)).toContain(100n);
expect(found.map((s) => s.userId)).toContain(101n);
});
});
describe('getLeaderboard', () => {
it('should return leaderboard sorted by score', async () => {
// Create users with different scores
const stats1 = TeamStatistics.create(100n);
stats1.addPersonalPlanting(50, '110000', '110100');
await repository.save(stats1);
const stats2 = TeamStatistics.create(101n);
stats2.addPersonalPlanting(100, '110000', '110100');
await repository.save(stats2);
const stats3 = TeamStatistics.create(102n);
stats3.addPersonalPlanting(30, '110000', '110100');
await repository.save(stats3);
const leaderboard = await repository.getLeaderboard({ limit: 10 });
expect(leaderboard.length).toBe(3);
// Should be sorted by score descending
expect(leaderboard[0].userId).toBe(101n);
expect(leaderboard[0].rank).toBe(1);
expect(leaderboard[1].userId).toBe(100n);
expect(leaderboard[1].rank).toBe(2);
});
it('should respect limit and offset', async () => {
for (let i = 0; i < 10; i++) {
const stats = TeamStatistics.create(BigInt(100 + i));
stats.addPersonalPlanting(10 + i, '110000', '110100');
await repository.save(stats);
}
const leaderboard = await repository.getLeaderboard({ limit: 5, offset: 2 });
expect(leaderboard.length).toBe(5);
expect(leaderboard[0].rank).toBe(3); // 1-indexed, offset by 2
});
});
describe('getUserRank', () => {
it('should return correct rank', async () => {
const stats1 = TeamStatistics.create(100n);
stats1.addPersonalPlanting(100, '110000', '110100');
await repository.save(stats1);
const stats2 = TeamStatistics.create(101n);
stats2.addPersonalPlanting(50, '110000', '110100');
await repository.save(stats2);
const rank = await repository.getUserRank(101n);
expect(rank).toBe(2);
});
it('should return null for non-existent user', async () => {
const rank = await repository.getUserRank(999n);
expect(rank).toBeNull();
});
});
describe('batchUpdateTeamCounts', () => {
it('should batch update team counts for multiple users', async () => {
await repository.create(100n);
await repository.create(101n);
await repository.batchUpdateTeamCounts([
{ userId: 100n, countDelta: 10, provinceCode: '110000', cityCode: '110100' },
{ userId: 101n, countDelta: 20, provinceCode: '120000', cityCode: '120100' },
]);
const stats100 = await repository.findByUserId(100n);
const stats101 = await repository.findByUserId(101n);
expect(stats100!.teamPlantingCount).toBe(10);
expect(stats101!.teamPlantingCount).toBe(20);
});
});
});