Files

189 lines
6.2 KiB
TypeScript

import { Request, Response, NextFunction } from 'express';
// Mock JWTService before importing anything else
const mockJWTService = {
verify: jest.fn(),
refreshIfNeeded: jest.fn(),
create: jest.fn(),
shouldRefreshToken: jest.fn(),
test: jest.fn(),
};
jest.mock('../../../src/Application/Services/JWTService', () => {
return {
JWTService: jest.fn().mockImplementation(() => mockJWTService)
};
});
// Now import the middleware which will use the mocked JWTService
import { authRequired, adminRequired } from '../../../src/Application/Services/AuthMiddleware';
describe('AuthMiddleware', () => {
let mockRequest: Partial<Request>;
let mockResponse: Partial<Response>;
let mockNext: NextFunction;
beforeEach(() => {
jest.clearAllMocks();
mockRequest = {
cookies: {}
};
mockResponse = {
status: jest.fn().mockReturnThis(),
json: jest.fn().mockReturnThis(),
cookie: jest.fn()
};
mockNext = jest.fn();
});
describe('authRequired', () => {
it('should call next() when token is valid', () => {
// Arrange
const validPayload = {
userId: 'user-123',
authLevel: 0 as 0 | 1,
orgId: 'org-123'
};
mockJWTService.verify.mockReturnValue(validPayload);
mockJWTService.refreshIfNeeded.mockReturnValue(false); // Token doesn't need refresh
// Act
authRequired(mockRequest as Request, mockResponse as Response, mockNext);
// Assert
expect(mockJWTService.verify).toHaveBeenCalledWith(mockRequest);
expect(mockJWTService.refreshIfNeeded).toHaveBeenCalledWith(validPayload, mockResponse);
expect((mockRequest as any).user).toBe(validPayload);
expect(mockNext).toHaveBeenCalled();
expect(mockResponse.status).not.toHaveBeenCalled();
expect(mockResponse.json).not.toHaveBeenCalled();
});
it('should return 401 when token is invalid', () => {
// Arrange
mockJWTService.verify.mockReturnValue(null);
// Act
authRequired(mockRequest as Request, mockResponse as Response, mockNext);
// Assert
expect(mockJWTService.verify).toHaveBeenCalledWith(mockRequest);
expect(mockJWTService.refreshIfNeeded).not.toHaveBeenCalled();
expect(mockNext).not.toHaveBeenCalled();
expect(mockResponse.status).toHaveBeenCalledWith(401);
expect(mockResponse.json).toHaveBeenCalledWith({ error: 'Unauthorized' });
});
it('should refresh token when needed', () => {
// Arrange
const validPayload = {
userId: 'user-123',
authLevel: 0 as 0 | 1,
orgId: 'org-123'
};
mockJWTService.verify.mockReturnValue(validPayload);
mockJWTService.refreshIfNeeded.mockReturnValue(true); // Token needs refresh
// Act
authRequired(mockRequest as Request, mockResponse as Response, mockNext);
// Assert
expect(mockJWTService.verify).toHaveBeenCalledWith(mockRequest);
expect(mockJWTService.refreshIfNeeded).toHaveBeenCalledWith(validPayload, mockResponse);
expect((mockRequest as any).user).toBe(validPayload);
expect(mockNext).toHaveBeenCalled();
expect(mockResponse.status).not.toHaveBeenCalled();
expect(mockResponse.json).not.toHaveBeenCalled();
});
});
describe('adminRequired', () => {
it('should call next() when token is valid and user is admin', () => {
// Arrange
const adminPayload = {
userId: 'admin-123',
authLevel: 1 as 0 | 1,
orgId: 'org-123'
};
mockJWTService.verify.mockReturnValue(adminPayload);
mockJWTService.refreshIfNeeded.mockReturnValue(false);
// Act
adminRequired(mockRequest as Request, mockResponse as Response, mockNext);
// Assert
expect(mockJWTService.verify).toHaveBeenCalledWith(mockRequest);
expect(mockJWTService.refreshIfNeeded).toHaveBeenCalledWith(adminPayload, mockResponse);
expect((mockRequest as any).user).toBe(adminPayload);
expect(mockNext).toHaveBeenCalled();
expect(mockResponse.status).not.toHaveBeenCalled();
expect(mockResponse.json).not.toHaveBeenCalled();
});
it('should return 403 when token is invalid', () => {
// Arrange
mockJWTService.verify.mockReturnValue(null);
// Act
adminRequired(mockRequest as Request, mockResponse as Response, mockNext);
// Assert
expect(mockJWTService.verify).toHaveBeenCalledWith(mockRequest);
expect(mockJWTService.refreshIfNeeded).not.toHaveBeenCalled();
expect(mockNext).not.toHaveBeenCalled();
expect(mockResponse.status).toHaveBeenCalledWith(403);
expect(mockResponse.json).toHaveBeenCalledWith({ error: 'Forbidden' });
});
it('should return 403 when user is not admin', () => {
// Arrange
const regularUserPayload = {
userId: 'user-123',
authLevel: 0 as 0 | 1,
orgId: 'org-123'
};
mockJWTService.verify.mockReturnValue(regularUserPayload);
// Act
adminRequired(mockRequest as Request, mockResponse as Response, mockNext);
// Assert
expect(mockJWTService.verify).toHaveBeenCalledWith(mockRequest);
expect(mockJWTService.refreshIfNeeded).not.toHaveBeenCalled();
expect(mockNext).not.toHaveBeenCalled();
expect(mockResponse.status).toHaveBeenCalledWith(403);
expect(mockResponse.json).toHaveBeenCalledWith({ error: 'Forbidden' });
});
it('should refresh token for valid admin user', () => {
// Arrange
const adminPayload = {
userId: 'admin-123',
authLevel: 1 as 0 | 1,
orgId: 'org-123'
};
mockJWTService.verify.mockReturnValue(adminPayload);
mockJWTService.refreshIfNeeded.mockReturnValue(true);
// Act
adminRequired(mockRequest as Request, mockResponse as Response, mockNext);
// Assert
expect(mockJWTService.verify).toHaveBeenCalledWith(mockRequest);
expect(mockJWTService.refreshIfNeeded).toHaveBeenCalledWith(adminPayload, mockResponse);
expect((mockRequest as any).user).toBe(adminPayload);
expect(mockNext).toHaveBeenCalled();
expect(mockResponse.status).not.toHaveBeenCalled();
expect(mockResponse.json).not.toHaveBeenCalled();
});
});
});