175 lines
5.7 KiB
TypeScript
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);
|
|
});
|
|
});
|
|
});
|