273 lines
9.0 KiB
TypeScript
273 lines
9.0 KiB
TypeScript
|
|
import { Test, TestingModule } from '@nestjs/testing';
|
||
|
|
import { getRepositoryToken } from '@nestjs/typeorm';
|
||
|
|
import { Repository } from 'typeorm';
|
||
|
|
import { BlacklistService } from './blacklist.service';
|
||
|
|
import { Blacklist } from '../../entities/blacklist.entity';
|
||
|
|
import { User } from '../../entities/user.entity';
|
||
|
|
import { GroupMember } from '../../entities/group-member.entity';
|
||
|
|
import { BlacklistStatus } from '../../common/enums';
|
||
|
|
import { NotFoundException, ForbiddenException } from '@nestjs/common';
|
||
|
|
|
||
|
|
describe('BlacklistService', () => {
|
||
|
|
let service: BlacklistService;
|
||
|
|
let blacklistRepository: Repository<Blacklist>;
|
||
|
|
let userRepository: Repository<User>;
|
||
|
|
let groupMemberRepository: Repository<GroupMember>;
|
||
|
|
|
||
|
|
const mockBlacklist = {
|
||
|
|
id: 'blacklist-1',
|
||
|
|
reporterId: 'user-1',
|
||
|
|
targetGameId: 'game-123',
|
||
|
|
targetNickname: '违规玩家',
|
||
|
|
reason: '恶意行为',
|
||
|
|
proofImages: ['image1.jpg'],
|
||
|
|
status: BlacklistStatus.PENDING,
|
||
|
|
createdAt: new Date(),
|
||
|
|
};
|
||
|
|
|
||
|
|
const mockUser = {
|
||
|
|
id: 'user-1',
|
||
|
|
username: '举报人',
|
||
|
|
isMember: true,
|
||
|
|
};
|
||
|
|
|
||
|
|
const mockGroupMember = {
|
||
|
|
id: 'member-1',
|
||
|
|
userId: 'user-1',
|
||
|
|
groupId: 'group-1',
|
||
|
|
};
|
||
|
|
|
||
|
|
const mockQueryBuilder = {
|
||
|
|
leftJoinAndSelect: jest.fn().mockReturnThis(),
|
||
|
|
andWhere: jest.fn().mockReturnThis(),
|
||
|
|
orderBy: jest.fn().mockReturnThis(),
|
||
|
|
getMany: jest.fn(),
|
||
|
|
};
|
||
|
|
|
||
|
|
beforeEach(async () => {
|
||
|
|
const module: TestingModule = await Test.createTestingModule({
|
||
|
|
providers: [
|
||
|
|
BlacklistService,
|
||
|
|
{
|
||
|
|
provide: getRepositoryToken(Blacklist),
|
||
|
|
useValue: {
|
||
|
|
create: jest.fn(),
|
||
|
|
save: jest.fn(),
|
||
|
|
find: jest.fn(),
|
||
|
|
findOne: jest.fn(),
|
||
|
|
remove: jest.fn(),
|
||
|
|
count: jest.fn(),
|
||
|
|
createQueryBuilder: jest.fn(() => mockQueryBuilder),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
provide: getRepositoryToken(User),
|
||
|
|
useValue: {
|
||
|
|
findOne: jest.fn(),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
provide: getRepositoryToken(GroupMember),
|
||
|
|
useValue: {
|
||
|
|
find: jest.fn(),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
],
|
||
|
|
}).compile();
|
||
|
|
|
||
|
|
service = module.get<BlacklistService>(BlacklistService);
|
||
|
|
blacklistRepository = module.get<Repository<Blacklist>>(getRepositoryToken(Blacklist));
|
||
|
|
userRepository = module.get<Repository<User>>(getRepositoryToken(User));
|
||
|
|
groupMemberRepository = module.get<Repository<GroupMember>>(getRepositoryToken(GroupMember));
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should be defined', () => {
|
||
|
|
expect(service).toBeDefined();
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('create', () => {
|
||
|
|
it('应该成功创建黑名单举报', async () => {
|
||
|
|
const createDto = {
|
||
|
|
targetGameId: 'game-123',
|
||
|
|
targetNickname: '违规玩家',
|
||
|
|
reason: '恶意行为',
|
||
|
|
proofImages: ['image1.jpg'],
|
||
|
|
};
|
||
|
|
|
||
|
|
jest.spyOn(userRepository, 'findOne').mockResolvedValue(mockUser as any);
|
||
|
|
jest.spyOn(blacklistRepository, 'create').mockReturnValue(mockBlacklist as any);
|
||
|
|
jest.spyOn(blacklistRepository, 'save').mockResolvedValue(mockBlacklist as any);
|
||
|
|
jest.spyOn(blacklistRepository, 'findOne').mockResolvedValue(mockBlacklist as any);
|
||
|
|
|
||
|
|
const result = await service.create('user-1', createDto);
|
||
|
|
|
||
|
|
expect(result).toBeDefined();
|
||
|
|
expect(blacklistRepository.create).toHaveBeenCalledWith({
|
||
|
|
...createDto,
|
||
|
|
reporterId: 'user-1',
|
||
|
|
status: BlacklistStatus.PENDING,
|
||
|
|
});
|
||
|
|
expect(blacklistRepository.save).toHaveBeenCalled();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('findAll', () => {
|
||
|
|
it('应该返回黑名单列表', async () => {
|
||
|
|
const query = { status: BlacklistStatus.APPROVED };
|
||
|
|
mockQueryBuilder.getMany.mockResolvedValue([mockBlacklist]);
|
||
|
|
|
||
|
|
const result = await service.findAll(query);
|
||
|
|
|
||
|
|
expect(result).toHaveLength(1);
|
||
|
|
expect(blacklistRepository.createQueryBuilder).toHaveBeenCalled();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('应该支持按状态筛选', async () => {
|
||
|
|
const query = { status: BlacklistStatus.PENDING };
|
||
|
|
|
||
|
|
mockQueryBuilder.getMany.mockResolvedValue([mockBlacklist]);
|
||
|
|
|
||
|
|
await service.findAll(query);
|
||
|
|
|
||
|
|
expect(mockQueryBuilder.andWhere).toHaveBeenCalledWith(
|
||
|
|
'blacklist.status = :status',
|
||
|
|
{ status: BlacklistStatus.PENDING }
|
||
|
|
);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('findOne', () => {
|
||
|
|
it('应该返回单个黑名单记录', async () => {
|
||
|
|
jest.spyOn(blacklistRepository, 'findOne').mockResolvedValue(mockBlacklist as any);
|
||
|
|
|
||
|
|
const result = await service.findOne('blacklist-1');
|
||
|
|
|
||
|
|
expect(result).toBeDefined();
|
||
|
|
expect(result.id).toBe('blacklist-1');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('记录不存在时应该抛出异常', async () => {
|
||
|
|
jest.spyOn(blacklistRepository, 'findOne').mockResolvedValue(null);
|
||
|
|
|
||
|
|
await expect(service.findOne('non-existent')).rejects.toThrow(NotFoundException);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('review', () => {
|
||
|
|
it('应该成功审核黑名单(会员权限)', async () => {
|
||
|
|
const reviewDto = {
|
||
|
|
status: BlacklistStatus.APPROVED,
|
||
|
|
reviewNote: '确认违规',
|
||
|
|
};
|
||
|
|
|
||
|
|
const updatedBlacklist = {
|
||
|
|
...mockBlacklist,
|
||
|
|
...reviewDto,
|
||
|
|
reviewerId: 'user-1',
|
||
|
|
};
|
||
|
|
|
||
|
|
jest.spyOn(userRepository, 'findOne').mockResolvedValue(mockUser as any);
|
||
|
|
jest.spyOn(blacklistRepository, 'findOne')
|
||
|
|
.mockResolvedValueOnce(mockBlacklist as any) // First call in review method
|
||
|
|
.mockResolvedValueOnce(updatedBlacklist as any); // Second call in findOne at the end
|
||
|
|
jest.spyOn(blacklistRepository, 'save').mockResolvedValue(updatedBlacklist as any);
|
||
|
|
|
||
|
|
const result = await service.review('user-1', 'blacklist-1', reviewDto);
|
||
|
|
|
||
|
|
expect(result.status).toBe(BlacklistStatus.APPROVED);
|
||
|
|
expect(blacklistRepository.save).toHaveBeenCalled();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('非会员审核时应该抛出异常', async () => {
|
||
|
|
const reviewDto = {
|
||
|
|
status: BlacklistStatus.APPROVED,
|
||
|
|
};
|
||
|
|
|
||
|
|
jest.spyOn(userRepository, 'findOne').mockResolvedValue({
|
||
|
|
...mockUser,
|
||
|
|
isMember: false,
|
||
|
|
} as any);
|
||
|
|
|
||
|
|
await expect(service.review('user-1', 'blacklist-1', reviewDto)).rejects.toThrow(ForbiddenException);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('用户不存在时应该抛出异常', async () => {
|
||
|
|
const reviewDto = {
|
||
|
|
status: BlacklistStatus.APPROVED,
|
||
|
|
};
|
||
|
|
|
||
|
|
jest.spyOn(userRepository, 'findOne').mockResolvedValue(null);
|
||
|
|
|
||
|
|
await expect(service.review('user-1', 'blacklist-1', reviewDto)).rejects.toThrow(ForbiddenException);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('checkBlacklist', () => {
|
||
|
|
it('应该正确检查玩家是否在黑名单', async () => {
|
||
|
|
jest.spyOn(blacklistRepository, 'findOne').mockResolvedValue({
|
||
|
|
...mockBlacklist,
|
||
|
|
status: BlacklistStatus.APPROVED,
|
||
|
|
} as any);
|
||
|
|
|
||
|
|
const result = await service.checkBlacklist('game-123');
|
||
|
|
|
||
|
|
expect(result.isBlacklisted).toBe(true);
|
||
|
|
expect(result.blacklist).toBeDefined();
|
||
|
|
expect(blacklistRepository.findOne).toHaveBeenCalledWith({
|
||
|
|
where: {
|
||
|
|
targetGameId: 'game-123',
|
||
|
|
status: BlacklistStatus.APPROVED,
|
||
|
|
},
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('玩家不在黑名单时应该返回false', async () => {
|
||
|
|
jest.spyOn(blacklistRepository, 'findOne').mockResolvedValue(null);
|
||
|
|
|
||
|
|
const result = await service.checkBlacklist('game-123');
|
||
|
|
|
||
|
|
expect(result.isBlacklisted).toBe(false);
|
||
|
|
expect(result.blacklist).toBeNull();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('remove', () => {
|
||
|
|
it('举报人应该可以删除自己的举报', async () => {
|
||
|
|
jest.spyOn(blacklistRepository, 'findOne').mockResolvedValue(mockBlacklist as any);
|
||
|
|
jest.spyOn(userRepository, 'findOne').mockResolvedValue(mockUser as any);
|
||
|
|
jest.spyOn(blacklistRepository, 'remove').mockResolvedValue(mockBlacklist as any);
|
||
|
|
|
||
|
|
const result = await service.remove('user-1', 'blacklist-1');
|
||
|
|
|
||
|
|
expect(result.message).toBe('删除成功');
|
||
|
|
expect(blacklistRepository.remove).toHaveBeenCalled();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('会员应该可以删除任何举报', async () => {
|
||
|
|
jest.spyOn(blacklistRepository, 'findOne').mockResolvedValue({
|
||
|
|
...mockBlacklist,
|
||
|
|
reporterId: 'other-user',
|
||
|
|
} as any);
|
||
|
|
jest.spyOn(userRepository, 'findOne').mockResolvedValue(mockUser as any);
|
||
|
|
jest.spyOn(blacklistRepository, 'remove').mockResolvedValue(mockBlacklist as any);
|
||
|
|
|
||
|
|
const result = await service.remove('user-1', 'blacklist-1');
|
||
|
|
|
||
|
|
expect(result.message).toBe('删除成功');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('非举报人且非会员删除时应该抛出异常', async () => {
|
||
|
|
jest.spyOn(blacklistRepository, 'findOne').mockResolvedValue({
|
||
|
|
...mockBlacklist,
|
||
|
|
reporterId: 'other-user',
|
||
|
|
} as any);
|
||
|
|
jest.spyOn(userRepository, 'findOne').mockResolvedValue({
|
||
|
|
...mockUser,
|
||
|
|
isMember: false,
|
||
|
|
} as any);
|
||
|
|
|
||
|
|
await expect(service.remove('user-1', 'blacklist-1')).rejects.toThrow(ForbiddenException);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|