import { describe, it, expect, vi, beforeEach } from 'vitest'; import request from 'supertest'; import { app } from '../index.js'; import pool from '../db.js'; import bcrypt from 'bcryptjs'; // Mock dependencies vi.mock('../db.js', () => ({ default: { query: vi.fn(), }, initDB: vi.fn() })); vi.mock('bcryptjs', () => ({ default: { compare: vi.fn(), hash: vi.fn() } })); describe('Auth Routes', () => { beforeEach(() => { vi.clearAllMocks(); }); describe('POST /api/auth/login', () => { it('logs in successfully with correct credentials', async () => { const mockUser = { id: 'u1', name: 'Test User', email: 'test@test.com', password_hash: 'hashed_password', role: 'employee', dept: 'dev' }; // Mock DB response pool.query.mockResolvedValue([[mockUser]]); // Mock bcrypt comparison bcrypt.compare.mockResolvedValue(true); const res = await request(app) .post('/api/auth/login') .send({ email: 'test@test.com', password: 'password' }); expect(res.status).toBe(200); expect(res.body).toEqual(expect.objectContaining({ id: 'u1', email: 'test@test.com' })); expect(res.body).not.toHaveProperty('password_hash'); }); it('returns 401 for invalid password', async () => { const mockUser = { id: 'u1', email: 'test@test.com', password_hash: 'hashed_password' }; pool.query.mockResolvedValue([[mockUser]]); bcrypt.compare.mockResolvedValue(false); const res = await request(app) .post('/api/auth/login') .send({ email: 'test@test.com', password: 'wrong' }); expect(res.status).toBe(401); expect(res.body).toEqual({ error: 'Invalid email or password' }); }); it('returns 401 for user not found', async () => { pool.query.mockResolvedValue([[]]); // Empty array const res = await request(app) .post('/api/auth/login') .send({ email: 'notfound@test.com', password: 'password' }); expect(res.status).toBe(401); }); }); describe('POST /api/auth/register', () => { it('registers a new user successfully', async () => { pool.query.mockResolvedValueOnce([[]]); // Check existing email (empty) pool.query.mockResolvedValueOnce({}); // Insert success bcrypt.hash.mockResolvedValue('hashed_new_password'); const newUser = { name: 'New User', email: 'new@test.com', password: 'password', role: 'employee' }; const res = await request(app) .post('/api/auth/register') .send(newUser); expect(res.status).toBe(201); expect(res.body).toEqual(expect.objectContaining({ name: 'New User', email: 'new@test.com' })); // Verify DB insert called expect(pool.query).toHaveBeenCalledTimes(2); expect(pool.query).toHaveBeenLastCalledWith( expect.stringContaining('INSERT INTO users'), expect.arrayContaining(['New User', 'employee', 'new@test.com', 'hashed_new_password']) ); }); it('returns 409 if email already exists', async () => { pool.query.mockResolvedValueOnce([[{ id: 'existing' }]]); const res = await request(app) .post('/api/auth/register') .send({ name: 'User', email: 'existing@test.com', password: 'pw' }); expect(res.status).toBe(409); }); }); });