Contributing¶
This page covers how to set up a development environment, run tests, and generate coverage reports.
Prerequisites¶
- Rust (nightly toolchain)
- Node.js 20+
- Docker and Docker Compose
- uv (Python package manager, for pre-commit)
Getting started¶
# Clone the repo
git clone https://github.com/alexmohr/assimilate
cd assimilate
# Install Rust nightly with required components
rustup toolchain install nightly
rustup component add rustfmt clippy --toolchain nightly
# Install frontend dependencies
npm ci --prefix frontend
# Install pre-commit hooks
uv run pre-commit install
Running the demo environment¶
The demo environment provides a fully seeded server for manual testing and documentation screenshots.
.devcontainer/start.sh --demo
Or directly with Docker Compose:
docker compose -f .devcontainer/demo/docker-compose.demo.yml up --build
Open http://localhost:8080 — login: admin / admin.
Build and lint¶
Rust¶
# Format
cargo +nightly fmt -- \
--config error_on_unformatted=true,error_on_line_overflow=true,\
format_strings=true,group_imports=StdExternalCrate,imports_granularity=Crate
# Lint
cargo +nightly clippy --workspace -- -D warnings
# Unit and integration tests (requires PostgreSQL — see below)
cargo test --workspace
Frontend¶
cd frontend
npm run format:check # Prettier formatting
npm run lint # ESLint
npm run test # Vitest unit tests
npm run build # Production build (must succeed before committing)
Database integration tests¶
Tests in crates/server/tests/db_queries.rs require a live PostgreSQL instance.
Start one with Docker:
docker run -d --name borg-postgres \
-e POSTGRES_USER=borg \
-e POSTGRES_PASSWORD=borg_dev \
-e POSTGRES_DB=borg \
-p 5432:5432 \
postgres:latest
Then run the tests:
DATABASE_URL=postgres://borg:borg_dev@localhost:5432/borg \
cargo +nightly test -p server --test db_queries
E2E tests¶
Playwright tests live in frontend/e2e/ and run against the demo environment.
Run¶
Start the demo environment first, then:
cd frontend
npm run e2e
Run with coverage¶
Istanbul instrumentation is activated by setting VITE_COVERAGE=true at build time. The instrumented bundle writes window.__coverage__ in the browser; the Playwright fixture captures it after each test and saves JSON files to frontend/.nyc_output/.
# 1. Build with Istanbul instrumentation
cd frontend
VITE_COVERAGE=true npm run build
# 2. Start the demo, mounting the instrumented build over the container's static files
cd ..
docker compose \
-f .devcontainer/demo/docker-compose.demo.yml \
-f .devcontainer/demo/docker-compose.coverage-override.yml \
up -d
# 3. Run tests — coverage JSON files accumulate in frontend/.nyc_output/
cd frontend
VITE_COVERAGE=true npm run e2e
# 4. Generate LCOV report
npm run e2e:coverage # writes frontend/coverage-e2e/lcov.info
Note
The instrumented build is significantly larger than the production build (Istanbul adds counter code to every statement). Use only for coverage measurement, not deployment.
Code coverage¶
Unit coverage (Rust + Vitest)¶
Rust coverage uses cargo-llvm-cov:
# Install once
cargo install cargo-llvm-cov
DATABASE_URL=postgres://borg:borg_dev@localhost:5432/borg \
cargo +nightly llvm-cov --workspace --lcov --output-path lcov.info \
-- --include-ignored --test-threads=1
Frontend Vitest coverage:
cd frontend
npm run test:coverage # writes frontend/coverage/lcov.info
Merging all coverage¶
To produce a single merged LCOV file (the same way CI does):
# Rust + Vitest + e2e
sed 's|^SF:|SF:frontend/|' frontend/coverage/lcov.info > frontend-lcov-fixed.info
cat lcov.info frontend-lcov-fixed.info frontend/coverage-e2e/lcov.info > merged.info
CI coverage¶
In CI, coverage is collected by three jobs and reported to Coveralls:
| Source | Tool | Coveralls flag |
|---|---|---|
| Rust unit + integration tests | cargo-llvm-cov |
unit |
| Frontend Vitest unit tests | vitest --coverage |
unit |
| Playwright e2e tests | vite-plugin-istanbul + nyc |
e2e |
The coveralls-finish job finalises the report after both jobs complete.
Pre-commit hooks¶
uv run pre-commit run --all-files --show-diff-on-failure
All hooks must pass before committing. If a hook modifies files (trailing whitespace, formatting), stage the changes and re-run.