import { UserModel } from '../UserModel'; import { CreateUserInput } from '../types'; // Mock the database pool jest.mock('../../config/database', () => ({ query: jest.fn() })); // Mock the logger jest.mock('../../utils/logger', () => ({ info: jest.fn(), error: jest.fn(), warn: jest.fn() })); describe('UserModel', () => { let mockPool: any; beforeEach(() => { jest.clearAllMocks(); mockPool = require('../../config/database'); }); describe('create', () => { it('should create a new user successfully', async () => { const userData: CreateUserInput = { email: 'test@example.com', name: 'Test User', password: 'password123', role: 'user' }; const mockUser = { id: '123e4567-e89b-12d3-a456-426614174000', email: userData.email, name: userData.name, password_hash: 'hashed_password', role: userData.role, created_at: new Date(), updated_at: new Date(), is_active: true }; mockPool.query.mockResolvedValueOnce({ rows: [mockUser] }); const result = await UserModel.create(userData); expect(mockPool.query).toHaveBeenCalledWith( expect.stringContaining('INSERT INTO users'), [userData.email, userData.name, userData.password, userData.role] ); expect(result).toEqual(mockUser); }); it('should handle database errors', async () => { const userData: CreateUserInput = { email: 'test@example.com', name: 'Test User', password: 'password123' }; const error = new Error('Database error'); mockPool.query.mockRejectedValueOnce(error); await expect(UserModel.create(userData)).rejects.toThrow('Database error'); }); }); describe('findById', () => { it('should find user by ID successfully', async () => { const userId = '123e4567-e89b-12d3-a456-426614174000'; const mockUser = { id: userId, email: 'test@example.com', name: 'Test User', password_hash: 'hashed_password', role: 'user', created_at: new Date(), updated_at: new Date(), is_active: true }; mockPool.query.mockResolvedValueOnce({ rows: [mockUser] }); const result = await UserModel.findById(userId); expect(mockPool.query).toHaveBeenCalledWith( 'SELECT * FROM users WHERE id = $1 AND is_active = true', [userId] ); expect(result).toEqual(mockUser); }); it('should return null when user not found', async () => { const userId = '123e4567-e89b-12d3-a456-426614174000'; mockPool.query.mockResolvedValueOnce({ rows: [] }); const result = await UserModel.findById(userId); expect(result).toBeNull(); }); }); describe('findByEmail', () => { it('should find user by email successfully', async () => { const email = 'test@example.com'; const mockUser = { id: '123e4567-e89b-12d3-a456-426614174000', email, name: 'Test User', password_hash: 'hashed_password', role: 'user', created_at: new Date(), updated_at: new Date(), is_active: true }; mockPool.query.mockResolvedValueOnce({ rows: [mockUser] }); const result = await UserModel.findByEmail(email); expect(mockPool.query).toHaveBeenCalledWith( 'SELECT * FROM users WHERE email = $1 AND is_active = true', [email] ); expect(result).toEqual(mockUser); }); }); describe('update', () => { it('should update user successfully', async () => { const userId = '123e4567-e89b-12d3-a456-426614174000'; const updates = { name: 'Updated Name', email: 'updated@example.com' }; const mockUpdatedUser = { id: userId, ...updates, password_hash: 'hashed_password', role: 'user', created_at: new Date(), updated_at: new Date(), is_active: true }; mockPool.query.mockResolvedValueOnce({ rows: [mockUpdatedUser] }); const result = await UserModel.update(userId, updates); expect(mockPool.query).toHaveBeenCalledWith( expect.stringContaining('UPDATE users'), expect.arrayContaining([updates.name, updates.email, userId]) ); expect(result).toEqual(mockUpdatedUser); }); }); describe('delete', () => { it('should soft delete user successfully', async () => { const userId = '123e4567-e89b-12d3-a456-426614174000'; mockPool.query.mockResolvedValueOnce({ rows: [{ id: userId }] }); const result = await UserModel.delete(userId); expect(mockPool.query).toHaveBeenCalledWith( 'UPDATE users SET is_active = false WHERE id = $1 RETURNING id', [userId] ); expect(result).toBe(true); }); it('should return false when user not found', async () => { const userId = '123e4567-e89b-12d3-a456-426614174000'; mockPool.query.mockResolvedValueOnce({ rows: [] }); const result = await UserModel.delete(userId); expect(result).toBe(false); }); }); describe('emailExists', () => { it('should return true when email exists', async () => { const email = 'test@example.com'; mockPool.query.mockResolvedValueOnce({ rows: [{ id: '123' }] }); const result = await UserModel.emailExists(email); expect(mockPool.query).toHaveBeenCalledWith( 'SELECT id FROM users WHERE email = $1 AND is_active = true', [email] ); expect(result).toBe(true); }); it('should return false when email does not exist', async () => { const email = 'test@example.com'; mockPool.query.mockResolvedValueOnce({ rows: [] }); const result = await UserModel.emailExists(email); expect(result).toBe(false); }); }); describe('count', () => { it('should return correct user count', async () => { const expectedCount = 5; mockPool.query.mockResolvedValueOnce({ rows: [{ count: expectedCount.toString() }] }); const result = await UserModel.count(); expect(mockPool.query).toHaveBeenCalledWith( 'SELECT COUNT(*) FROM users WHERE is_active = true' ); expect(result).toBe(expectedCount); }); }); });