'use strict'; /** * Integration tests – Invoice controller (controllers/invoice.js) * * We focus on the read path (getInvoices_get) which does not require the full * complex invoice-creation pipeline (jobs, clients, Stripe, etc.). * A seeded Invoice document is created directly via the model for query tests. */ const { connectDB, disconnectDB, clearCollection } = require('./jest.setup'); const { mockApplicator, mockClient, mockReq, mockRes, newId } = require('./mock_data'); let Invoice, Customer, Client; beforeAll(async () => { await connectDB(); Invoice = require('../../model/invoice'); Customer = require('../../model/customer'); Client = require('../../model/client'); }); afterAll(async () => { await disconnectDB(); }); const invoiceCtl = require('../../controllers/invoice'); describe('Invoice controller – data methods', () => { let applicator, client; function makeInvoiceDoc(puid, clientId) { return { code: `INV-${Date.now()}`, companyName: 'Test Applicator Co.', address: '123 Main St', currency: 'USD', dueDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), openDate: new Date(), status: 'open', paymentTerm: 30, byPuid: puid, clients: [ { billTo: clientId, code: `INV-${Date.now()}-1`, split: '100', subTotal: '100.00', }, ], jobs: [], }; } beforeAll(async () => { await clearCollection(Invoice); applicator = await Customer.create(mockApplicator()); client = await Client.create(mockClient(applicator._id)); }); afterAll(async () => { await clearCollection(Invoice); await Client.deleteMany({ _id: client._id }); await Customer.deleteMany({ _id: applicator._id }); }); const makeReq = (extra = {}) => mockReq({ uid: applicator._id, puid: applicator._id, ut: '1', userInfo: { puid: applicator._id, kind: '1', premium: 0, membership: null, markedDelete: false, }, ...extra, }); // ------------------------------------------------------------------------- describe('getInvoices_get', () => { beforeAll(async () => { await Invoice.create(makeInvoiceDoc(applicator._id, client._id)); }); it('returns invoices for the applicator', async () => { const req = makeReq({ query: {} }); const res = mockRes(); await invoiceCtl.getInvoices_get(req, res); expect(res.json).toHaveBeenCalled(); expect(Array.isArray(res._data)).toBe(true); expect(res._data.length).toBeGreaterThan(0); }); it('returns empty array when no invoices match filter', async () => { const filters = JSON.stringify({ code: { value: 'NONEXISTENT_CODE_12345', valueOperator: 'contains' } }); const req = makeReq({ query: { filters } }); const res = mockRes(); await invoiceCtl.getInvoices_get(req, res); expect(res.json).toHaveBeenCalled(); expect(res._data.length).toBe(0); }); it('throws AppParamError when applicator puid is invalid', async () => { const req = mockReq({ uid: newId(), puid: 'invalid-puid', ut: '1', userInfo: { puid: 'invalid-puid', kind: '1', premium: 0, membership: null, markedDelete: false, }, }); const res = mockRes(); await expect(invoiceCtl.getInvoices_get(req, res)).rejects.toThrow(); }); }); });