Skip to main content

Test Inventory

Bilko —Drop Test Inventory

Status: Active — Tests Implemented Version: 2.0 Last Updated:updated: 2026-03-0202-13 Author:Source: ALAIsrc/drop-app/tests/ DocumentationTotal Team

test

Thisfiles: inventory14 catalogs(7 allunit, implemented1 testsintegration, in1 Bilko,performance, organized1 byregression, package3 andE2E, file.1 setup)


SummaryDirectory Structure

tests/
  setup.ts                              # Global setup (sets NODE_ENV=test)
  unit/
    auth.test.ts                        # Password hashing + JWT tokens
    db.test.ts                          # Database schema validation
    feature-flags.test.ts               # Feature flag system
    middleware.test.ts                   # Rate limiting + error responses
    utils.test.ts                       # Utility functions (randomId, maskBankAccount)
    validation.test.ts                  # Input validation functions
    api-routes.test.ts                  # API routes with DB integration
  integration/
    api-endpoints.test.ts               # Full API endpoint integration tests
  performance/
    api-benchmarks.test.ts              # Performance benchmarks
  regression/
    known-bugs.test.ts                  # Regression tests for fixed bugs
  e2e/
    user-flows.spec.ts                  # Basic user journey E2E
    full-flows.spec.ts                  # Complete feature journey E2E
    input-chaos.spec.ts                 # Malicious/edge-case input E2E

Unit Tests (Vitest)

tests/unit/auth.test.ts -- 7 tests

Password Hashing (4 tests):

  • hashPassword produces bcrypt hash (starts with $2)
  • verifyPassword validates correct bcrypt password
  • verifyPassword rejects wrong password
  • verifyPassword does NOT accept SHA-256 hashes (security fix C4)

JWT Token Management (3 tests):

  • signToken and verifyToken round-trip works
  • verifyToken rejects invalid tokens
  • verifyToken rejects tampered tokens

tests/unit/db.test.ts -- 5 tests

  • Creates all 11 expected tables (users, transactions, recipients, merchants, cards, bank_accounts, sessions, notifications, settings, exchange_rates, spending_limits)
  • Users table does NOT have balance column (pass-through model verification)
  • Cards table does NOT have card_number or cvv columns (PCI-DSS fix verification). Has last_four and token_ref instead.
  • Transaction type constraint only allows remittance and qr_payment
  • Foreign key constraints are enforced

tests/unit/feature-flags.test.ts -- 6 tests

  • isEnabled returns default when no env var is set
  • isEnabled reads NEXT_PUBLIC_FF_* env vars
  • featureGate returns 404-like response when disabled
  • featureGate returns null when enabled
  • getAllFlags returns complete flag set (8 flags)
  • topUpViaCard flag does NOT exist (removed feature)

tests/unit/middleware.test.ts -- 7 tests

Rate Limiting (3 tests):

  • Allows requests within limit
  • Blocks after limit exceeded
  • Resets after window expires

jsonError (2 tests):

  • Returns correct JSON format ({error, message, details})
  • Includes details array when provided

getClientIp (2 tests):

  • Extracts from X-Forwarded-For header (first IP)
  • Returns 127.0.0.1 when no header present

tests/unit/utils.test.ts -- 5 tests

randomId (3 tests):

  • Generates prefixed IDs with correct format (prefix_<hex16>)
  • Generates unique IDs on each call
  • Uses the provided prefix

maskBankAccount (2 tests):

  • Masks correctly, showing only last 4 characters
  • Returns short accounts unchanged

tests/unit/validation.test.ts -- 10 tests

Email Validation (2 tests):

  • Accepts valid emails (standard, tag, domain variants)
  • Rejects invalid emails (empty, no @, space, null)

Phone Validation (2 tests):

  • Accepts international format (+47, +381)
  • Rejects invalid numbers (no +, too short, letters, null)

Amount Validation (2 tests):

  • Accepts valid positive amounts (including 0.01)
  • Rejects negative, zero, NaN, and >2 decimal places

IBAN Validation (2 tests):

  • Validates correct IBANs (Norwegian, German)
  • Rejects invalid IBANs (empty, too short, bad checksum, null)

Name Validation (6 tests, grouped):

  • Accepts valid names (Latin, Bosnian chars, apostrophes, hyphens, umlauts)
  • Rejects numbers-only input
  • Accepts names with numbers mixed in (has letters)
  • Rejects empty and null
  • Rejects XSS payloads (<script>, onclick=)
  • Rejects special-chars-only input

PIN Validation (2 tests):

  • Validates 4-digit PINs
  • Rejects invalid PINs (too short, too long, letters, null)

tests/unit/api-routes.test.ts -- 8 test groups

  1. DB + Auth Integration -- User creation with bcrypt, password verification, hash uniqueness
  2. Exchange Rates Seeded -- 6 NOK rates, queryable for API response
  3. Rate Limiting -- Allows within limit, blocks after exceeded, resets after window, cleans expired entries
  4. User Registration Flow -- Insert, unique constraint, default values, KYC/role constraints
  5. Session Tracking -- Create, retrieve, revocation, expiry, index verification
  6. End-to-End User Flow -- Register -> login -> session -> revoke
  7. Foreign Key Constraints -- Cannot create orphan sessions, cannot delete user with sessions
  8. Utility Functions -- randomId format and uniqueness

Integration Tests (Vitest)

tests/integration/api-endpoints.test.ts -- 20+ tests

Tests actual API route handlers with mocked database and auth.

POST /api/auth/register (5 tests):

  • Successfully registers with valid input (201, checks DB)
  • Returns 422 for missing email
  • Returns 422 for short password
  • Returns 422 for missing first name
  • Returns 409 for duplicate email
  • Returns 400 for invalid JSON body

POST /api/auth/login (5 tests):

  • Successfully logs in with valid credentials (200)
  • Returns 401 for wrong password
  • Returns 401 for non-existent user
  • Returns 400 for missing email or password
  • Returns 400 for invalid JSON body

GET /api/rates (2 tests):

  • Returns all exchange rates (6 currencies)
  • Returns empty rates when none seeded

GET /api/rates/[currency] (3 tests):

  • Returns rate for valid currency
  • Returns 404 for unsupported currency
  • Handles case-insensitive codes

POST /api/transactions/remittance (7 tests):

  • Successfully creates remittance (201, verifies balance deduction)
  • Returns 401 when not authenticated
  • Returns 403 when KYC not approved
  • Returns 404 when recipient not found
  • Returns 402 when insufficient balance
  • Returns 400 for amount below/above limits
  • Returns 400 for invalid amount (NaN)

POST /api/transactions/qr-payment (8 tests):

  • Successfully creates QR payment (201, verifies balance, fee calc)
  • Returns 401 when not authenticated
  • Returns 404 when merchant not found
  • Returns 402 when insufficient balance
  • Returns 400 for amount below/above limits
  • Returns 400 for missing merchantId
  • Returns 400 for invalid JSON body

Performance Tests (Vitest)

tests/performance/api-benchmarks.test.ts -- 8 tests

<
PackageTest Test FilesTest CasesStatusThreshold
apps/api/tests/hashPassword (mockbcrypt suite)rounds=12) 11< test files~130Implemented1000ms
apps/api/tests/unit/verifyPassword (unitbcrypt suite)compare) 4< test files~60Implemented1000ms
apps/api/tests/e2e/rateLimit (E2Esingle suite)check 2< test files~30Implemented50ms
apps/api/tests/integration/DB (realSELECT DB)query 5< test files~50Implemented10ms
packages/core/tests/DB (unit)INSERT query 5< test files121Implemented20ms
TotalExchange rate lookup 27 ~390Active

Test Category Breakdown

CategoryDescriptionRequires DB
Mock suite (tests/*.test.ts)API endpoint tests with mocked Prisma — fast, no DBNo10ms
Unit50 suiteconcurrent (tests/unit/)rateLimit calls Service-layer< tests,2000ms financial logic, SEF clientNototal
E2ETransaction suite (tests/e2e/)INSERT End-to-end< billing flows with mocked servicesNo
Integration suite (tests/integration/)Real DB tests (docker-compose.test.yml)Yes — PostgreSQL
Core unit (packages/core/)Pure business logic — no HTTP, no DBNo50ms

packages/core/tests/ — UnitRegression Tests

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

Vitest)

accounting.tests/regression/known-bugs.test.ts -- 204 testsbug groups

TestsBUG-001: double-entry bookkeeping engine: validateDoubleEntry, createJournalEntry, calculateTrialBalance.

Test NameWhat It TestsStatus
validateDoubleEntry - returns true for balanced entryDebit total equals credit totalImplemented
validateDoubleEntry - returns false for unbalanced entryDebit ≠ creditImplemented
validateDoubleEntry - returns false for fewer than 2 linesMinimum 2 lines requiredImplemented
validateDoubleEntry - returns false for empty linesEmpty array → falseImplemented
validateDoubleEntry - returns false for negative amountsNegative amounts invalidImplemented
validateDoubleEntry - returns false for zero amountsZero amounts invalidImplemented
validateDoubleEntry - handles multiple lines that sum to balancedMulti-line balanced entryImplemented
validateDoubleEntry - handles decimal amounts with precisionNUMERIC(19,4) precisionImplemented
createJournalEntry - returns entry when valid and balancedHappy pathImplemented
createJournalEntry - throws for fewer than 2 linesError: "at least 2 lines"Implemented
createJournalEntry - throws for empty lines arrayError: "at least 2 lines"Implemented
createJournalEntry - throws forrateLimit() missing descriptionError: "must have a description"Implemented
createJournalEntry - throws for whitespace-only descriptionWhitespace = missingImplemented
createJournalEntry - throws for missing dateError: "must have a date"Implemented
createJournalEntry - throws for unbalanced entryError shows debit vs credit amountsImplemented
createJournalEntry - throws for negative amount linesNegative amounts rejectedImplemented
calculateTrialBalance - returns balanced from balanced entriesisBalanced=true, totals correctImplemented
calculateTrialBalance - groups by account numberRows aggregated per accountImplemented
calculateTrialBalance - returns empty rows for no transactionsEmpty array → zero totalsImplemented
calculateTrialBalance - sorts rows by account numberRows sorted ascendingImplemented

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

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

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

invoicing.test.ts — 22 tests

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

Test NameWhat It TestsStatus
generateInvoiceNumber - generates INV-YYYY-NNN formatStandard formatImplemented
generateInvoiceNumber - increments from last numberSequential numberingImplemented
generateInvoiceNumber - pads number to 3 digitsZero-paddingImplemented
generateInvoiceNumber - handles numbers beyond 999No truncation for 1000+Implemented
generateInvoiceNumber - throws for empty prefixError: "prefix is required"Implemented
generateInvoiceNumber - throws for whitespace-only prefixWhitespace = invalidImplemented
generateInvoiceNumber - throws for negative lastNumberError: "non-negative integer"Implemented
generateInvoiceNumber - throws for non-integer lastNumberFloat rejectedImplemented
calculateInvoiceTotals - calculates line item totalquantity × unitPriceImplemented
calculateInvoiceTotals - calculates subtotal as sum of linesSum of all line totalsImplemented
calculateInvoiceTotals - calculates tax per line itemlineTotal × taxRate / 100Implemented
calculateInvoiceTotals - calculates total = subtotal + taxFinal totalImplemented
calculateInvoiceTotals - handles items without taxRateMissing tax = 0Implemented
calculateInvoiceTotals - returns zeros for empty itemsEmpty array → all zerosImplemented
calculateInvoiceTotals - handles multiple items with different ratesMixed 20%/10% taxImplemented
calculateInvoiceTotals - maintains decimal precision3 × 33.33 = 99.99Implemented
validateLineItem - returns true for valid itemHappy pathImplemented
validateLineItem - returns false for zero quantityqty=0 invalidImplemented
validateLineItem - returns false for negative quantityqty<0 invalidImplemented
validateLineItem - returns false for negative unitPriceprice<0 invalidImplemented
validateLineItem - returns false for empty descriptionDescription requiredImplemented
validateLineItem - returns false for whitespace-only descriptionWhitespace = emptyImplemented

multi-currency.test.ts — 24 tests

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

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

tax.test.ts — 23 tests

Tests VAT calculations for all supported countries and edge cases.

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

apps/api/tests/ — Mock API Tests

Integration tests for Express API endpoints. Tests use mocked Prisma clienttests): — no real database required. Setup in tests/setup.ts.

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

Provides:

  • PrismaRate clientlimit mockactually viablocks vi.mock('../src/lib/prisma')after exceeded
  • EnvironmentCount variableincrements setupcorrectly (JWTin secrets, rate limits)database
  • createTestUser()Resets after factorywindow expires

BUG-002: Validation errors generic message (3 tests):

  • Register returns details array for testvalidation user objectserrors
  • generateTestAccessToken()Details contain specific field errors
  • Multiple validation errors all included

BUG-003: Email without @ passed client-side (3 tests):

  • API rejects email without @ symbol
  • API rejects empty string as email
  • API accepts valid JWTemail forwith authenticated@
  • requests

BUG-004: Missing getDb import in auth.ts (5 tests):

  • All auth module exports are functional (signToken, verifyToken, setAuthCookie, clearAuthCookie, getCurrentUser)
  • generateTestRefreshToken()getCurrentUser returns validnull refreshwhen no token
  • Constants:All TEST_ORG_ID,exports TEST_USER_ID,are TEST_USER_EMAILfunctions

E2E Tests (Playwright)

auth.test.tests/e2e/user-flows.spec.ts -- 115 teststest groups

Landing

Page (3
  • Loads
  • onboarding to login page
    login
    Testtests):

    Name
    RouteStatus
    returns 201homepage with user,Drop organization,branding
  • Has navigation to login and tokens
  • POST
  • Navigates /auth/register
  • Implemented
    returns

    Login 400Flow for(4 duplicatetests):

    email
    POST
  • Shows /auth/register
  • Implemented
    returns 200form with tokenscorrect forfields valid
  • Shows credentials
  • POST /auth/loginImplemented
    returns 401 for invalid passwordPOST /auth/loginImplemented
    returns 401 for non-existent emailPOST /auth/loginImplemented
    returns 200error with newempty accesscredentials token(client-side) for
  • Shows valid refresh token
  • POST /auth/refreshImplemented
    returns 401 when no refresh token cookie is presentPOST /auth/refreshImplemented
    returns 204 and clears cookiePOST /auth/logoutImplemented
    returns 200error with currentwrong usercredentials when
  • Logs authenticated
  • GET /auth/meImplemented
    returns 401 when no token providedGET /auth/meImplemented
    returns 401 for invalid tokenGET /auth/meImplemented

    invoices.test.ts — 11 tests

    credentials,todashboard

    Registration

    fields, button
  • Validates
  • email format client-side flow: PIN api/rates api/rates/RSD

  • Each
  • page
    Test NameRouteStatus
    returns 200in with paginateddemo list GETredirects /invoices Implemented
    returnsFlow 401(4 withouttests):

    auth
    GET
  • Shows /invoices
  • Implemented
    returns 201form with createdrequired invoicePOSTdisabled /invoicesImplemented
    returnsclient-side 200
  • Validates withpassword fulllength invoice
  • GET
  • Full /invoices/:id
  • Implemented
    returns 404 when invoice not foundGET /invoices/:idImplemented
    returns 200 when updating draft invoicePUT /invoices/:idImplemented
    returns 400 when updating sent invoicePUT /invoices/:idImplemented
    returns 200 when sending invoice (draftform -> sent)PATCH /invoices/:id/statusImplemented
    returns 200 when marking invoice as paid (sentOTP -> paid)PATCH-> success

    Dashboard (2 tests):

    • Login redirects to dashboard with action buttons
    • Authenticated pages load after login

    API Health (4 tests):

    • GET /invoices/:id/status
    Implemented
    returns 204exchange whenrates deleting draft invoiceDELETE
  • GET /invoices/:id
  • Implemented
    returns 400specific whenrate deleting sent invoiceDELETE
  • GET /invoices/api/rates/XXX returns 404
  • POST /api/auth/register validates input
  • All Pages Load (10 tests):id

    Implemented
    (/,
    /login, /onboarding, /dashboard, /send, /scan, /history, /accounts, /profile, /cards) returns no server error

    expenses.test.tests/e2e/full-flows.spec.ts -- 98 testsjourneys

  • New
  • User -- form -> OTP -> PIN -> Moneylogin->recipient->skipped)
    TestRegistration AreaRouteStatus
    Listsuccess expenses-> dashboard (200skipped) +
  • Send auth)
  • GET-- /expenses Implemented
    Createamount expense-> confirm -> verify in history
  • QR Payment -- login -> scan -> amount -> pay -> verify in history
  • Virtual Card -- login -> cards -> order -> verify card appears
  • Bank Accounts -- login -> accounts -> verify Open Banking info, DNB account
  • Profile and Logout -- login -> profile -> verify info -> logout -> redirect
  • Full Navigation -- login -> navigate all 7 pages via direct links
  • Error Handling -- wrong credentials -> error -> correct -> success (201)
  • POST /expensesImplemented
    Get expense by ID (200 + 404)GET /expenses/:idImplemented
    Update expense (200 + 400 for non-pending)PUT /expenses/:idImplemented
    Approve expense (200 + role check)PATCH /expenses/:id/approveImplemented
    Delete expense (204 + 400 for approved)DELETE /expenses/:idImplemented

    contacts.test.tests/e2e/input-chaos.spec.ts -- 97 tests

    test groups,
    Test AreaRouteStatus
    List contacts (200 + auth)GET /contactsImplemented
    Create contact (201 + validation)POST /contactsImplemented
    Get contact (200 + 404)GET /contacts/:idImplemented
    Update contact (200)PUT /contacts/:idImplemented
    Delete contact (204)DELETE /contacts/:idImplemented

    accounts.test.ts — 4 tests

    Test AreaRouteStatus
    List chart of accounts (200)GET /accountsImplemented
    Get account by ID (200 + 404)GET /accounts/:idImplemented
    Create account (201)POST /accountsImplemented
    Delete account (204)DELETE /accounts/:idImplemented

    banking.test.ts — 10 tests

    Test AreaRouteStatus
    List bank accounts (200)GET /banking/accountsImplemented
    Create bank account (201)POST /banking/accountsImplemented
    Import bank statement (200 + validation)POST /banking/accounts/:id/importImplemented
    List bank transactions (200)GET /banking/accounts/:id/transactionsImplemented
    Reconcile transaction (200 + 400 for mismatch)POST /banking/accounts/:id/reconcileImplemented

    reports.test.ts — 9 tests

    Test AreaRouteStatus
    Profit & Loss report (200 + date range)GET /reports/profit-lossImplemented
    Balance sheet (200)GET /reports/balance-sheetImplemented
    VAT report for RS (200 + correct rates)GET /reports/vatImplemented
    Trial balance (200)GET /reports/trial-balanceImplemented
    Auth required on all report endpointsAll report routesImplemented

    transactions.test.ts — 9 tests

    Test AreaRouteStatus
    List transactions (200 + pagination)GET /transactionsImplemented
    Filter by account (200)GET /transactions?accountId=Implemented
    Get transaction by ID (200 + 404)GET /transactions/:idImplemented
    Auth requiredAll transaction routesImplemented

    country.test.ts — 2740+ tests

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

    Test AreaRouteStatus
    Serbian PDV ratesChaos (20/10/0)8 for RS orgGET /country/tax-ratesImplemented
    Bosnian PDV rate (17) for BA orgGET /country/tax-ratesImplemented
    Croatian PDV rates (25/13/5/0) for HR orgGET /country/tax-ratesImplemented
    Invoice number format per countryGET /country/invoice-formatImplemented
    Auth requiredAll country routesImplemented
    Unknown country code (400)GET /country/tax-ratesImplemented

    chatbot.test.ts — Chatbot API Tests

    Test NameRouteStatus
    returns 200 with assistant responsePOST /chatbot/messageImplemented
    returns 400 when message is emptyPOST /chatbot/messageImplemented
    returns 429 when rate limit exceededPOST /chatbot/messageImplemented
    returns 401 without authPOST /chatbot/messageImplemented
    returns 200 with conversation historyGET /chatbot/historyImplemented
    returns empty array when no history existsGET /chatbot/historyImplemented
    returns 401 without auth on historyGET /chatbot/historyImplemented
    returns 204 when history clearedDELETE /chatbot/historyImplemented
    returns 401 without auth on clear historyDELETE /chatbot/historyImplemented

    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 AreaStatus
    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 foundImplemented
    Throws 400 when invoice is already cancelledImplemented
    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 AreaRouteStatus
    Receipt not attached (404)GET /expenses/tests):id/receiptImplemented
    Receipt auth required (401)GET /expenses/:id/receiptImplemented
    VAT export PDF (200 / 404)GET /reports/vat/export/pdfImplemented
    VAT export XML (200 / 404)GET /reports/vat/export/xmlImplemented
    Dashboard metrics (200)GET /reports/dashboardImplemented
    Dashboard auth required (401)GET /reports/dashboardImplemented
    Audit log (200 + owner/admin only)GET /security/audit-logImplemented
    Audit log role check (403 for viewer)GET /security/audit-logImplemented
    Data export (200 + owner only)POST /security/data-exportImplemented
    Data export role check (403 for admin)POST /security/data-exportImplemented

    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:

    • lineTotalEmpty =fields, quantityspaces-only ×email, unitPrice
    • XSS
    • lineTaxin =email, lineTotalSQL ×injection taxRatein /email, 100
    • 10K
    • subtotalchar =email, sum(lineTotals)
    • unicode
    • taxAmountpassword, =special sum(lineTaxes)
    • characters,
    • totalNorwegian = subtotal + taxAmount
    • baseAmount = total × exchangeRatecharacters

    Registration

    Chaos (20+
  • All
  • fields empty, XSS in without @, email with spaces, password password all-numbers, SQL injection injection, 10K char name, special-chars-only, Bosnian chars, emoji,
    Testtests):

    Area
    Status
    Single-linefirstName, invoiceemail arithmeticImplemented
    Multi-line invoiceemail with mixedonly tax@, ratesImplemented
    Multi-currency7 exchangechars rate(boundary), applicationImplemented
    Zero-quantityin linelastName, itemsHTML rejectedImplemented
    NUMERIC(19,4)numbers-only precisionnames, maintainedImplemented
    spaces-only,
    password

    two-factor.test.tscomplexity, underage Two-FactorDOB, Authenticationduplicate Service

    email, far-future DOB, OTP with letters/5 digits/7+ digits, phone with letters

    TestsSend TwoFactorServiceMoney atChaos the(6 service level. Mocks: bcryptjs, speakeasy, qrcode, Prisma.tests):

  • Amount
  • 0,extremelylarge,textinnumberfield,XSSinname,1MB
    Testnegative, Name Status
    enableXSS -in search, special chars in search

    QR Payment Chaos (4 tests):

    • Amount 0, negative, very large, many decimals

    API Impossible Inputs (14 tests):

    • Empty JSON, number as email, null values, array/object as email, wrong passwordContent-Type, path throwstraversal, unauthorized
    Implemented
    enablepassword, -unicode correctemail, numbers-only name, underage DOB, duplicate email, password → returns secret + QR data URL + 10 codesImplemented
    enable - backup codes are hashed before storingImplemented
    enable - plaintext backup codes returned once onlyImplemented
    verify - valid TOTP + window=1 → activates 2FAImplemented
    verify - invalid TOTP → throws badRequestImplemented
    disable - correct password → clears secret + backup codesImplemented
    disable - wrong password → throws unauthorizedImplemented

    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 AreaStatus
    SefClient submits UBL XML to SEF sandbox URLImplemented
    SefClient uses production URL in production envImplemented
    SefClient retries on network failureImplemented
    createSefClientFromEnv() reads credentials from env varsImplemented
    generateSEFInvoiceXML() produces valid UBL 2.1 XMLImplemented
    InvoiceService.submitToSef() never re-throws errorsImplemented

    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 HTTPletters — stateless math functions.

    CountryFunctions TestedStatus
    SerbiacalculateSerbianPDV, calculateNetFromGrossPDV, qualifiesForPausalRegime, requiresVATRegistration, calculateSerbianCITImplemented
    BosniacalculateBosnianPDV, calculateNetFromGrossPDV, requiresVATRegistrationImplemented
    CroatiacalculateCroatianPDV, calculateNetFromGrossPDV, requiresVATRegistrationImplemented
    All ratesStandard, reduced, zero, super-reduced rates per countryImplemented

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

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

    RunPage with:

    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 AreaStatus
    Register new organization + owner userImplemented
    Login with correct credentialsImplemented
    Refresh access token via cookieImplemented
    Reject duplicate email registrationImplemented

    invoice.integration.test.ts — Invoice CRUD Integration

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

    Test AreaStatus
    Create invoice with line itemsImplemented
    Read invoice by IDImplemented
    Update draft invoiceImplemented
    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 AreaStatus
    Credit note creates reversing journal entriesImplemented
    Reversing entries balance (debits = credits)Implemented
    Original invoice marked as creditedImplemented

    report.integration.test.ts — Reports Integration

    Report generation against real DB with seeded transactions.

    Test AreaStatus
    P&L report returns revenue/expense dataImplemented
    VAT report returns correct tax amountsImplemented
    Trial balance returns isBalanced=trueImplemented

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

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

    Test AreaStatus
    Org A cannot list Org B's invoicesImplemented
    Org A cannot read Org B's invoice by IDImplemented
    Org A cannot update Org B's invoiceImplemented
    Org A cannot delete Org B's contactImplemented
    Cross-tenant requests return 404 (not 403 — no data leakage)Implemented

    Coverage Tracking

    ModuleCurrent StatusTarget
    @bilko/core accounting engineTests implemented (20 cases)>95%
    @bilko/core invoicingTests implemented (22 cases)>95%
    @bilko/core tax/VATTests implemented (23 cases)>95%
    @bilko/core multi-currencyTests implemented (24 cases)>90%
    @bilko/core chart of accountsTests implemented (32 cases)>90%
    Auth APITests implemented (11 cases)>85%
    Invoices APITests implemented (11 cases)>80%
    Expenses APITests implemented (9 cases)>80%
    Banking APITests implemented (10 cases)>75%
    Reports APITests implemented (9 cases)>75%
    Country/Tax-Rates APITests implemented (27 cases)>80%
    Chatbot APITests implemented (9 cases)>80%
    Security/Audit APITests 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 + SubmissionTests implemented>85%
    VAT Calculations (country packages)Tests implemented>95%
    Multi-tenant isolation (real DB)Tests implementedResilience (5 scenarios)100%
    Invoice CRUD (real DB)Tests implemented>80%
    Credit note GL (real DB)Tests implemented>90%

    Test Execution Commands

    # 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 && npx vitest run
    
    # API unit suite only
    cd apps/api && npx vitest run tests/unit/
    
    # API E2E suite only (mocked services, no DB)
    cd apps/api && 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 && npm run test:integration
    
    # Watch mode (re-run on change)
    cd packages/core && npx vitest
    cd apps/api && npx vitest
    
    # Specific file
    cd apps/api && npx vitest run tests/auth.test.ts
    cd apps/api && 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
    

    tests):


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