Testing¶
FARA uses five distinct levels of testing, each responsible for a different aspect of quality. This separation isn't accidental — each level solves a problem that others can't solve well or at all.
Five types of tests¶
-
Unit tests (Python)
Isolated checks of individual functions and classes — no DB, no network. The fastest. Runs in seconds.
-
Integration tests (Python)
Verify how modules interact with real PostgreSQL and FastAPI TestClient. Cover CRUD, permissions, business logic.
-
E2E (Playwright)
Browser tests of the UI: Chromium runs real user scenarios — login, lead creation, sending a message.
-
Performance
Measure ORM, API, search, serialization speed under load. Benchmarks and load testing.
-
Security
Verify ACL, Rules, permission bypass, injections, authentication. That one user can't see another's data.
Why the separation¶
This isn't just different folders and tools — each level has its own goal and trade-offs.
Test pyramid¶
graph TB
E2E[E2E — Playwright<br/>~5% of tests, slowest]
PERF[Performance<br/>~5%, separate category]
SEC[Security<br/>~5%, separate category]
INT[Integration — pytest + httpx<br/>~30% of tests, medium]
UNIT[Unit — pytest<br/>~55% of tests, fastest]
E2E --> INT
INT --> UNIT
style UNIT fill:#d1f7c4,stroke:#2c6c1c
style INT fill:#fde6c4,stroke:#8b4f1c
style E2E fill:#f8d3d3,stroke:#8b1c1c
style PERF fill:#dde7ff,stroke:#5170c4
style SEC fill:#e0d4ff,stroke:#5b1c8b
The higher the level — the more expensive tests are to maintain and the slower they run. So the majority should be unit tests, the minority — e2e. Not the other way around.
What each type catches¶
| Type | Catches | Doesn't catch |
|---|---|---|
| Unit | Logic inside a function — math, validation, parsing, edge cases | Whether modules actually work together |
| Integration | DB correctness, JSON serialization, ORM-level ACL, call chains | UI regressions, autoplay-policy, real clicks |
| E2E | That a user can actually do a task: login → create lead → assign manager | Performance leaks, race conditions in code |
| Performance | Speed regressions — was 50ms, now 300ms, search 5x slower | Data correctness |
| Security | Whether user A can read user B's data, rate-limit bypass, input validation | Business bugs |
When to write each¶
- Changed a parser/formatter/mapper → unit test for new cases.
- Added a new endpoint → integration test for CRUD + ACL.
- New UI page → e2e for the key user path.
- Rewrote a hot method (search, render, etc.) → performance test with measurement.
- Added a role / new permission → security test for role isolation.
You don't need to cover each change with all five levels. Each changed piece of code requires at least one level — the one where it would regress.
Running all tests¶
# Python unit + integration
pytest tests/unit tests/integration -v
# Performance — separate command, slow
pytest tests/performance -v -m performance
# Security
pytest tests/security -v -m security
# E2E — separate process
cd e2e && npx playwright test
Folder structure¶
tests/
├── conftest.py ← shared fixtures (db_pool, env, client)
├── unit/ ← fast, isolated tests
├── integration/ ← with real DB
├── performance/
└── security/
e2e/ ← Playwright (separate project)
├── playwright.config.ts
├── tests/
└── package.json