import { describe, it, expect, vi, beforeEach, afterAll } from 'vitest'; import request from 'supertest'; // Import the real app and db — Pool is lazy, no connection until query() const app = require('../app'); const db = require('../db'); // Replace pool.query with a mock — routes reference the same pool object const originalQuery = db.pool.query; db.pool.query = vi.fn(); afterAll(() => { db.pool.query = originalQuery; }); describe('GET /api/bills', () => { beforeEach(() => { db.pool.query.mockReset(); }); it('returns all bills', async () => { const mockBills = [ { id: 1, name: 'Electric', amount: 150, due_day: 15, assigned_paycheck: 1 }, { id: 2, name: 'Water', amount: 50, due_day: 20, assigned_paycheck: 2 }, ]; db.pool.query.mockResolvedValue({ rows: mockBills }); const res = await request(app).get('/api/bills'); expect(res.status).toBe(200); expect(res.body).toEqual(mockBills); }); it('returns 500 on db error', async () => { db.pool.query.mockRejectedValue(new Error('DB error')); const res = await request(app).get('/api/bills'); expect(res.status).toBe(500); expect(res.body).toEqual({ error: 'Failed to fetch bills' }); }); }); describe('POST /api/bills', () => { beforeEach(() => { db.pool.query.mockReset(); }); it('creates a bill with valid data', async () => { const newBill = { id: 1, name: 'Internet', amount: 80, due_day: 1, assigned_paycheck: 1, category: 'General', active: true, variable_amount: false }; db.pool.query.mockResolvedValue({ rows: [newBill] }); const res = await request(app) .post('/api/bills') .send({ name: 'Internet', amount: 80, due_day: 1, assigned_paycheck: 1 }); expect(res.status).toBe(201); expect(res.body).toEqual(newBill); }); it('returns 400 for invalid data', async () => { const res = await request(app) .post('/api/bills') .send({ name: '', amount: 80, due_day: 1, assigned_paycheck: 1 }); expect(res.status).toBe(400); expect(res.body).toEqual({ error: 'name is required' }); }); }); describe('GET /api/bills/:id', () => { beforeEach(() => { db.pool.query.mockReset(); }); it('returns a bill by id', async () => { const bill = { id: 1, name: 'Electric', amount: 150 }; db.pool.query.mockResolvedValue({ rows: [bill] }); const res = await request(app).get('/api/bills/1'); expect(res.status).toBe(200); expect(res.body).toEqual(bill); }); it('returns 404 when not found', async () => { db.pool.query.mockResolvedValue({ rows: [] }); const res = await request(app).get('/api/bills/999'); expect(res.status).toBe(404); expect(res.body).toEqual({ error: 'Bill not found' }); }); }); describe('DELETE /api/bills/:id', () => { beforeEach(() => { db.pool.query.mockReset(); }); it('deletes a bill', async () => { db.pool.query.mockResolvedValue({ rows: [{ id: 1 }] }); const res = await request(app).delete('/api/bills/1'); expect(res.status).toBe(200); expect(res.body).toEqual({ deleted: true, id: 1 }); }); it('returns 404 when bill not found', async () => { db.pool.query.mockResolvedValue({ rows: [] }); const res = await request(app).delete('/api/bills/999'); expect(res.status).toBe(404); }); }); describe('PATCH /api/bills/:id/toggle', () => { beforeEach(() => { db.pool.query.mockReset(); }); it('toggles bill active status', async () => { const toggled = { id: 1, name: 'Electric', active: false }; db.pool.query.mockResolvedValue({ rows: [toggled] }); const res = await request(app).patch('/api/bills/1/toggle'); expect(res.status).toBe(200); expect(res.body).toEqual(toggled); }); });