Files
whale-town-end/src/business/admin/admin.controller.spec.ts
moyin 6924416bbd feat:实现管理员系统核心功能
- 添加管理员数据库管理控制器和服务
- 实现管理员操作日志记录系统
- 添加数据库异常处理过滤器
- 完善管理员权限验证和响应格式
- 添加全面的属性测试覆盖
2026-01-08 23:05:34 +08:00

237 lines
6.6 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.
/**
* AdminController 单元测试
*
* 功能描述:
* - 测试管理员控制器的所有HTTP端点
* - 验证请求参数处理和响应格式
* - 测试权限验证和异常处理
*
* 职责分离:
* - HTTP层测试不涉及业务逻辑实现
* - Mock业务服务专注控制器逻辑
* - 验证请求响应的正确性
*
* 最近修改:
* - 2026-01-07: 代码规范优化 - 创建AdminController测试文件补充测试覆盖
*
* @author moyin
* @version 1.0.1
* @since 2026-01-07
* @lastModified 2026-01-07
*/
import { Test, TestingModule } from '@nestjs/testing';
import { Response } from 'express';
import { AdminController } from './admin.controller';
import { AdminService } from './admin.service';
import { AdminGuard } from './admin.guard';
describe('AdminController', () => {
let controller: AdminController;
let adminService: jest.Mocked<AdminService>;
const mockAdminService = {
login: jest.fn(),
listUsers: jest.fn(),
getUser: jest.fn(),
resetPassword: jest.fn(),
getRuntimeLogs: jest.fn(),
getLogDirAbsolutePath: jest.fn(),
};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [AdminController],
providers: [
{
provide: AdminService,
useValue: mockAdminService,
},
],
})
.overrideGuard(AdminGuard)
.useValue({ canActivate: () => true })
.compile();
controller = module.get<AdminController>(AdminController);
adminService = module.get(AdminService);
});
afterEach(() => {
jest.clearAllMocks();
});
describe('login', () => {
it('should login admin successfully', async () => {
const loginDto = { identifier: 'admin', password: 'Admin123456' };
const expectedResult = {
success: true,
data: { admin: { id: '1', username: 'admin', role: 9 }, access_token: 'token' },
message: '管理员登录成功'
};
adminService.login.mockResolvedValue(expectedResult);
const result = await controller.login(loginDto);
expect(adminService.login).toHaveBeenCalledWith('admin', 'Admin123456');
expect(result).toEqual(expectedResult);
});
it('should handle login failure', async () => {
const loginDto = { identifier: 'admin', password: 'wrong' };
const expectedResult = {
success: false,
message: '密码错误',
error_code: 'ADMIN_LOGIN_FAILED'
};
adminService.login.mockResolvedValue(expectedResult);
const result = await controller.login(loginDto);
expect(result.success).toBe(false);
expect(result.error_code).toBe('ADMIN_LOGIN_FAILED');
});
});
describe('listUsers', () => {
it('should list users with default pagination', async () => {
const expectedResult = {
success: true,
data: {
users: [{ id: '1', username: 'user1' }],
limit: 100,
offset: 0
},
message: '用户列表获取成功'
};
adminService.listUsers.mockResolvedValue(expectedResult);
const result = await controller.listUsers();
expect(adminService.listUsers).toHaveBeenCalledWith(100, 0);
expect(result).toEqual(expectedResult);
});
it('should list users with custom pagination', async () => {
const expectedResult = {
success: true,
data: {
users: [],
limit: 50,
offset: 10
},
message: '用户列表获取成功'
};
adminService.listUsers.mockResolvedValue(expectedResult);
const result = await controller.listUsers('50', '10');
expect(adminService.listUsers).toHaveBeenCalledWith(50, 10);
expect(result).toEqual(expectedResult);
});
});
describe('getUser', () => {
it('should get user by id', async () => {
const expectedResult = {
success: true,
data: { user: { id: '123', username: 'testuser' } },
message: '用户信息获取成功'
};
adminService.getUser.mockResolvedValue(expectedResult);
const result = await controller.getUser('123');
expect(adminService.getUser).toHaveBeenCalledWith(BigInt(123));
expect(result).toEqual(expectedResult);
});
});
describe('resetPassword', () => {
it('should reset user password', async () => {
const resetDto = { newPassword: 'NewPass1234' };
const expectedResult = {
success: true,
message: '密码重置成功'
};
adminService.resetPassword.mockResolvedValue(expectedResult);
const result = await controller.resetPassword('123', resetDto);
expect(adminService.resetPassword).toHaveBeenCalledWith(BigInt(123), 'NewPass1234');
expect(result).toEqual(expectedResult);
});
});
describe('getRuntimeLogs', () => {
it('should get runtime logs with default lines', async () => {
const expectedResult = {
success: true,
data: {
file: 'app.log',
updated_at: '2026-01-07T00:00:00.000Z',
lines: ['log line 1', 'log line 2']
},
message: '运行日志获取成功'
};
adminService.getRuntimeLogs.mockResolvedValue(expectedResult);
const result = await controller.getRuntimeLogs();
expect(adminService.getRuntimeLogs).toHaveBeenCalledWith(undefined);
expect(result).toEqual(expectedResult);
});
it('should get runtime logs with custom lines', async () => {
const expectedResult = {
success: true,
data: {
file: 'app.log',
updated_at: '2026-01-07T00:00:00.000Z',
lines: ['log line 1']
},
message: '运行日志获取成功'
};
adminService.getRuntimeLogs.mockResolvedValue(expectedResult);
const result = await controller.getRuntimeLogs('100');
expect(adminService.getRuntimeLogs).toHaveBeenCalledWith(100);
expect(result).toEqual(expectedResult);
});
});
describe('downloadLogsArchive', () => {
let mockResponse: Partial<Response>;
beforeEach(() => {
mockResponse = {
setHeader: jest.fn(),
status: jest.fn().mockReturnThis(),
json: jest.fn(),
end: jest.fn(),
headersSent: false,
};
});
it('should handle missing log directory', async () => {
adminService.getLogDirAbsolutePath.mockReturnValue('/nonexistent/logs');
await controller.downloadLogsArchive(mockResponse as Response);
expect(mockResponse.status).toHaveBeenCalledWith(404);
expect(mockResponse.json).toHaveBeenCalledWith({
success: false,
message: '日志目录不存在'
});
});
});
});