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