/** * LoginController 单元测试 * * 功能描述: * - 测试登录控制器的HTTP请求处理 * - 验证API响应格式和状态码 * - 测试错误处理和异常情况 * * 最近修改: * - 2026-01-14: 架构重构 - 从business层移动到gateway层 (修改者: moyin) * - 2026-01-12: 代码规范优化 - 创建缺失的控制器测试文件 (修改者: moyin) * * @author moyin * @version 1.1.0 * @since 2026-01-12 * @lastModified 2026-01-14 */ import { Test, TestingModule } from '@nestjs/testing'; import { Response } from 'express'; import { HttpStatus } from '@nestjs/common'; import { LoginController } from './login.controller'; import { LoginService } from '../../business/auth/login.service'; describe('LoginController', () => { let controller: LoginController; let loginService: jest.Mocked; let mockResponse: jest.Mocked; beforeEach(async () => { const mockLoginService = { login: jest.fn(), githubOAuth: jest.fn(), sendPasswordResetCode: jest.fn(), resetPassword: jest.fn(), changePassword: jest.fn(), verificationCodeLogin: jest.fn(), sendLoginVerificationCode: jest.fn(), refreshAccessToken: jest.fn(), debugVerificationCode: jest.fn(), }; const module: TestingModule = await Test.createTestingModule({ controllers: [LoginController], providers: [ { provide: LoginService, useValue: mockLoginService, }, ], }).compile(); controller = module.get(LoginController); loginService = module.get(LoginService); // Mock Response object mockResponse = { status: jest.fn().mockReturnThis(), json: jest.fn().mockReturnThis(), } as any; }); it('should be defined', () => { expect(controller).toBeDefined(); }); describe('login', () => { it('should handle successful login', async () => { const loginDto = { identifier: 'testuser', password: 'password123' }; const mockResult = { success: true, data: { user: { id: '1', username: 'testuser', nickname: '测试用户', role: 1, created_at: new Date() }, access_token: 'token', refresh_token: 'refresh_token', expires_in: 3600, token_type: 'Bearer', message: '登录成功' }, message: '登录成功' }; loginService.login.mockResolvedValue(mockResult); await controller.login(loginDto, mockResponse); expect(loginService.login).toHaveBeenCalledWith({ identifier: 'testuser', password: 'password123' }); expect(mockResponse.status).toHaveBeenCalledWith(HttpStatus.OK); expect(mockResponse.json).toHaveBeenCalledWith(mockResult); }); it('should handle login failure', async () => { const loginDto = { identifier: 'testuser', password: 'wrongpassword' }; const mockResult = { success: false, message: '用户名或密码错误', error_code: 'LOGIN_FAILED' }; loginService.login.mockResolvedValue(mockResult); await controller.login(loginDto, mockResponse); expect(mockResponse.status).toHaveBeenCalledWith(HttpStatus.UNAUTHORIZED); expect(mockResponse.json).toHaveBeenCalledWith(mockResult); }); }); describe('githubOAuth', () => { it('should handle GitHub OAuth successfully', async () => { const githubDto = { github_id: '12345', username: 'githubuser', nickname: 'GitHub User', email: 'github@example.com' }; const mockResult = { success: true, data: { user: { id: '1', username: 'githubuser', nickname: 'GitHub User', role: 1, created_at: new Date() }, access_token: 'token', refresh_token: 'refresh_token', expires_in: 3600, token_type: 'Bearer', message: 'GitHub登录成功' }, message: 'GitHub登录成功' }; loginService.githubOAuth.mockResolvedValue(mockResult); await controller.githubOAuth(githubDto, mockResponse); expect(loginService.githubOAuth).toHaveBeenCalledWith(githubDto); expect(mockResponse.status).toHaveBeenCalledWith(HttpStatus.OK); expect(mockResponse.json).toHaveBeenCalledWith(mockResult); }); }); describe('refreshToken', () => { it('should handle token refresh successfully', async () => { const refreshTokenDto = { refresh_token: 'valid_refresh_token' }; const mockResult = { success: true, data: { access_token: 'new_access_token', refresh_token: 'new_refresh_token', expires_in: 3600, token_type: 'Bearer' }, message: '令牌刷新成功' }; loginService.refreshAccessToken.mockResolvedValue(mockResult); await controller.refreshToken(refreshTokenDto, mockResponse); expect(loginService.refreshAccessToken).toHaveBeenCalledWith('valid_refresh_token'); expect(mockResponse.status).toHaveBeenCalledWith(HttpStatus.OK); expect(mockResponse.json).toHaveBeenCalledWith(mockResult); }); it('should handle token refresh failure', async () => { const refreshTokenDto = { refresh_token: 'invalid_refresh_token' }; const mockResult = { success: false, message: '刷新令牌无效或已过期', error_code: 'TOKEN_REFRESH_FAILED' }; loginService.refreshAccessToken.mockResolvedValue(mockResult); await controller.refreshToken(refreshTokenDto, mockResponse); expect(mockResponse.status).toHaveBeenCalledWith(HttpStatus.UNAUTHORIZED); expect(mockResponse.json).toHaveBeenCalledWith(mockResult); }); }); });