# Test Inventory

# Bilko — Test Inventory

**Status:** Partially stale — recount required after Kotlin/Ktor migration and Playwright partitioning
**Version:** 2.1
**Last Updated:** 2026-05-21
**Author:** ALAI Documentation Team

This inventory catalogs implemented tests in Bilko, organized by package and file. It currently contains historical Express/Prisma-era details and must not be used as the source of truth for current test counts. For current policy, use [TEST-STRATEGY.md](./TEST-STRATEGY.md), [E2E-TEST-PLAN.md](./E2E-TEST-PLAN.md), and [DEMO-TESTING-PLAN.md](./DEMO-TESTING-PLAN.md).

---

## Summary

> **Refresh note (2026-05-21):** quick filesystem inventory found `apps/api/src/test/kotlin` with many Kotlin test files, `packages/core/tests`, and `apps/e2e/tests`. The table below is historical until regenerated from the current tree.

| Package                                 | Test Files    | Test Cases | Status      |
| --------------------------------------- | ------------- | ---------- | ----------- |
| `apps/api/tests/` (mock suite)          | 11 test files | ~130       | Implemented |
| `apps/api/tests/unit/` (unit suite)     | 4 test files  | ~60        | Implemented |
| `apps/api/tests/e2e/` (E2E suite)       | 2 test files  | ~30        | Implemented |
| `apps/api/tests/integration/` (real DB) | 5 test files  | ~50        | Implemented |
| `packages/core/tests/` (unit)           | 5 test files  | 121        | Implemented |
| **Total**                               | **27**        | **~390**   | Active      |

### Test Category Breakdown

| Category                                     | Description                                         | Requires DB          |
| -------------------------------------------- | --------------------------------------------------- | -------------------- |
| **Mock suite** (`tests/*.test.ts`)           | API endpoint tests with mocked Prisma — fast, no DB | No                   |
| **Unit suite** (`tests/unit/`)               | Service-layer tests, financial logic, SEF client    | No                   |
| **E2E suite** (`tests/e2e/`)                 | End-to-end billing flows with mocked services       | No                   |
| **Integration suite** (`tests/integration/`) | Real DB tests (docker-compose.test.yml)             | **Yes** — PostgreSQL |
| **Core unit** (`packages/core/`)             | Pure business logic — no HTTP, no DB                | No                   |

---

## `packages/core/tests/` — Unit Tests

Pure unit tests for the `@bilko/core` financial engine. No database, no HTTP. Uses `globals: true` (no explicit imports of `describe`/`it`/`expect`).

### `accounting.test.ts` — 20 tests

Tests double-entry bookkeeping engine: `validateDoubleEntry`, `createJournalEntry`, `calculateTrialBalance`.

| Test Name                                                           | What It Tests                       | Status      |
| ------------------------------------------------------------------- | ----------------------------------- | ----------- |
| `validateDoubleEntry - returns true for balanced entry`             | Debit total equals credit total     | Implemented |
| `validateDoubleEntry - returns false for unbalanced entry`          | Debit ≠ credit                      | Implemented |
| `validateDoubleEntry - returns false for fewer than 2 lines`        | Minimum 2 lines required            | Implemented |
| `validateDoubleEntry - returns false for empty lines`               | Empty array → false                 | Implemented |
| `validateDoubleEntry - returns false for negative amounts`          | Negative amounts invalid            | Implemented |
| `validateDoubleEntry - returns false for zero amounts`              | Zero amounts invalid                | Implemented |
| `validateDoubleEntry - handles multiple lines that sum to balanced` | Multi-line balanced entry           | Implemented |
| `validateDoubleEntry - handles decimal amounts with precision`      | NUMERIC(19,4) precision             | Implemented |
| `createJournalEntry - returns entry when valid and balanced`        | Happy path                          | Implemented |
| `createJournalEntry - throws for fewer than 2 lines`                | Error: "at least 2 lines"           | Implemented |
| `createJournalEntry - throws for empty lines array`                 | Error: "at least 2 lines"           | Implemented |
| `createJournalEntry - throws for missing description`               | Error: "must have a description"    | Implemented |
| `createJournalEntry - throws for whitespace-only description`       | Whitespace = missing                | Implemented |
| `createJournalEntry - throws for missing date`                      | Error: "must have a date"           | Implemented |
| `createJournalEntry - throws for unbalanced entry`                  | Error shows debit vs credit amounts | Implemented |
| `createJournalEntry - throws for negative amount lines`             | Negative amounts rejected           | Implemented |
| `calculateTrialBalance - returns balanced from balanced entries`    | isBalanced=true, totals correct     | Implemented |
| `calculateTrialBalance - groups by account number`                  | Rows aggregated per account         | Implemented |
| `calculateTrialBalance - returns empty rows for no transactions`    | Empty array → zero totals           | Implemented |
| `calculateTrialBalance - sorts rows by account number`              | Rows sorted ascending               | Implemented |

---

### `chart-of-accounts.test.ts` — 32 tests

Tests chart of accounts operations: account creation, parent-child hierarchy, account type validation.

| Test Area                                                        | Test Count | Status      |
| ---------------------------------------------------------------- | ---------- | ----------- |
| Account creation (valid + invalid inputs)                        | ~10        | Implemented |
| Account hierarchy (parent-child relationships)                   | ~8         | Implemented |
| Account type validation (Asset/Liability/Equity/Revenue/Expense) | ~7         | Implemented |
| Account code format validation (1xxx-5xxx range)                 | ~7         | Implemented |

---

### `invoicing.test.ts` — 22 tests

Tests invoice number generation, total calculations, and line item validation.

| Test Name                                                              | What It Tests                 | Status      |
| ---------------------------------------------------------------------- | ----------------------------- | ----------- |
| `generateInvoiceNumber - generates INV-YYYY-NNN format`                | Standard format               | Implemented |
| `generateInvoiceNumber - increments from last number`                  | Sequential numbering          | Implemented |
| `generateInvoiceNumber - pads number to 3 digits`                      | Zero-padding                  | Implemented |
| `generateInvoiceNumber - handles numbers beyond 999`                   | No truncation for 1000+       | Implemented |
| `generateInvoiceNumber - throws for empty prefix`                      | Error: "prefix is required"   | Implemented |
| `generateInvoiceNumber - throws for whitespace-only prefix`            | Whitespace = invalid          | Implemented |
| `generateInvoiceNumber - throws for negative lastNumber`               | Error: "non-negative integer" | Implemented |
| `generateInvoiceNumber - throws for non-integer lastNumber`            | Float rejected                | Implemented |
| `calculateInvoiceTotals - calculates line item total`                  | quantity × unitPrice          | Implemented |
| `calculateInvoiceTotals - calculates subtotal as sum of lines`         | Sum of all line totals        | Implemented |
| `calculateInvoiceTotals - calculates tax per line item`                | lineTotal × taxRate / 100     | Implemented |
| `calculateInvoiceTotals - calculates total = subtotal + tax`           | Final total                   | Implemented |
| `calculateInvoiceTotals - handles items without taxRate`               | Missing tax = 0               | Implemented |
| `calculateInvoiceTotals - returns zeros for empty items`               | Empty array → all zeros       | Implemented |
| `calculateInvoiceTotals - handles multiple items with different rates` | Mixed 20%/10% tax             | Implemented |
| `calculateInvoiceTotals - maintains decimal precision`                 | 3 × 33.33 = 99.99             | Implemented |
| `validateLineItem - returns true for valid item`                       | Happy path                    | Implemented |
| `validateLineItem - returns false for zero quantity`                   | qty=0 invalid                 | Implemented |
| `validateLineItem - returns false for negative quantity`               | qty<0 invalid                 | Implemented |
| `validateLineItem - returns false for negative unitPrice`              | price<0 invalid               | Implemented |
| `validateLineItem - returns false for empty description`               | Description required          | Implemented |
| `validateLineItem - returns false for whitespace-only description`     | Whitespace = empty            | Implemented |

---

### `multi-currency.test.ts` — 24 tests

Tests currency conversion, exchange rate locking, and NUMERIC precision handling.

| Test Area                                           | Test Count | Status      |
| --------------------------------------------------- | ---------- | ----------- |
| Currency conversion (EUR/RSD/BAM)                   | ~8         | Implemented |
| Exchange rate locking at transaction date           | ~6         | Implemented |
| NUMERIC(19,4) precision (no float drift)            | ~5         | Implemented |
| Edge cases (zero rate, missing rate, same currency) | ~5         | Implemented |

---

### `tax.test.ts` — 23 tests

Tests VAT calculations for all supported countries and edge cases.

| Test Area                                                 | Test Count | Status      |
| --------------------------------------------------------- | ---------- | ----------- |
| Serbia PDV (20% standard, 10% reduced, 0% exempt)         | ~6         | Implemented |
| BiH PDV (17% standard)                                    | ~4         | Implemented |
| Croatia PDV (25% standard, 13% reduced, 5% super-reduced) | ~5         | Implemented |
| Mixed tax rates on single invoice                         | ~3         | Implemented |
| Zero-rate exports                                         | ~2         | Implemented |
| Reverse VAT / gross-to-net                                | ~3         | Implemented |

---

## `apps/api/tests/` — Mock API Tests

Integration tests for Express API endpoints. Tests use **mocked Prisma client** — no real database required. Setup in `tests/setup.ts`.

### `setup.ts` — Test Infrastructure (not a test file)

Provides:

- Prisma client mock via `vi.mock('../src/lib/prisma')`
- Environment variable setup (JWT secrets, rate limits)
- `createTestUser()` — factory for test user objects
- `generateTestAccessToken()` — valid JWT for authenticated requests
- `generateTestRefreshToken()` — valid refresh token
- Constants: `TEST_ORG_ID`, `TEST_USER_ID`, `TEST_USER_EMAIL`

---

### `auth.test.ts` — 11 tests

| Test Name                                                   | Route               | Status      |
| ----------------------------------------------------------- | ------------------- | ----------- |
| `returns 201 with user, organization, and tokens`           | POST /auth/register | Implemented |
| `returns 400 for duplicate email`                           | POST /auth/register | Implemented |
| `returns 200 with tokens for valid credentials`             | POST /auth/login    | Implemented |
| `returns 401 for invalid password`                          | POST /auth/login    | Implemented |
| `returns 401 for non-existent email`                        | POST /auth/login    | Implemented |
| `returns 200 with new access token for valid refresh token` | POST /auth/refresh  | Implemented |
| `returns 401 when no refresh token cookie is present`       | POST /auth/refresh  | Implemented |
| `returns 204 and clears cookie`                             | POST /auth/logout   | Implemented |
| `returns 200 with current user when authenticated`          | GET /auth/me        | Implemented |
| `returns 401 when no token provided`                        | GET /auth/me        | Implemented |
| `returns 401 for invalid token`                             | GET /auth/me        | Implemented |

---

### `invoices.test.ts` — 11 tests

| Test Name                                                 | Route                      | Status      |
| --------------------------------------------------------- | -------------------------- | ----------- |
| `returns 200 with paginated list`                         | GET /invoices              | Implemented |
| `returns 401 without auth`                                | GET /invoices              | Implemented |
| `returns 201 with created invoice`                        | POST /invoices             | Implemented |
| `returns 200 with full invoice`                           | GET /invoices/:id          | Implemented |
| `returns 404 when invoice not found`                      | GET /invoices/:id          | Implemented |
| `returns 200 when updating draft invoice`                 | PUT /invoices/:id          | Implemented |
| `returns 400 when updating sent invoice`                  | PUT /invoices/:id          | Implemented |
| `returns 200 when sending invoice (draft -> sent)`        | PATCH /invoices/:id/status | Implemented |
| `returns 200 when marking invoice as paid (sent -> paid)` | PATCH /invoices/:id/status | Implemented |
| `returns 204 when deleting draft invoice`                 | DELETE /invoices/:id       | Implemented |
| `returns 400 when deleting sent invoice`                  | DELETE /invoices/:id       | Implemented |

---

### `expenses.test.ts` — 9 tests

| Test Area                                  | Route                       | Status      |
| ------------------------------------------ | --------------------------- | ----------- |
| List expenses (200 + auth)                 | GET /expenses               | Implemented |
| Create expense (201)                       | POST /expenses              | Implemented |
| Get expense by ID (200 + 404)              | GET /expenses/:id           | Implemented |
| Update expense (200 + 400 for non-pending) | PUT /expenses/:id           | Implemented |
| Approve expense (200 + role check)         | PATCH /expenses/:id/approve | Implemented |
| Delete expense (204 + 400 for approved)    | DELETE /expenses/:id        | Implemented |

---

### `contacts.test.ts` — 9 tests

| Test Area                         | Route                | Status      |
| --------------------------------- | -------------------- | ----------- |
| List contacts (200 + auth)        | GET /contacts        | Implemented |
| Create contact (201 + validation) | POST /contacts       | Implemented |
| Get contact (200 + 404)           | GET /contacts/:id    | Implemented |
| Update contact (200)              | PUT /contacts/:id    | Implemented |
| Delete contact (204)              | DELETE /contacts/:id | Implemented |

---

### `accounts.test.ts` — 4 tests

| Test Area                     | Route                | Status      |
| ----------------------------- | -------------------- | ----------- |
| List chart of accounts (200)  | GET /accounts        | Implemented |
| Get account by ID (200 + 404) | GET /accounts/:id    | Implemented |
| Create account (201)          | POST /accounts       | Implemented |
| Delete account (204)          | DELETE /accounts/:id | Implemented |

---

### `banking.test.ts` — 10 tests

| Test Area                                      | Route                                  | Status      |
| ---------------------------------------------- | -------------------------------------- | ----------- |
| List bank accounts (200)                       | GET /banking/accounts                  | Implemented |
| Create bank account (201)                      | POST /banking/accounts                 | Implemented |
| Import bank statement (200 + validation)       | POST /banking/accounts/:id/import      | Implemented |
| List bank transactions (200)                   | GET /banking/accounts/:id/transactions | Implemented |
| Reconcile transaction (200 + 400 for mismatch) | POST /banking/accounts/:id/reconcile   | Implemented |

---

### `reports.test.ts` — 9 tests

| Test Area                               | Route                      | Status      |
| --------------------------------------- | -------------------------- | ----------- |
| Profit & Loss report (200 + date range) | GET /reports/profit-loss   | Implemented |
| Balance sheet (200)                     | GET /reports/balance-sheet | Implemented |
| VAT report for RS (200 + correct rates) | GET /reports/vat           | Implemented |
| Trial balance (200)                     | GET /reports/trial-balance | Implemented |
| Auth required on all report endpoints   | All report routes          | Implemented |

---

### `transactions.test.ts` — 9 tests

| Test Area                            | Route                        | Status      |
| ------------------------------------ | ---------------------------- | ----------- |
| List transactions (200 + pagination) | GET /transactions            | Implemented |
| Filter by account (200)              | GET /transactions?accountId= | Implemented |
| Get transaction by ID (200 + 404)    | GET /transactions/:id        | Implemented |
| Auth required                        | All transaction routes       | Implemented |

---

### `country.test.ts` — 27 tests

Tests the country plugin integration — routes that return country-specific tax configuration.

| Test Area                                 | Route                       | Status      |
| ----------------------------------------- | --------------------------- | ----------- |
| Serbian PDV rates (20/10/0) for RS org    | GET /country/tax-rates      | Implemented |
| Bosnian PDV rate (17) for BA org          | GET /country/tax-rates      | Implemented |
| Croatian PDV rates (25/13/5/0) for HR org | GET /country/tax-rates      | Implemented |
| Invoice number format per country         | GET /country/invoice-format | Implemented |
| Auth required                             | All country routes          | Implemented |
| Unknown country code (400)                | GET /country/tax-rates      | Implemented |

---

### `chatbot.test.ts` — Chatbot API Tests

| Test Name                                    | Route                   | Status      |
| -------------------------------------------- | ----------------------- | ----------- |
| `returns 200 with assistant response`        | POST /chatbot/message   | Implemented |
| `returns 400 when message is empty`          | POST /chatbot/message   | Implemented |
| `returns 429 when rate limit exceeded`       | POST /chatbot/message   | Implemented |
| `returns 401 without auth`                   | POST /chatbot/message   | Implemented |
| `returns 200 with conversation history`      | GET /chatbot/history    | Implemented |
| `returns empty array when no history exists` | GET /chatbot/history    | Implemented |
| `returns 401 without auth on history`        | GET /chatbot/history    | Implemented |
| `returns 204 when history cleared`           | DELETE /chatbot/history | Implemented |
| `returns 401 without auth on clear history`  | DELETE /chatbot/history | Implemented |

---

### `invoice-gl-reversal.test.ts` — Invoice GL Reversal Tests

Tests `InvoiceService.cancelInvoice()` — when a SENT invoice is cancelled, reversing double-entry GL entries are created to undo the original booking.

| Test Area                                                        | Status      |
| ---------------------------------------------------------------- | ----------- |
| Cancels draft invoice (sets status to cancelled, no GL reversal) | Implemented |
| Cancels sent invoice (creates reversing GL transactions)         | Implemented |
| Reversal debits = original credits (GL stays balanced)           | Implemented |
| Throws 404 when invoice not found                                | Implemented |
| Throws 400 when invoice is already cancelled                     | Implemented |
| Throws 400 when invoice is paid (cannot cancel paid invoices)    | Implemented |

---

### `new-endpoints.test.ts` — Additional Endpoint Tests

Tests for supplemental endpoints not covered in the main mock suite.

| Test Area                              | Route                       | Status      |
| -------------------------------------- | --------------------------- | ----------- |
| Receipt not attached (404)             | GET /expenses/:id/receipt   | Implemented |
| Receipt auth required (401)            | GET /expenses/:id/receipt   | Implemented |
| VAT export PDF (200 / 404)             | GET /reports/vat/export/pdf | Implemented |
| VAT export XML (200 / 404)             | GET /reports/vat/export/xml | Implemented |
| Dashboard metrics (200)                | GET /reports/dashboard      | Implemented |
| Dashboard auth required (401)          | GET /reports/dashboard      | Implemented |
| Audit log (200 + owner/admin only)     | GET /security/audit-log     | Implemented |
| Audit log role check (403 for viewer)  | GET /security/audit-log     | Implemented |
| Data export (200 + owner only)         | POST /security/data-export  | Implemented |
| Data export role check (403 for admin) | POST /security/data-export  | Implemented |

---

### `e2e/api.test.ts` — Full E2E (no mocks, live server)

End-to-end API integration test. Exercises the full Express application stack with a live server.

| Status      |
| ----------- |
| Implemented |

---

### `e2e/billing-flow.e2e.test.ts` — Billing Workflow E2E

Tests the full billing flow through HTTP endpoints with mocked services (no real DB required):

1. Create contact
2. Create invoice
3. Send invoice (draft → sent)
4. Mark invoice paid (sent → paid)
5. Check P&L shows revenue
6. Verify trial balance returns `isBalanced=true`
7. Multi-currency invoice in EUR with country VAT rates
8. Credit note creation

| Status      |
| ----------- |
| Implemented |

---

## `apps/api/tests/unit/` — Unit Tests (service layer)

Service-level unit tests with mocked Prisma. No HTTP layer. Tests business logic in individual service classes.

### `invoice-service-calculations.test.ts` — Invoice Arithmetic

Tests `InvoiceService.createInvoice()` arithmetic at the service layer. Verifies:

- `lineTotal = quantity × unitPrice`
- `lineTax = lineTotal × taxRate / 100`
- `subtotal = sum(lineTotals)`
- `taxAmount = sum(lineTaxes)`
- `total = subtotal + taxAmount`
- `baseAmount = total × exchangeRate`

| Test Area                                | Status      |
| ---------------------------------------- | ----------- |
| Single-line invoice arithmetic           | Implemented |
| Multi-line invoice with mixed tax rates  | Implemented |
| Multi-currency exchange rate application | Implemented |
| Zero-quantity line items rejected        | Implemented |
| NUMERIC(19,4) precision maintained       | Implemented |

---

### `two-factor.test.ts` — Two-Factor Authentication Service

Tests `TwoFactorService` at the service level. Mocks: bcryptjs, speakeasy, qrcode, Prisma.

| Test Name                                                             | Status      |
| --------------------------------------------------------------------- | ----------- |
| `enable - wrong password → throws unauthorized`                       | Implemented |
| `enable - correct password → returns secret + QR data URL + 10 codes` | Implemented |
| `enable - backup codes are hashed before storing`                     | Implemented |
| `enable - plaintext backup codes returned once only`                  | Implemented |
| `verify - valid TOTP + window=1 → activates 2FA`                      | Implemented |
| `verify - invalid TOTP → throws badRequest`                           | Implemented |
| `disable - correct password → clears secret + backup codes`           | Implemented |
| `disable - wrong password → throws unauthorized`                      | Implemented |

---

### `sef-submission.test.ts` — SEF (Serbia E-Invoicing) Client

Tests `SefClient` class and `InvoiceService.submitToSef()` fire-and-forget behavior. HTTP calls are mocked via `vi.spyOn(global, 'fetch')`.

| Test Area                                                  | Status      |
| ---------------------------------------------------------- | ----------- |
| `SefClient` submits UBL XML to SEF sandbox URL             | Implemented |
| `SefClient` uses production URL in production env          | Implemented |
| `SefClient` retries on network failure                     | Implemented |
| `createSefClientFromEnv()` reads credentials from env vars | Implemented |
| `generateSEFInvoiceXML()` produces valid UBL 2.1 XML       | Implemented |
| `InvoiceService.submitToSef()` never re-throws errors      | Implemented |

---

### `vat-calculation.test.ts` — VAT Calculation Tests (Country Packages)

Tests pure calculation functions from `@bilko/country-rs`, `@bilko/country-ba`, and `@bilko/country-hr`. No Prisma, no HTTP — stateless math functions.

| Country     | Functions Tested                                                                                                                | Status      |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| **Serbia**  | `calculateSerbianPDV`, `calculateNetFromGrossPDV`, `qualifiesForPausalRegime`, `requiresVATRegistration`, `calculateSerbianCIT` | Implemented |
| **Bosnia**  | `calculateBosnianPDV`, `calculateNetFromGrossPDV`, `requiresVATRegistration`                                                    | Implemented |
| **Croatia** | `calculateCroatianPDV`, `calculateNetFromGrossPDV`, `requiresVATRegistration`                                                   | Implemented |
| All rates   | Standard, reduced, zero, super-reduced rates per country                                                                        | Implemented |

---

## `apps/api/tests/integration/` — Real Database Tests

Integration tests that run against a **real PostgreSQL database** via `docker-compose.test.yml`. Requires Docker.

**Run with:**

```bash
cd apps/api
docker-compose -f ../../docker-compose.test.yml up -d
npm run test:integration
```

### `auth.integration.test.ts` — Auth Integration

Full registration + login + refresh flow against real DB.

| Test Area                              | Status      |
| -------------------------------------- | ----------- |
| Register new organization + owner user | Implemented |
| Login with correct credentials         | Implemented |
| Refresh access token via cookie        | Implemented |
| Reject duplicate email registration    | Implemented |

---

### `invoice.integration.test.ts` — Invoice CRUD Integration

Invoice lifecycle against real DB: create → read → update → status change.

| Test Area                      | Status      |
| ------------------------------ | ----------- |
| Create invoice with line items | Implemented |
| Read invoice by ID             | Implemented |
| Update draft invoice           | Implemented |
| Send invoice (draft → sent)    | Implemented |
| Mark paid (sent → paid)        | Implemented |

---

### `credit-note-gl.integration.test.ts` — Credit Note GL Integration

Tests credit note creation against real DB — verifies reversing GL entries balance.

| Test Area                                     | Status      |
| --------------------------------------------- | ----------- |
| Credit note creates reversing journal entries | Implemented |
| Reversing entries balance (debits = credits)  | Implemented |
| Original invoice marked as credited           | Implemented |

---

### `report.integration.test.ts` — Reports Integration

Report generation against real DB with seeded transactions.

| Test Area                               | Status      |
| --------------------------------------- | ----------- |
| P&L report returns revenue/expense data | Implemented |
| VAT report returns correct tax amounts  | Implemented |
| Trial balance returns `isBalanced=true` | Implemented |

---

### `tenant-isolation.integration.test.ts` — Multi-Tenant Security

Verifies multi-tenant isolation: Organization A cannot read or modify Organization B's data.

| Test Area                                                    | Status      |
| ------------------------------------------------------------ | ----------- |
| Org A cannot list Org B's invoices                           | Implemented |
| Org A cannot read Org B's invoice by ID                      | Implemented |
| Org A cannot update Org B's invoice                          | Implemented |
| Org A cannot delete Org B's contact                          | Implemented |
| Cross-tenant requests return 404 (not 403 — no data leakage) | Implemented |

---

## Coverage Tracking

| Module                              | Current Status                        | Target |
| ----------------------------------- | ------------------------------------- | ------ |
| `@bilko/core` accounting engine     | Tests implemented (20 cases)          | >95%   |
| `@bilko/core` invoicing             | Tests implemented (22 cases)          | >95%   |
| `@bilko/core` tax/VAT               | Tests implemented (23 cases)          | >95%   |
| `@bilko/core` multi-currency        | Tests implemented (24 cases)          | >90%   |
| `@bilko/core` chart of accounts     | Tests implemented (32 cases)          | >90%   |
| Auth API                            | Tests implemented (11 cases)          | >85%   |
| Invoices API                        | Tests implemented (11 cases)          | >80%   |
| Expenses API                        | Tests implemented (9 cases)           | >80%   |
| Banking API                         | Tests implemented (10 cases)          | >75%   |
| Reports API                         | Tests implemented (9 cases)           | >75%   |
| Country/Tax-Rates API               | Tests implemented (27 cases)          | >80%   |
| Chatbot API                         | Tests implemented (9 cases)           | >80%   |
| Security/Audit API                  | Tests implemented (via new-endpoints) | >80%   |
| Invoice GL Reversal (service layer) | Tests implemented                     | >90%   |
| Two-Factor Auth (service layer)     | Tests implemented (8 cases)           | >90%   |
| SEF Client + Submission             | Tests implemented                     | >85%   |
| VAT Calculations (country packages) | Tests implemented                     | >95%   |
| Multi-tenant isolation (real DB)    | Tests implemented (5 scenarios)       | 100%   |
| Invoice CRUD (real DB)              | Tests implemented                     | >80%   |
| Credit note GL (real DB)            | Tests implemented                     | >90%   |

---

## Test Execution Commands

```bash
# All tests (from project root — mock + unit + E2E suites)
npm run test

# Core unit tests only
cd packages/core && npx vitest run

# API mock suite only (no DB required)
cd apps/api-express && npx vitest run

# API unit suite only
cd apps/api-express && npx vitest run tests/unit/

# API E2E suite only (mocked services, no DB)
cd apps/api-express && npx vitest run tests/e2e/

# Real DB integration tests (requires docker-compose.test.yml)
docker-compose -f docker-compose.test.yml up -d
cd apps/api-express && npm run test:integration

# Watch mode (re-run on change)
cd packages/core && npx vitest
cd apps/api-express && npx vitest

# Specific file
cd apps/api-express && npx vitest run tests/auth.test.ts
cd apps/api-express && npx vitest run tests/unit/two-factor.test.ts

# With coverage
cd packages/core && npx vitest run --coverage

# Verbose output
npx vitest run --reporter=verbose
```

---

## Related Documents

- Testing Guide: [TESTING-GUIDE.md](TESTING-GUIDE.md)
- Backend Architecture: [../backend/BACKEND-ARCHITECTURE.md](../backend/BACKEND-ARCHITECTURE.md)

---

**Last Updated:** 2026-03-02
**Status:** Active
**Total Tests:** ~390 across 27 test files (mock + unit + E2E + integration)