Skip to content

Testing

How to run Jenny’s test suite, lint, and type checks locally, and what CI enforces on every pull request.

Terminal window
pytest -q

The suite uses pytest-asyncio in auto mode (asyncio_mode = "auto" in pyproject.toml’s [tool.pytest.ini_options]) — async test functions run without needing an explicit @pytest.mark.asyncio decorator on each one. testpaths is set to tests/, so a bare pytest from the repo root already scopes correctly.

Tests mirror the jenny/ package structure directory-for-directory: tests/agent/ covers jenny/agent/, tests/webui/ covers jenny/webui/, tests/config/ covers jenny/config/, and so on. When you add a module under jenny/, its tests belong in the matching relative path under tests/, not wherever is convenient.

Scoping to one directory is the fast inner loop while working on a single subsystem, for example:

Terminal window
pytest tests/config/ -v

CI additionally runs with pytest-cov (--cov=jenny --cov-report=term-missing:skip-covered). Coverage is informational only — there is no blocking threshold; it exists to make undercovered modules visible, not to fail a build over a percentage.

Terminal window
ruff check jenny/ tests/

Configured in pyproject.toml’s [tool.ruff] / [tool.ruff.lint]: line length 100, target py311, rule set E, F, I, N, W selected, with E501 (line-too-long) explicitly ignored — line length is a soft target, not an enforced one.

Jenny uses pyright in basic mode (config in pyrightconfig.json, include: ["jenny"], excluding jenny/templates and jenny/skills). It’s a static check only — zero runtime impact — but it runs in two tiers with different consequences:

Terminal window
# BLOCKING subset — must stay green, this is what CI fails the build on:
npx pyright jenny/bus jenny/command jenny/runtime jenny/session
# Full-perimeter visibility — informational, does not fail the build:
npx pyright || true

The blocking subset (jenny/bus, jenny/command, jenny/runtime, jenny/session) is already error-clean today and is expected to stay that way — a PR that reintroduces a type error in one of those four packages fails CI. Running pyright against the whole jenny/ perimeter (the second command) surfaces residual errors elsewhere in the codebase without blocking anything; that’s the honest state of a codebase being tightened incrementally rather than one pretending to be fully typed already. reportMissingImports is disabled project-wide since Android/Chaquopy-only dependencies aren’t installed in a plain CI environment, and jenny/pydantic_compat (the homemade, stdlib-only BaseModel reimplementation — see FORK_BOUNDARY.md) gets relaxed reportGeneralTypeIssues/reportAttributeAccessIssue settings since it leans on dynamic metaprogramming that pyright can’t fully follow.

One command, straight from AGENTS.md, runs everything CI runs before a PR is considered:

Terminal window
ruff check jenny/ tests/ && npx pyright jenny/bus jenny/command jenny/runtime jenny/session && pytest -q

Run this before committing or opening a PR. It’s exactly the lint + blocking-type-check + test sequence, without the coverage report or the non-blocking full-perimeter pyright pass (those two are visibility-only in CI, not gates).

.github/workflows/ci.yml defines three jobs on every push/PR to main:

Job What it does
dco Verifies every commit in the PR carries a matching Signed-off-by: line (scripts/check_dco.sh). See CONTRIBUTING.md for the sign-off requirement — a PR with unsigned commits cannot merge.
lint ruff check jenny/ tests/, then the blocking pyright subset, then the non-blocking full-perimeter pyright pass (|| true).
test pytest -q --cov=jenny --cov-report=term-missing:skip-covered, run twice as a matrix across Python 3.11 and 3.12.

CI validates the Android code path on a plain host runner (installing jenny with pip install -e .) rather than inside an actual Android build — Android is the only supported runtime target for the shipped app, but the Python side of the codebase is what CI exercises directly.

Language and style conventions that tests should also follow

Section titled “Language and style conventions that tests should also follow”
  • Docstrings and comments in Italian for new code; code inherited from upstream keeps its existing English — don’t translate text that’s already there.
  • Identifiers, log messages, and commit-facing strings (commit messages, PR descriptions) stay in English regardless of the above.
  • User-facing WebUI strings are localized via the i18n JSON files (jenny/templates/ui/assets/i18n/{it,en}.json) — never hardcode UI copy directly in JS/HTML.

See Code style for the complete set of conventions beyond testing.

Jenny · code underAGPL-3.0 · name and mascot undertrademark

No cookies, no trackers, no analytics. This page loads nothing from a third party.