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); }); 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); }); }); });