/** * Chart of Accounts Route Tests * * Tests for `/api/plugins/financials/accounts` endpoints * Uses REAL PostgreSQL database - NO mocks */ const request = require('supertest'); const express = require('express'); const accountsRouter = require('../../routes/accounts'); const FinancialTestHelper = require('../helpers/testHelper'); describe('Chart of Accounts Routes', () => { let app; let testHelper; let testSite; let testUserId; let chartOfAccountsRepository; beforeAll(async () => { // Create Express app for testing app = express(); app.use(express.json()); app.use('/api/plugins/financials', accountsRouter); // Initialize test helper testHelper = new FinancialTestHelper(); // Create test data testSite = await testHelper.createTestSite(); testUserId = testHelper.userId; // Import repository chartOfAccountsRepository = require('../../repositories').chartOfAccountsRepository; }); afterAll(async () => { // Cleanup handled by global schema manager }); describe('GET /api/plugins/financials/accounts', () => { it('should return all accounts for a site', async () => { // Create test accounts const accountsData = [ { site_id: testSite.id, account_code: '1000', account_name: 'Cash Account', account_type: 'asset', description: 'Cash and cash equivalents', is_active: true, created_by: testUserId }, { site_id: testSite.id, account_code: '2000', account_name: 'Accounts Payable', account_type: 'liability', description: 'Amounts owed to vendors', is_active: true, created_by: testUserId } ]; // Insert accounts using repository for (const account of accountsData) { await chartOfAccountsRepository.create(account); } const response = await request(app) .get('/api/plugins/financials/accounts') .query({ site_id: testSite.id }); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(response.body.data).toBeInstanceOf(Array); expect(response.body.data.length).toBeGreaterThanOrEqual(2); // Verify account structure matches expected format const account = response.body.data.find(a => a.account_code === '1000'); expect(account).toBeDefined(); expect(account.account_name).toBe('Cash Account'); expect(account.account_type).toBe('asset'); }); it('should return empty array if no accounts exist', async () => { // Create a different site with no accounts const anotherSite = await testHelper.createTestSite(); const response = await request(app) .get('/api/plugins/financials/accounts') .query({ site_id: anotherSite.id }); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(response.body.data).toEqual([]); }); it('should filter accounts by active status', async () => { // Create active and inactive accounts await chartOfAccountsRepository.create({ site_id: testSite.id, account_code: '3000', account_name: 'Active Account', account_type: 'asset', is_active: true, created_by: testUserId }); await chartOfAccountsRepository.create({ site_id: testSite.id, account_code: '4000', account_name: 'Inactive Account', account_type: 'asset', is_active: false, created_by: testUserId }); const response = await request(app) .get('/api/plugins/financials/accounts') .query({ site_id: testSite.id }); expect(response.status).toBe(200); // Should include both active and inactive (implementation detail) expect(response.body.data.length).toBeGreaterThan(0); }); }); describe('GET /api/plugins/financials/accounts/:id', () => { let testAccount; beforeEach(async () => { // Create a test account testAccount = await chartOfAccountsRepository.create({ site_id: testSite.id, account_code: '5000', account_name: 'Test Account', account_type: 'equity', description: 'Test account for detailed view', is_active: true, created_by: testUserId }); }); it('should return account details by ID', async () => { const response = await request(app) .get(`/api/plugins/financials/accounts/${testAccount.id}`) .query({ site_id: testSite.id }); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(response.body.data).toBeDefined(); expect(response.body.data.id).toBe(testAccount.id); expect(response.body.data.account_code).toBe('5000'); expect(response.body.data.account_name).toBe('Test Account'); }); it('should return 404 for non-existent account', async () => { const fakeId = '00000000-0000-0000-0000-000000000000'; const response = await request(app) .get(`/api/plugins/financials/accounts/${fakeId}`) .query({ site_id: testSite.id }); expect(response.status).toBe(404); }); }); describe('POST /api/plugins/financials/accounts', () => { it('should create a new account', async () => { const newAccount = { site_id: testSite.id, account_code: '6000', account_name: 'New Test Account', account_type: 'expense', description: 'Test expense account', is_active: true }; const response = await request(app) .post('/api/plugins/financials/accounts') .send(newAccount); expect(response.status).toBe(201); expect(response.body.success).toBe(true); expect(response.body.data).toBeDefined(); expect(response.body.data.account_code).toBe('6000'); expect(response.body.data.account_name).toBe('New Test Account'); }); it('should reject duplicate account codes for same site', async () => { const account1 = { site_id: testSite.id, account_code: '7000', account_name: 'First Account', account_type: 'asset', is_active: true }; await request(app) .post('/api/plugins/financials/accounts') .send(account1); // Try to create another with same code const account2 = { site_id: testSite.id, account_code: '7000', account_name: 'Duplicate Account', account_type: 'asset', is_active: true }; const response = await request(app) .post('/api/plugins/financials/accounts') .send(account2); // Should fail validation expect(response.status).toBeGreaterThanOrEqual(400); }); it('should require all required fields', async () => { const incompleteAccount = { site_id: testSite.id, account_name: 'Incomplete Account' // Missing account_code and account_type }; const response = await request(app) .post('/api/plugins/financials/accounts') .send(incompleteAccount); expect(response.status).toBe(400); }); }); describe('PUT /api/plugins/financials/accounts/:id', () => { let testAccount; beforeEach(async () => { testAccount = await chartOfAccountsRepository.create({ site_id: testSite.id, account_code: '8000', account_name: 'Original Name', account_type: 'revenue', description: 'Original description', is_active: true, created_by: testUserId }); }); it('should update account details', async () => { const updateData = { account_name: 'Updated Name', description: 'Updated description', is_active: false }; const response = await request(app) .put(`/api/plugins/financials/accounts/${testAccount.id}`) .send(updateData); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(response.body.data.account_name).toBe('Updated Name'); expect(response.body.data.description).toBe('Updated description'); expect(response.body.data.is_active).toBe(false); }); it('should return 404 for non-existent account', async () => { const fakeId = '00000000-0000-0000-0000-000000000000'; const response = await request(app) .put(`/api/plugins/financials/accounts/${fakeId}`) .send({ account_name: 'Test' }); expect(response.status).toBe(404); }); }); describe('DELETE /api/plugins/financials/accounts/:id', () => { let testAccount; beforeEach(async () => { testAccount = await chartOfAccountsRepository.create({ site_id: testSite.id, account_code: '9000', account_name: 'Account to Delete', account_type: 'asset', is_active: true, created_by: testUserId }); }); it('should delete an account', async () => { const response = await request(app) .delete(`/api/plugins/financials/accounts/${testAccount.id}`); expect(response.status).toBe(200); expect(response.body.success).toBe(true); // Verify account is deleted const deletedAccount = await chartOfAccountsRepository.findById(testAccount.id); expect(deletedAccount).toBeUndefined(); }); it('should return 404 for non-existent account', async () => { const fakeId = '00000000-0000-0000-0000-000000000000'; const response = await request(app) .delete(`/api/plugins/financials/accounts/${fakeId}`); expect(response.status).toBe(404); }); }); describe('GET /api/plugins/financials/accounts/:id/balance', () => { let testAccount; beforeEach(async () => { testAccount = await chartOfAccountsRepository.create({ site_id: testSite.id, account_code: '10000', account_name: 'Balance Test Account', account_type: 'asset', is_active: true, created_by: testUserId }); }); it('should return account balance calculation', async () => { const response = await request(app) .get(`/api/plugins/financials/accounts/${testAccount.id}/balance`) .query({ site_id: testSite.id, start_date: '2024-01-01', end_date: '2024-12-31' }); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(response.body.data).toBeDefined(); expect(response.body.data.account_id).toBeDefined(); // Balance calculation structure should exist // (exact structure depends on implementation) }); }); });