Skip to content

Testing Quick Start for New Developers ​

Run all tests before pushing code. No exceptions.


TL;DR The Commands You Must Run Before Pushing ​

bash
# Backend (client_backend)
cd backend/client_backend
npm test        # Vitest all unit, property, and integration tests
npm run build   # TypeScript compile check

# Frontend (app)
cd ../../app
npm test        # Vitest all component, hook, and utility tests
npm run build   # TypeScript + Vite production build

Both must pass with zero failures. If any test or build fails, do not push. Fix the issue first.


What Gets Tested ​

Backend (backend/client_backend/) ​

CategoryCountWhat It Validates
Property-based tests (fast-check)27Mathematical correctness of billing, rates, cascading, service pricing
Integration tests2 suitesFull API endpoint CRUD + end-to-end billing flow
Unit tests~14 suitesControllers, middleware, utilities, services

Total runtime: ~60-90 seconds (property tests spin up in-memory MongoDB replicas).

Frontend (app/) ​

CategoryCountWhat It Validates
Property-based tests (fast-check)1 suiteClient-side floor validation (service pricing)
Hook tests3 suitesuseOnboardingState, useFormPersistence, useExportCsv
Component tests3 suitesCallFlowComponents, PresetSelector, OnCallConnectedPanel
Page tests2 suitesAgentEditorPage (enhance), AddCreditsPage

Total runtime: ~5-10 seconds (uses happy-dom, no real browser).


Before You Commit Full Checklist ​

bash
# Step 1: Backend tests
cd backend/client_backend
npm test

# Step 2: Backend TypeScript compilation
npm run build

# Step 3: Frontend tests
cd ../../app
npm test

# Step 4: Frontend build (catches TypeScript + import errors)
npm run build

Quick one-liner (Windows CMD): ​

cmd
cd /d E:\Oktivo\Oktivo\oktivo_voice\backend\client_backend & npm test & npm run build & cd /d E:\Oktivo\Oktivo\oktivo_voice\app & npm test & npm run build

If any step fails, stop and fix before pushing.


Test File Locations ​

backend/client_backend/src/
├── __tests__/                              ← Main test directory (property + integration)
│   ├── billing-split-correctness.test.ts
│   ├── cumulative-profit-tracking.test.ts
│   ├── end-to-end-billing-flow.integration.test.ts
│   ├── global-cascade-isolation.test.ts
│   ├── orgConfigReplica-api.integration.test.ts
│   ├── orgConfigReplica-effective-superadmin-rate.test.ts
│   ├── orgConfigReplica-schema-constraint.test.ts
│   ├── rate-snapshot-effective-superadmin-rate.test.ts
│   ├── rate-snapshot-immutability.test.ts
│   ├── superadmin-rate-update-persistence.test.ts
│   ├── transaction-metadata-completeness.test.ts
│   ├── service-pricing-data-model.test.ts          ← NEW: Properties 6, 8
│   ├── service-pricing-floor-constraint.test.ts    ← NEW: Property 1
│   ├── service-pricing-cascade-floor.test.ts       ← NEW: Property 3
│   ├── service-pricing-visibility-cascade.test.ts  ← NEW: Property 4
│   ├── service-pricing-visibility-filtering.test.ts← NEW: Property 5
│   ├── service-pricing-org-boundary.test.ts        ← NEW: Property 7
│   ├── rate-resolution-hierarchy.test.ts           ← NEW: Property 2
│   ├── invisible-preset-rate-resolution.test.ts    ← NEW: Property 9
│   ├── (+ bugfix-related tests)
│   └── ...
├── controllers/__tests__/                  ← Controller tests
│   ├── servicePricing.controller.test.ts   ← NEW: 20 unit tests for CRUD + validation
│   └── ...
├── middleware/__tests__/                   ← Middleware tests
├── utils/__tests__/                        ← Utility tests
├── services/*.test.ts                      ← Colocated service tests
└── tests/                                  ← EXCLUDED (legacy manual/E2E see TESTING-GUIDE.md)

Vitest config (vitest.config.ts):

  • Includes: src/**/*.test.ts
  • Excludes: src/tests/** (legacy scripts that need a running server)
  • Timeout: 60 seconds per test

Understanding the Property-Based Tests (Credit System + Service Pricing) ​

These tests use fast-check to generate random inputs and verify mathematical invariants hold for ALL possible values, not just handpicked examples.

Credit System Properties ​

Property #FileWhat It Proves
1services/orgConfigReplica.service.rateResolution.test.tsRate resolution picks the correct rate based on overrides
2__tests__/superadmin-rate-update-persistence.test.tsConfig updates persist correctly with version increment
3__tests__/orgConfigReplica-schema-constraint.test.tsReplica schema only contains expected fields
4__tests__/global-cascade-isolation.test.tsFloor enforcement + per-org isolation during cascade
8__tests__/billing-split-correctness.test.tscustomerCharge = ceil(units * org_rate), orgCharge = ceil(units * superadmin_rate)
9__tests__/rate-snapshot-immutability.test.tsMid-call rate changes don't affect billing
11__tests__/transaction-metadata-completeness.test.tsAll required metadata fields present in transactions
12__tests__/cumulative-profit-tracking.test.tstotalProfitRetained = Σ(customerCharge - orgCharge)
13__tests__/orgConfigReplica-effective-superadmin-rate.test.tsEffective rate = per-org when set, else global
14services/orgConfigReplica.service.superadminOrgRatePersistence.test.tsSet/read round-trip for per-org rates
17__tests__/rate-snapshot-effective-superadmin-rate.test.tsSnapshot captures correct source (per_org vs global)

Service Pricing Properties ​

Property #FileWhat It Proves
SP-1__tests__/service-pricing-floor-constraint.test.tsUpsert succeeds ⟺ customer_rate >= org_rate
SP-2__tests__/rate-resolution-hierarchy.test.tsResolved rate = customer_override → org_override → default
SP-3__tests__/service-pricing-cascade-floor.test.tsAfter cascade, ALL customer rates >= new org_rate
SP-4__tests__/service-pricing-visibility-cascade.test.tsDisabled preset → zero overrides remain
SP-5__tests__/service-pricing-visibility-filtering.test.tsOnly visible presets returned; invisible presets reject upserts
SP-6__tests__/service-pricing-data-model.test.tsRepeated upserts → exactly one document (idempotent)
SP-7__tests__/service-pricing-org-boundary.test.tsCross-org operations → 403 Forbidden
SP-8__tests__/service-pricing-data-model.test.tsSchema rejects customer_rate <= 0
SP-9__tests__/invisible-preset-rate-resolution.test.tsInvisible presets never resolve to customer_override
SP-10app/pages/admin/__tests__/ServicePricingPage.floorValidation.property.test.tsClient-side: submit disabled ⟺ input < org_rate

Each test runs 30-100 random iterations. If any single iteration fails, fast-check reports the minimal counterexample.


If a Test Fails ​

  1. Read the error message Vitest shows exactly which assertion failed and which file/line.
  2. For property tests fast-check shows the "counterexample" (the random input that broke the invariant). This is your debugging starting point.
  3. For integration tests check if your code change affected an API response shape or database schema.
  4. Common causes:
    • Changed a field name in a model without updating tests
    • Modified a service method signature
    • Broke rate validation logic (org_rate < superadmin_rate)
    • Changed transaction metadata structure

Adding New Tests ​

Follow existing patterns:

typescript
// Property test template (fast-check)
import { describe, it, expect } from "vitest";
import fc from "fast-check";

describe("Property N: My Property", () => {
  it("property: description of invariant", async () => {
    await fc.assert(
      fc.asyncProperty(myGenerator, async (input) => {
        // Arrange + Act
        const result = await myService.doThing(input);
        // Assert the invariant
        expect(result).toBe(expectedValue);
      }),
      { numRuns: 50 }
    );
  });
});
typescript
// Integration test template (supertest)
import request from "supertest";
import express from "express";

describe("My API endpoint", () => {
  it("should return 200 with correct data", async () => {
    const res = await request(app).get("/api/my-endpoint");
    expect(res.status).toBe(200);
    expect(res.body.success).toBe(true);
  });
});

Last updated: