From eafa40d7d30afc6ccfe6681542a795ac2b768e8c Mon Sep 17 00:00:00 2001 From: david akor Date: Mon, 30 Mar 2026 06:56:45 +0100 Subject: [PATCH] Fix: Add missing auth middleware tests - Create api/src/__tests__/auth.test.ts with comprehensive test coverage - Test all 5 required scenarios: valid token, missing token, expired token, invalid token, malformed header - Add additional edge cases for robust security testing - Mock JWT configuration properly for isolated testing - Follow existing test patterns from codebase - Addresses security-critical authentication testing gap Closes #37 --- api/src/__tests__/auth.test.ts | 118 +++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 api/src/__tests__/auth.test.ts diff --git a/api/src/__tests__/auth.test.ts b/api/src/__tests__/auth.test.ts new file mode 100644 index 0000000..e17febb --- /dev/null +++ b/api/src/__tests__/auth.test.ts @@ -0,0 +1,118 @@ +import { Request, Response, NextFunction } from 'express'; +import jwt from 'jsonwebtoken'; +import { authenticateToken, AuthRequest } from '../middleware/auth'; +import { UnauthorizedError } from '../utils/errors'; + +// Mock the config module +jest.mock('../config', () => ({ + config: { + auth: { + jwtSecret: 'test-secret-key-for-testing', + jwtExpiresIn: '1h' + } + } +})); + +describe('Auth Middleware', () => { + let mockRequest: Partial; + let mockResponse: Partial; + let mockNext: NextFunction; + + beforeEach(() => { + mockRequest = { + headers: {}, + }; + mockResponse = {}; + mockNext = jest.fn(); + }); + + describe('authenticateToken', () => { + it('should pass through with valid token', () => { + const validToken = jwt.sign({ address: '0x1234567890123456789012345678901234567890' }, 'test-secret-key-for-testing'); + mockRequest.headers = { + authorization: `Bearer ${validToken}`, + }; + + authenticateToken(mockRequest as AuthRequest, mockResponse as Response, mockNext); + + expect(mockNext).toHaveBeenCalledWith(); + expect(mockRequest.user).toEqual({ address: '0x1234567890123456789012345678901234567890' }); + }); + + it('should return 401 when token is missing', () => { + mockRequest.headers = {}; + + expect(() => { + authenticateToken(mockRequest as AuthRequest, mockResponse as Response, mockNext); + }).toThrow(UnauthorizedError); + + expect(mockNext).not.toHaveBeenCalled(); + }); + + it('should return 401 when token is expired', () => { + const expiredToken = jwt.sign( + { address: '0x1234567890123456789012345678901234567890' }, + 'test-secret-key-for-testing', + { expiresIn: '-1s' } + ); + mockRequest.headers = { + authorization: `Bearer ${expiredToken}`, + }; + + expect(() => { + authenticateToken(mockRequest as AuthRequest, mockResponse as Response, mockNext); + }).toThrow(UnauthorizedError); + + expect(mockNext).not.toHaveBeenCalled(); + }); + + it('should return 401 when token is invalid', () => { + const invalidToken = 'invalid-token-string'; + mockRequest.headers = { + authorization: `Bearer ${invalidToken}`, + }; + + expect(() => { + authenticateToken(mockRequest as AuthRequest, mockResponse as Response, mockNext); + }).toThrow(UnauthorizedError); + + expect(mockNext).not.toHaveBeenCalled(); + }); + + it('should return 401 when authorization header is malformed', () => { + mockRequest.headers = { + authorization: 'InvalidFormat token', + }; + + expect(() => { + authenticateToken(mockRequest as AuthRequest, mockResponse as Response, mockNext); + }).toThrow(UnauthorizedError); + + expect(mockNext).not.toHaveBeenCalled(); + }); + + it('should return 401 when authorization header has no token', () => { + mockRequest.headers = { + authorization: 'Bearer', + }; + + expect(() => { + authenticateToken(mockRequest as AuthRequest, mockResponse as Response, mockNext); + }).toThrow(UnauthorizedError); + + expect(mockNext).not.toHaveBeenCalled(); + }); + + it('should return 401 when authorization header has only Bearer without space', () => { + mockRequest.headers = { + authorization: 'Bearertoken', + }; + + expect(() => { + authenticateToken(mockRequest as AuthRequest, mockResponse as Response, mockNext); + }).toThrow(UnauthorizedError); + + expect(mockNext).not.toHaveBeenCalled(); + }); + }); +});