Files
whale-town-end/src/business/notice/notice.service.spec.ts
moyin 874ccfa879 db:添加通知系统数据库支持
- 创建notices表结构SQL脚本
- 包含完整的字段定义和索引优化
- 添加通知服务单元测试用例
2026-01-10 21:52:48 +08:00

202 lines
5.6 KiB
TypeScript

import { Test, TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { NoticeService } from './notice.service';
import { NoticeGateway } from './notice.gateway';
import { Notice, NoticeStatus, NoticeType } from './notice.entity';
describe('NoticeService', () => {
let service: NoticeService;
let repository: Repository<Notice>;
let gateway: NoticeGateway;
const mockRepository = {
create: jest.fn(),
save: jest.fn(),
find: jest.fn(),
findOne: jest.fn(),
count: jest.fn(),
createQueryBuilder: jest.fn(),
};
const mockGateway = {
sendToUser: jest.fn(),
broadcast: jest.fn(),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
NoticeService,
{
provide: getRepositoryToken(Notice),
useValue: mockRepository,
},
{
provide: NoticeGateway,
useValue: mockGateway,
},
],
}).compile();
service = module.get<NoticeService>(NoticeService);
repository = module.get<Repository<Notice>>(getRepositoryToken(Notice));
gateway = module.get<NoticeGateway>(NoticeGateway);
});
afterEach(() => {
jest.clearAllMocks();
});
describe('create', () => {
it('should create and send notice immediately when no scheduledAt', async () => {
const createDto = {
title: 'Test Notice',
content: 'Test Content',
userId: 1,
};
const mockNotice = {
id: 1,
...createDto,
status: NoticeStatus.PENDING,
type: NoticeType.SYSTEM,
scheduledAt: null,
};
mockRepository.create.mockReturnValue(mockNotice);
mockRepository.save.mockResolvedValueOnce(mockNotice);
mockRepository.save.mockResolvedValueOnce({
...mockNotice,
status: NoticeStatus.SENT,
sentAt: new Date(),
});
const result = await service.create(createDto);
expect(mockRepository.create).toHaveBeenCalledWith({
...createDto,
scheduledAt: null,
});
expect(mockRepository.save).toHaveBeenCalledTimes(2);
expect(mockGateway.sendToUser).toHaveBeenCalledWith(1, {
type: 'notice',
data: mockNotice,
});
});
it('should create scheduled notice without sending immediately', async () => {
const scheduledAt = new Date(Date.now() + 3600000); // 1 hour later
const createDto = {
title: 'Scheduled Notice',
content: 'Scheduled Content',
scheduledAt: scheduledAt.toISOString(),
};
const mockNotice = {
id: 1,
...createDto,
scheduledAt,
status: NoticeStatus.PENDING,
};
mockRepository.create.mockReturnValue(mockNotice);
mockRepository.save.mockResolvedValue(mockNotice);
const result = await service.create(createDto);
expect(mockGateway.sendToUser).not.toHaveBeenCalled();
expect(mockGateway.broadcast).not.toHaveBeenCalled();
});
});
describe('sendSystemNotice', () => {
it('should create and send system notice', async () => {
const mockNotice = {
id: 1,
title: 'System Notice',
content: 'System Content',
type: NoticeType.SYSTEM,
userId: 1,
status: NoticeStatus.PENDING,
};
mockRepository.create.mockReturnValue(mockNotice);
mockRepository.save.mockResolvedValueOnce(mockNotice);
mockRepository.save.mockResolvedValueOnce({
...mockNotice,
status: NoticeStatus.SENT,
});
const result = await service.sendSystemNotice('System Notice', 'System Content', 1);
expect(result.type).toBe(NoticeType.SYSTEM);
expect(mockGateway.sendToUser).toHaveBeenCalled();
});
});
describe('sendBroadcast', () => {
it('should create and send broadcast notice', async () => {
const mockNotice = {
id: 1,
title: 'Broadcast Notice',
content: 'Broadcast Content',
type: NoticeType.BROADCAST,
userId: null,
status: NoticeStatus.PENDING,
};
mockRepository.create.mockReturnValue(mockNotice);
mockRepository.save.mockResolvedValueOnce(mockNotice);
mockRepository.save.mockResolvedValueOnce({
...mockNotice,
status: NoticeStatus.SENT,
});
const result = await service.sendBroadcast('Broadcast Notice', 'Broadcast Content');
expect(result.type).toBe(NoticeType.BROADCAST);
expect(mockGateway.broadcast).toHaveBeenCalled();
});
});
describe('markAsRead', () => {
it('should mark notice as read', async () => {
const mockNotice = {
id: 1,
userId: 1,
status: NoticeStatus.SENT,
};
const updatedNotice = {
...mockNotice,
status: NoticeStatus.READ,
readAt: new Date(),
};
mockRepository.findOne.mockResolvedValue(mockNotice);
mockRepository.save.mockResolvedValue(updatedNotice);
const result = await service.markAsRead(1, 1);
expect(result.status).toBe(NoticeStatus.READ);
expect(result.readAt).toBeDefined();
});
});
describe('getUserUnreadCount', () => {
it('should return unread count for user', async () => {
mockRepository.count.mockResolvedValue(5);
const count = await service.getUserUnreadCount(1);
expect(count).toBe(5);
expect(mockRepository.count).toHaveBeenCalledWith({
where: [
{ userId: 1, status: NoticeStatus.SENT },
{ userId: null, status: NoticeStatus.SENT },
],
});
});
});
});