Testing Strategy
Lana tests domain behavior at several layers:
| Layer | Location | Purpose |
|---|---|---|
| Rust unit tests | #[cfg(test)] modules beside implementation code | Entity commands, value objects, and pure domain rules |
| Rust integration tests | Crate tests/ directories | Services, repositories, and ledger behavior against real PostgreSQL |
| BATS end-to-end tests | bats/ | Stateful API workflows against a running application |
| Cypress frontend tests | apps/admin-panel/cypress/ | Admin-panel browser workflows |
Rust Tests
Enter the development shell and start dependencies:
make nix-develop
make up-deps
Use the SQLx offline query cache for compilation:
# All tests
SQLX_OFFLINE=true cargo nextest run
# Single crate
SQLX_OFFLINE=true cargo nextest run -p core-credit
# Filter by a test-name substring
SQLX_OFFLINE=true cargo nextest run -p core-credit nullable_aware_cursor_pagination
SQLX_OFFLINE=true removes the compile-time database requirement; it does not remove the runtime PostgreSQL requirement for integration tests.
Database Isolation
lib/test-db connects to the PostgreSQL server in LANA__RUNTIME_DB__PG_CON, creates or migrates lana_test_template using lana/app/migrations/, and clones it into a fresh lana_test_run_<timestamp>_<uuid> database for each test process. Calls within one process share that scratch database; they do not write into the running application's development database.
The connection user needs permission to create databases. Test initialization garbage-collects scratch databases with no active connections once they are older than one minute. To reclaim leftovers manually, when no tests are running:
make clean-test-dbs
This force-drops lana_test_% databases, including the template; the next run recreates the template. It does not reset the development database.
For examples of the real test setup, see core/credit/tests/support/helpers.rs and the tests in core/credit/tests/. Do not connect new integration tests directly to the development database.
BATS End-to-End Tests
For the managed end-to-end suite:
make e2e
For local iteration against a running application:
make up-app
make bats BATS_ARGS=bats/customer.bats
BATS drives real API workflows and changes the running application's data. Unlike the Rust integration-test scratch databases, it is not isolated from that application's state. Use a disposable local stack when you need a clean environment; make recreate-app wipes the worktree's local state.
Frontend Tests
The Cypress stack helpers use fixed ports and a real-time clock. Stop any running worktree stack first, then enter a fixed-port shell so the test commands use the same URLs:
make down-deps
LANA_DEV_PORT_MODE=fixed make nix-develop
make start-cypress-stack
make test-cypress-in-ci
make stop-cypress-stack
The stop helper cleans local dependency state; use a disposable worktree if you need to preserve your development data. With the Cypress stack running, the package's direct commands are:
# Headless
pnpm --filter admin-panel cypress:run-headless
# Interactive
pnpm --filter admin-panel cypress:run-ui
There is no cypress:open package script. The cypress:run-ui script invokes cypress open after GraphQL code generation.
Development Data
To seed the chart and module configurations for manual development, use the supported bootstrap flow against a running app:
make up-app bootstrap
This is not a test fixture loader. Rust tests build their own fixtures in scratch databases, and BATS/Cypress set up the workflow data they need. There is no cargo run -- seed command.
CI Integration
PR checks cover Rust unit/integration tests through nextest, BATS workflows, Cypress browser tests, and code checks. Documentation changes are built separately with nix run .#check-docs.