const authController = require('../controllers/auth.controller'); const { User } = require('../models'); const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken'); // Mock dependencies jest.mock('../models'); jest.mock('bcrypt'); jest.mock('jsonwebtoken'); describe('Auth Controller', () => { let req, res; beforeEach(() => { req = { body: {}, user: null }; res = { status: jest.fn().mockReturnThis(), json: jest.fn().mockReturnThis() }; jest.clearAllMocks(); }); describe('register', () => { it('should register a new user successfully', async () => { req.body = { username: 'testuser', email: 'test@example.com', password: 'Test123!@#' }; User.findOne = jest.fn().mockResolvedValue(null); User.create = jest.fn().mockResolvedValue({ id: '123', username: 'testuser', email: 'test@example.com', role: 'user' }); jwt.sign = jest.fn().mockReturnValue('mock-token'); await authController.register(req, res); expect(res.status).toHaveBeenCalledWith(201); expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ success: true, message: 'User registered successfully', data: expect.objectContaining({ token: 'mock-token', user: expect.objectContaining({ username: 'testuser', email: 'test@example.com' }) }) }) ); }); it('should return 400 if username already exists', async () => { req.body = { username: 'existinguser', email: 'new@example.com', password: 'Test123!@#' }; User.findOne = jest.fn().mockResolvedValue({ username: 'existinguser' }); await authController.register(req, res); expect(res.status).toHaveBeenCalledWith(400); expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ success: false, message: 'Username already exists' }) ); }); it('should return 409 if email already exists', async () => { req.body = { username: 'newuser', email: 'existing@example.com', password: 'Test123!@#' }; User.findOne = jest.fn() .mockResolvedValueOnce(null) // username check .mockResolvedValueOnce({ email: 'existing@example.com' }); // email check await authController.register(req, res); expect(res.status).toHaveBeenCalledWith(409); expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ success: false, message: 'Email already registered' }) ); }); it('should return 400 for missing required fields', async () => { req.body = { username: 'testuser' // missing email and password }; await authController.register(req, res); expect(res.status).toHaveBeenCalledWith(400); expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ success: false }) ); }); it('should return 500 on database error', async () => { req.body = { username: 'testuser', email: 'test@example.com', password: 'Test123!@#' }; User.findOne = jest.fn().mockRejectedValue(new Error('Database error')); await authController.register(req, res); expect(res.status).toHaveBeenCalledWith(500); expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ success: false, message: 'Internal server error' }) ); }); }); describe('login', () => { it('should login user successfully with email', async () => { req.body = { email: 'test@example.com', password: 'Test123!@#' }; const mockUser = { id: '123', username: 'testuser', email: 'test@example.com', password: 'hashed-password', role: 'user', isActive: true, save: jest.fn() }; User.findOne = jest.fn().mockResolvedValue(mockUser); bcrypt.compare = jest.fn().mockResolvedValue(true); jwt.sign = jest.fn().mockReturnValue('mock-token'); await authController.login(req, res); expect(res.status).toHaveBeenCalledWith(200); expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ success: true, message: 'Login successful', data: expect.objectContaining({ token: 'mock-token' }) }) ); }); it('should login user successfully with username', async () => { req.body = { username: 'testuser', password: 'Test123!@#' }; const mockUser = { id: '123', username: 'testuser', email: 'test@example.com', password: 'hashed-password', role: 'user', isActive: true, save: jest.fn() }; User.findOne = jest.fn().mockResolvedValue(mockUser); bcrypt.compare = jest.fn().mockResolvedValue(true); jwt.sign = jest.fn().mockReturnValue('mock-token'); await authController.login(req, res); expect(res.status).toHaveBeenCalledWith(200); }); it('should return 400 if user not found', async () => { req.body = { email: 'nonexistent@example.com', password: 'Test123!@#' }; User.findOne = jest.fn().mockResolvedValue(null); await authController.login(req, res); expect(res.status).toHaveBeenCalledWith(400); expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ success: false, message: 'Invalid credentials' }) ); }); it('should return 400 if password is incorrect', async () => { req.body = { email: 'test@example.com', password: 'WrongPassword' }; User.findOne = jest.fn().mockResolvedValue({ password: 'hashed-password' }); bcrypt.compare = jest.fn().mockResolvedValue(false); await authController.login(req, res); expect(res.status).toHaveBeenCalledWith(400); expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ success: false, message: 'Invalid credentials' }) ); }); it('should return 403 if user account is deactivated', async () => { req.body = { email: 'test@example.com', password: 'Test123!@#' }; User.findOne = jest.fn().mockResolvedValue({ isActive: false, password: 'hashed-password' }); bcrypt.compare = jest.fn().mockResolvedValue(true); await authController.login(req, res); expect(res.status).toHaveBeenCalledWith(403); expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ success: false, message: 'Account is deactivated' }) ); }); it('should return 400 for missing credentials', async () => { req.body = {}; await authController.login(req, res); expect(res.status).toHaveBeenCalledWith(400); }); }); describe('logout', () => { it('should logout user successfully', async () => { req.user = { id: '123' }; await authController.logout(req, res); expect(res.status).toHaveBeenCalledWith(200); expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ success: true, message: 'Logged out successfully' }) ); }); it('should handle logout without user context', async () => { req.user = null; await authController.logout(req, res); expect(res.status).toHaveBeenCalledWith(200); }); }); describe('verifyToken', () => { it('should verify user successfully', async () => { req.user = { id: '123', username: 'testuser', email: 'test@example.com', role: 'user' }; await authController.verifyToken(req, res); expect(res.status).toHaveBeenCalledWith(200); expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ success: true, message: 'Token is valid', data: expect.objectContaining({ user: expect.objectContaining({ id: '123', username: 'testuser' }) }) }) ); }); it('should return 401 if no user in request', async () => { req.user = null; await authController.verifyToken(req, res); expect(res.status).toHaveBeenCalledWith(401); expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ success: false, message: 'Unauthorized' }) ); }); }); });