rwadurian/backend/services/referral-service/test/integration/services/referral.service.integratio...

218 lines
7.8 KiB
TypeScript

import { Test, TestingModule } from '@nestjs/testing';
import { ReferralService } from '../../../src/application/services/referral.service';
import {
REFERRAL_RELATIONSHIP_REPOSITORY,
TEAM_STATISTICS_REPOSITORY,
ReferralChainService,
ReferralRelationship,
} from '../../../src/domain';
import { EventPublisherService } from '../../../src/infrastructure';
import { CreateReferralRelationshipCommand } from '../../../src/application/commands';
import { GetUserReferralInfoQuery, GetDirectReferralsQuery } from '../../../src/application/queries';
// Mock repository that works with domain aggregates
class MockReferralRepository {
private data = new Map<bigint, ReferralRelationship>();
private codeToUserId = new Map<string, bigint>();
async save(relationship: ReferralRelationship): Promise<ReferralRelationship> {
this.data.set(relationship.userId, relationship);
this.codeToUserId.set(relationship.referralCode, relationship.userId);
return relationship;
}
async findByUserId(userId: bigint): Promise<ReferralRelationship | null> {
return this.data.get(userId) ?? null;
}
async findByReferralCode(code: string): Promise<ReferralRelationship | null> {
const userId = this.codeToUserId.get(code);
if (!userId) return null;
return this.findByUserId(userId);
}
async findDirectReferrals(userId: bigint): Promise<ReferralRelationship[]> {
const results: ReferralRelationship[] = [];
for (const record of this.data.values()) {
if (record.referrerId === userId) {
results.push(record);
}
}
return results;
}
async existsByReferralCode(code: string): Promise<boolean> {
return this.codeToUserId.has(code);
}
async existsByUserId(userId: bigint): Promise<boolean> {
return this.data.has(userId);
}
async getReferralChain(userId: bigint): Promise<bigint[]> {
const record = this.data.get(userId);
return record?.referralChain ?? [];
}
}
class MockTeamStatsRepository {
private data = new Map<bigint, { userId: bigint; directReferralCount: number; totalTeamCount: number; personalPlantingCount: number; teamPlantingCount: number; leaderboardScore: number; addDirectReferral: (id: bigint) => void; getDirectReferralStats: () => Map<bigint, number> }>();
async create(userId: bigint) {
const stats = {
userId,
directReferralCount: 0,
totalTeamCount: 0,
personalPlantingCount: 0,
teamPlantingCount: 0,
leaderboardScore: 0,
addDirectReferral: function(id: bigint) { this.directReferralCount++; },
getDirectReferralStats: () => new Map<bigint, number>(),
};
this.data.set(userId, stats);
return stats;
}
async save(stats: { userId: bigint }) {
const existing = this.data.get(stats.userId);
if (existing) {
Object.assign(existing, stats);
}
return existing;
}
async findByUserId(userId: bigint) {
return this.data.get(userId) ?? null;
}
}
class MockEventPublisher {
async publishDomainEvents() {}
async publishEvent() {}
}
describe('ReferralService (Integration)', () => {
let service: ReferralService;
let referralRepo: MockReferralRepository;
let teamStatsRepo: MockTeamStatsRepository;
beforeEach(async () => {
referralRepo = new MockReferralRepository();
teamStatsRepo = new MockTeamStatsRepository();
const module: TestingModule = await Test.createTestingModule({
providers: [
ReferralService,
ReferralChainService,
{
provide: REFERRAL_RELATIONSHIP_REPOSITORY,
useValue: referralRepo,
},
{
provide: TEAM_STATISTICS_REPOSITORY,
useValue: teamStatsRepo,
},
{
provide: EventPublisherService,
useClass: MockEventPublisher,
},
],
}).compile();
service = module.get<ReferralService>(ReferralService);
});
describe('createReferralRelationship', () => {
it('should create referral relationship without referrer', async () => {
const command = new CreateReferralRelationshipCommand(100n, 12345678, null);
const result = await service.createReferralRelationship(command);
expect(result).toBeDefined();
expect(result.referralCode).toBeDefined();
expect(result.referralCode.length).toBeGreaterThanOrEqual(6);
});
it('should create referral relationship with valid referrer code', async () => {
// First create a referrer
const referrerCommand = new CreateReferralRelationshipCommand(50n, 11111111, null);
const referrerResult = await service.createReferralRelationship(referrerCommand);
// Then create with referrer code
const command = new CreateReferralRelationshipCommand(100n, 12345678, referrerResult.referralCode);
const result = await service.createReferralRelationship(command);
expect(result).toBeDefined();
expect(result.referralCode).toBeDefined();
});
it('should throw error if user already has referral relationship', async () => {
const command = new CreateReferralRelationshipCommand(100n, 12345678, null);
await service.createReferralRelationship(command);
await expect(service.createReferralRelationship(command)).rejects.toThrow('用户已存在推荐关系');
});
it('should throw error for invalid referral code', async () => {
const command = new CreateReferralRelationshipCommand(100n, 12345678, 'INVALID_CODE');
await expect(service.createReferralRelationship(command)).rejects.toThrow('推荐码不存在');
});
});
describe('getUserReferralInfo', () => {
it('should return user referral info', async () => {
// Create user first
const createCommand = new CreateReferralRelationshipCommand(100n, 12345678, null);
await service.createReferralRelationship(createCommand);
const query = new GetUserReferralInfoQuery(12345678);
const result = await service.getUserReferralInfo(query);
expect(result).toBeDefined();
expect(result.userId).toBe('100');
expect(result.referralCode).toBeDefined();
expect(result.directReferralCount).toBe(0);
});
it('should throw error for non-existent user', async () => {
const query = new GetUserReferralInfoQuery(99999999);
await expect(service.getUserReferralInfo(query)).rejects.toThrow('用户推荐关系不存在');
});
});
describe('getDirectReferrals', () => {
it('should return direct referrals list', async () => {
// Create referrer
const referrerCommand = new CreateReferralRelationshipCommand(50n, 11111111, null);
const referrerResult = await service.createReferralRelationship(referrerCommand);
// Create direct referrals
await service.createReferralRelationship(new CreateReferralRelationshipCommand(100n, 12345678, referrerResult.referralCode));
await service.createReferralRelationship(new CreateReferralRelationshipCommand(101n, 12345679, referrerResult.referralCode));
const query = new GetDirectReferralsQuery(50n);
const result = await service.getDirectReferrals(query);
expect(result.referrals.length).toBe(2);
expect(result.total).toBe(2);
});
});
describe('validateReferralCode', () => {
it('should return true for valid code', async () => {
const createCommand = new CreateReferralRelationshipCommand(100n, 12345678, null);
const { referralCode } = await service.createReferralRelationship(createCommand);
const isValid = await service.validateReferralCode(referralCode);
expect(isValid).toBe(true);
});
it('should return false for invalid code', async () => {
const isValid = await service.validateReferralCode('INVALID');
expect(isValid).toBe(false);
});
});
});