/** * 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; 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); 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; 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: '日志目录不存在' }); }); }); });