Testing¶
Run everything with task test and task lint.
Both are run by the same commands on a developer machine and in CI.
Backend¶
The backend uses pytest with pytest-asyncio (auto mode) and
Hypothesis.
Tests live in backend/tests and mirror the layers of the
application:
tests/domainPure unit tests of parsing, hashing, validation and approval rules. No database, no I/O.
tests/sourcesThe filesystem and GitLab source adapters.
tests/servicesPolling, ingest, search and the other service-layer behaviour.
tests/storageIntegration tests of the PostgreSQL store.
tests/routersHTTP tests through FastAPI’s
TestClient, including permissions and the approval workflow.tests/authToken claims and the command line.
Test doubles¶
Nothing in the suite talks to the network or to a real provider.
tests/fakes.pyFakeSource, an in-memory implementation of the source port. It records every call and scripts failures and incomplete listings.tests/gitlab_fake.pyFakeGitLab, a GitLab REST API v4 served throughhttpx.MockTransportwith realistic pagination and scripted failures.tests/auth_helpers.pyA throwaway dev secret and helpers to mint tokens.
Test database¶
Storage, service and router tests use a real PostgreSQL database. Start it with:
task db:up
The container listens on host port 55432 and contains two databases:
adriano for development and adriano_test for the tests.
The tests read ADRIANO_TEST_DATABASE_URL and never touch the
development database.
The storage fixtures build the schema once per session by running
the real Alembic migrations (including downgrade base) and
truncate all tables before each test.
Running tests¶
cd backend
uv run pytest # everything
uv run pytest tests/domain # one directory
uv run pytest tests/domain/test_hashing.py::test_name
uv run pytest -k "approval and not parity"
Test docstrings begin with “Ensure …” and state the behaviour under test.
Frontend¶
The frontend uses Vitest with jsdom and Vue Test Utils.
Tests live in frontend/tests and mirror src/: api,
auth, components, composables, plugins, utils and
views.
tests/setup.ts supplies the browser APIs Vuetify needs and jsdom
lacks.
cd frontend
npm ci
npm run test # whole suite, once
npx vitest run tests/utils/diff.test.ts
npx vitest run -t "pattern" # by test name
task test unsets VITE_DEV_AUTH so that a developer’s .env
cannot change the outcome.
Some tests guard conventions rather than behaviour:
style-blocks.test.tsfails when a<style>block contains a hard-coded colour or a rule without a justification comment (see Vuetify first).plugins/vuetify.test.tschecks that every theme text and background pair reaches a contrast ratio of at least 4.5:1.typography-scale.test.tsprotects the type scale.
Lint and type checks¶
task lint runs, in this order:
ruff checkRule sets E, F, I, D (pydocstyle,
pep257convention), C90 (complexity at most 10), B and UP, configured inbackend/pyproject.toml.ruff format --checkThe formatter, with a line length of 80.
npm run lintESLint with the Vue and TypeScript presets and no warnings allowed.
npm run typecheckvue-tsc --build.
Python type checking is configured for Pyright in
pyrightconfig.json at the repository root (it uses
backend/.venv) but is not part of task lint.
Editors that use Pylance pick it up automatically.