Skip to content

Testing

How the project's test suite runs — commands and numbers below were executed in this environment (see the validation report at the wiki repo root for the run log).

Backend (pytest)

  • Framework: pytest + FastAPI TestClient; SQLite in-memory with JSONB/ network-type compilation shims (tests/conftest.py) — no external services needed
  • Location: backend/tests/ (~290 files); EE-only areas are marked ee and skip automatically in a Core build
  • Docker-based run (same image CI uses):
docker build -q -f backend/Dockerfile.test -t umbryx-test .
docker run --rm -e APP_ENV=test umbryx-test \
  sh -c "cd /app && python -m pytest -q --no-cov"

Observed full-suite results (2026-10-30): EE 7474 passed / 2 skipped; Core 7215 passed / 169 skipped (7476 vs 7384 collected: EE ships extra test files for EE-only areas). Of Core's 169 skips, 167 are edition markers that do run in an EE build; the 2 skips present in both builds are one SSO entitlement gate (the test fixture runs unlicensed) and one PostgreSQL-only JSONB filter (the suite runs on SQLite).

Targeted run:

... python -m pytest tests/test_auth.py tests/test_sync_api.py -q --no-cov

Coverage is wired via --cov=app (pytest.ini addopts).

Frontend (Vitest)

cd frontend && npm ci && npm run test        # vitest suite
npm run lint && npm run build                # eslint + production build

Lint / formatting

  • Backend: ruff + black, line length 100 (backend/pyproject.toml)
  • Frontend: ESLint flat config
  • Pre-commit hooks configured (.pre-commit-config.yaml)

Demo stand (functional/manual)

scripts/demo-stand.sh up|seed|down raises an isolated throwaway instance with synthetic data on port 8899 — the sanctioned way to reproduce screenshots and smoke-test workflows without touching a live instance.

Known limitations

  • Tests run against SQLite, not PostgreSQL — dialect-specific behavior (upserts, JSONB indexing) is covered by the code's dialect guards rather than the suite
  • Frontend tests cover store/logic components; view-level E2E is not automated