Files
whale-town-end/src/business/zulip/chat.controller.spec.ts

195 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 聊天控制器测试
*
* 功能描述:
* - 测试聊天消息发送功能
* - 验证消息过滤和验证逻辑
* - 测试错误处理和异常情况
* - 验证WebSocket消息广播功能
*
* 测试范围:
* - 消息发送API测试
* - 参数验证测试
* - 错误处理测试
* - 业务逻辑验证
*
* 最近修改:
* - 2026-01-12: Bug修复 - 修复测试用例中的方法名和DTO结构 (修改者: moyin)
* - 2026-01-12: 代码规范优化 - 创建测试文件,确保控制器功能的测试覆盖 (修改者: moyin)
*
* @author moyin
* @version 1.0.1
* @since 2026-01-12
* @lastModified 2026-01-12
*/
import { Test, TestingModule } from '@nestjs/testing';
import { HttpException, HttpStatus } from '@nestjs/common';
import { ChatController } from './chat.controller';
import { ZulipService } from './zulip.service';
import { MessageFilterService } from './services/message_filter.service';
import { CleanWebSocketGateway } from './clean_websocket.gateway';
import { JwtAuthGuard } from '../auth/jwt_auth.guard';
// Mock JwtAuthGuard
const mockJwtAuthGuard = {
canActivate: jest.fn(() => true),
};
describe('ChatController', () => {
let controller: ChatController;
let zulipService: jest.Mocked<ZulipService>;
let messageFilterService: jest.Mocked<MessageFilterService>;
let websocketGateway: jest.Mocked<CleanWebSocketGateway>;
beforeEach(async () => {
const mockZulipService = {
sendChatMessage: jest.fn(),
};
const mockMessageFilterService = {
validateMessage: jest.fn(),
};
const mockWebSocketGateway = {
broadcastToRoom: jest.fn(),
getActiveConnections: jest.fn(),
};
const module: TestingModule = await Test.createTestingModule({
controllers: [ChatController],
providers: [
{
provide: ZulipService,
useValue: mockZulipService,
},
{
provide: MessageFilterService,
useValue: mockMessageFilterService,
},
{
provide: CleanWebSocketGateway,
useValue: mockWebSocketGateway,
},
{
provide: JwtAuthGuard,
useValue: mockJwtAuthGuard,
},
],
})
.overrideGuard(JwtAuthGuard)
.useValue(mockJwtAuthGuard)
.compile();
controller = module.get<ChatController>(ChatController);
zulipService = module.get(ZulipService);
messageFilterService = module.get(MessageFilterService);
websocketGateway = module.get(CleanWebSocketGateway);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
describe('sendMessage', () => {
const validMessageDto = {
content: 'Hello, world!',
stream: 'general',
topic: 'chat',
userId: 'user123',
scope: 'local',
};
it('should reject REST API message sending and suggest WebSocket', async () => {
// Act & Assert
await expect(controller.sendMessage(validMessageDto)).rejects.toThrow(
new HttpException(
'聊天消息发送需要通过 WebSocket 连接。请使用 WebSocket 接口wss://whaletownend.xinghangee.icu',
HttpStatus.BAD_REQUEST,
)
);
});
it('should log the REST API request attempt', async () => {
// Arrange
const loggerSpy = jest.spyOn(controller['logger'], 'log');
// Act
try {
await controller.sendMessage(validMessageDto);
} catch (error) {
// Expected to throw
}
// Assert
expect(loggerSpy).toHaveBeenCalledWith('收到REST API聊天消息发送请求', {
operation: 'sendMessage',
content: validMessageDto.content.substring(0, 50),
scope: validMessageDto.scope,
timestamp: expect.any(String),
});
});
it('should handle different message content lengths', async () => {
// Arrange
const longMessageDto = {
...validMessageDto,
content: 'a'.repeat(100), // Long message
};
// Act & Assert
await expect(controller.sendMessage(longMessageDto)).rejects.toThrow(HttpException);
});
it('should handle empty message content', async () => {
// Arrange
const emptyMessageDto = { ...validMessageDto, content: '' };
// Act & Assert
await expect(controller.sendMessage(emptyMessageDto)).rejects.toThrow(HttpException);
});
});
describe('Error Handling', () => {
it('should always throw HttpException for REST API requests', async () => {
// Arrange
const validMessageDto = {
content: 'Hello, world!',
stream: 'general',
topic: 'chat',
userId: 'user123',
scope: 'local',
};
// Act & Assert
await expect(controller.sendMessage(validMessageDto)).rejects.toThrow(HttpException);
});
it('should log error when REST API is used', async () => {
// Arrange
const validMessageDto = {
content: 'Hello, world!',
stream: 'general',
topic: 'chat',
userId: 'user123',
scope: 'local',
};
const loggerSpy = jest.spyOn(controller['logger'], 'error');
// Act
try {
await controller.sendMessage(validMessageDto);
} catch (error) {
// Expected to throw
}
// Assert
expect(loggerSpy).toHaveBeenCalledWith('REST API消息发送失败', {
operation: 'sendMessage',
error: expect.any(String),
timestamp: expect.any(String),
});
});
});
});