Files
whale-town-end/src/business/auth/jwt_auth.guard.spec.ts
moyin 267f1b2263 style(auth):优化auth模块代码规范和测试覆盖
范围:src/business/auth/
- 统一命名规范和注释格式
- 完善文件头部注释和修改记录
- 分离登录和注册业务逻辑到独立服务
- 添加缺失的测试文件(JWT守卫、控制器测试)
- 清理未使用的测试文件
- 优化代码结构和依赖关系
2026-01-12 18:04:33 +08:00

163 lines
5.1 KiB
TypeScript

/**
* JwtAuthGuard 单元测试
*
* 功能描述:
* - 测试JWT认证守卫的令牌验证功能
* - 验证用户信息提取和注入
* - 测试认证失败的异常处理
*
* 最近修改:
* - 2026-01-12: 代码规范优化 - 创建缺失的守卫测试文件 (修改者: moyin)
*
* @author moyin
* @version 1.0.0
* @since 2026-01-12
* @lastModified 2026-01-12
*/
import { Test, TestingModule } from '@nestjs/testing';
import { ExecutionContext, UnauthorizedException } from '@nestjs/common';
import { JwtAuthGuard } from './jwt_auth.guard';
import { LoginCoreService } from '../../core/login_core/login_core.service';
describe('JwtAuthGuard', () => {
let guard: JwtAuthGuard;
let loginCoreService: jest.Mocked<LoginCoreService>;
let mockExecutionContext: jest.Mocked<ExecutionContext>;
let mockRequest: any;
beforeEach(async () => {
const mockLoginCoreService = {
verifyToken: jest.fn(),
};
const module: TestingModule = await Test.createTestingModule({
providers: [
JwtAuthGuard,
{
provide: LoginCoreService,
useValue: mockLoginCoreService,
},
],
}).compile();
guard = module.get<JwtAuthGuard>(JwtAuthGuard);
loginCoreService = module.get(LoginCoreService);
// Mock request object
mockRequest = {
headers: {},
user: undefined,
};
// Mock execution context
mockExecutionContext = {
switchToHttp: jest.fn().mockReturnValue({
getRequest: jest.fn().mockReturnValue(mockRequest),
}),
} as any;
});
it('should be defined', () => {
expect(guard).toBeDefined();
});
describe('canActivate', () => {
it('should allow access with valid JWT token', async () => {
const mockPayload = {
sub: '1',
username: 'testuser',
role: 1,
type: 'access' as const,
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + 3600,
};
mockRequest.headers.authorization = 'Bearer valid_jwt_token';
loginCoreService.verifyToken.mockResolvedValue(mockPayload);
const result = await guard.canActivate(mockExecutionContext);
expect(result).toBe(true);
expect(mockRequest.user).toEqual(mockPayload);
expect(loginCoreService.verifyToken).toHaveBeenCalledWith('valid_jwt_token', 'access');
});
it('should deny access when authorization header is missing', async () => {
mockRequest.headers.authorization = undefined;
await expect(guard.canActivate(mockExecutionContext))
.rejects.toThrow(UnauthorizedException);
expect(loginCoreService.verifyToken).not.toHaveBeenCalled();
});
it('should deny access when token format is invalid', async () => {
mockRequest.headers.authorization = 'InvalidFormat token';
await expect(guard.canActivate(mockExecutionContext))
.rejects.toThrow(UnauthorizedException);
expect(loginCoreService.verifyToken).not.toHaveBeenCalled();
});
it('should deny access when token is not Bearer type', async () => {
mockRequest.headers.authorization = 'Basic dXNlcjpwYXNz';
await expect(guard.canActivate(mockExecutionContext))
.rejects.toThrow(UnauthorizedException);
expect(loginCoreService.verifyToken).not.toHaveBeenCalled();
});
it('should deny access when JWT token verification fails', async () => {
mockRequest.headers.authorization = 'Bearer invalid_jwt_token';
loginCoreService.verifyToken.mockRejectedValue(new Error('Token expired'));
await expect(guard.canActivate(mockExecutionContext))
.rejects.toThrow(UnauthorizedException);
expect(loginCoreService.verifyToken).toHaveBeenCalledWith('invalid_jwt_token', 'access');
});
it('should extract token correctly from Authorization header', async () => {
const mockPayload = {
sub: '1',
username: 'testuser',
role: 1,
type: 'access' as const,
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + 3600,
};
mockRequest.headers.authorization = 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.token';
loginCoreService.verifyToken.mockResolvedValue(mockPayload);
const result = await guard.canActivate(mockExecutionContext);
expect(result).toBe(true);
expect(loginCoreService.verifyToken).toHaveBeenCalledWith(
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.token',
'access'
);
});
it('should handle empty token after Bearer', async () => {
mockRequest.headers.authorization = 'Bearer ';
await expect(guard.canActivate(mockExecutionContext))
.rejects.toThrow(UnauthorizedException);
expect(loginCoreService.verifyToken).not.toHaveBeenCalled();
});
it('should handle authorization header with only Bearer', async () => {
mockRequest.headers.authorization = 'Bearer';
await expect(guard.canActivate(mockExecutionContext))
.rejects.toThrow(UnauthorizedException);
expect(loginCoreService.verifyToken).not.toHaveBeenCalled();
});
});
});