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(); private codeToUserId = new Map(); async save(relationship: ReferralRelationship): Promise { this.data.set(relationship.userId, relationship); this.codeToUserId.set(relationship.referralCode, relationship.userId); return relationship; } async findByUserId(userId: bigint): Promise { return this.data.get(userId) ?? null; } async findByReferralCode(code: string): Promise { const userId = this.codeToUserId.get(code); if (!userId) return null; return this.findByUserId(userId); } async findDirectReferrals(userId: bigint): Promise { const results: ReferralRelationship[] = []; for (const record of this.data.values()) { if (record.referrerId === userId) { results.push(record); } } return results; } async existsByReferralCode(code: string): Promise { return this.codeToUserId.has(code); } async existsByUserId(userId: bigint): Promise { return this.data.has(userId); } async getReferralChain(userId: bigint): Promise { const record = this.data.get(userId); return record?.referralChain ?? []; } } class MockTeamStatsRepository { private data = new Map void; getDirectReferralStats: () => Map }>(); 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(), }; 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); }); 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); }); }); });