const JwtService = require('../../../src/application/services/JwtService'); const jwt = require('jsonwebtoken'); // Mock jsonwebtoken jest.mock('jsonwebtoken'); describe('JwtService', () => { let jwtService; const mockSecret = 'test-secret'; const mockExpiresIn = '1h'; beforeEach(() => { // Setup environment variables process.env.JWT_SECRET = mockSecret; process.env.JWT_EXPIRES_IN = mockExpiresIn; jwtService = new JwtService(); // Reset all mocks jest.clearAllMocks(); }); describe('generateToken', () => { it('should generate a JWT token with payload', () => { // Arrange const payload = { userId: 1, email: 'john@example.com' }; const mockToken = 'mock_jwt_token_abc123'; jwt.sign.mockReturnValue(mockToken); // Act const result = jwtService.generateToken(payload); // Assert expect(jwt.sign).toHaveBeenCalledWith(payload, mockSecret, { expiresIn: mockExpiresIn }); expect(result).toBe(mockToken); }); it('should use default secret if JWT_SECRET not set', () => { // Arrange delete process.env.JWT_SECRET; jwtService = new JwtService(); const payload = { userId: 1, email: 'john@example.com' }; jwt.sign.mockReturnValue('token'); // Act jwtService.generateToken(payload); // Assert expect(jwt.sign).toHaveBeenCalledWith(payload, 'default-secret-change-me', expect.any(Object)); }); }); describe('verifyToken', () => { it('should verify and return decoded token', () => { // Arrange const token = 'valid_token'; const mockDecoded = { userId: 1, email: 'john@example.com' }; jwt.verify.mockReturnValue(mockDecoded); // Act const result = jwtService.verifyToken(token); // Assert expect(jwt.verify).toHaveBeenCalledWith(token, mockSecret); expect(result).toEqual(mockDecoded); }); it('should throw error for invalid token', () => { // Arrange const token = 'invalid_token'; jwt.verify.mockImplementation(() => { throw new Error('jwt malformed'); }); // Act & Assert expect(() => jwtService.verifyToken(token)).toThrow('Invalid or expired token'); }); it('should throw error for expired token', () => { // Arrange const token = 'expired_token'; jwt.verify.mockImplementation(() => { throw new Error('jwt expired'); }); // Act & Assert expect(() => jwtService.verifyToken(token)).toThrow('Invalid or expired token'); }); }); describe('extractTokenFromCookies', () => { it('should extract token from cookies object', () => { // Arrange const cookies = { auth_token: 'abc123xyz' }; // Act const result = jwtService.extractTokenFromCookies(cookies); // Assert expect(result).toBe('abc123xyz'); }); it('should return null if cookies object is empty', () => { // Arrange const cookies = {}; // Act const result = jwtService.extractTokenFromCookies(cookies); // Assert expect(result).toBeNull(); }); it('should return null if cookies is null', () => { // Arrange const cookies = null; // Act const result = jwtService.extractTokenFromCookies(cookies); // Assert expect(result).toBeNull(); }); it('should return null if cookies is undefined', () => { // Arrange const cookies = undefined; // Act const result = jwtService.extractTokenFromCookies(cookies); // Assert expect(result).toBeNull(); }); }); describe('getCookieOptions', () => { it('should return secure cookie options in production', () => { // Arrange process.env.NODE_ENV = 'production'; jwtService = new JwtService(); // Act const options = jwtService.getCookieOptions(); // Assert expect(options.httpOnly).toBe(true); expect(options.secure).toBe(true); expect(options.sameSite).toBe('strict'); expect(options.path).toBe('/'); expect(options.maxAge).toBeGreaterThan(0); }); it('should return non-secure cookie options in development', () => { // Arrange process.env.NODE_ENV = 'development'; jwtService = new JwtService(); // Act const options = jwtService.getCookieOptions(); // Assert expect(options.httpOnly).toBe(true); expect(options.secure).toBe(false); expect(options.sameSite).toBe('strict'); }); }); describe('getCookieName', () => { it('should return the cookie name', () => { // Act const name = jwtService.getCookieName(); // Assert expect(name).toBe('auth_token'); }); }); describe('extractTokenFromHeader (legacy)', () => { it('should extract token from valid Authorization header', () => { // Arrange const authHeader = 'Bearer abc123xyz'; // Act const result = jwtService.extractTokenFromHeader(authHeader); // Assert expect(result).toBe('abc123xyz'); }); it('should return null if Authorization header is missing', () => { // Arrange const authHeader = null; // Act const result = jwtService.extractTokenFromHeader(authHeader); // Assert expect(result).toBeNull(); }); it('should return null if Authorization header does not start with Bearer', () => { // Arrange const authHeader = 'Basic abc123xyz'; // Act const result = jwtService.extractTokenFromHeader(authHeader); // Assert expect(result).toBeNull(); }); }); });