Skip to content

Running the tests

uv run pytest

That is the whole suite. What CI runs is a set of nox sessions, each in its own environment, and any of them can be reproduced:

uv run nox -s tests        # the suite, on a clean install
uv run nox -s typeguard    # the suite with runtime type checking
uv run nox -s xdoctest     # the examples in docstrings
uv run nox -s models-check  # the generated config models are current
uv run nox -s docs-build   # the site, in strict mode

The frontend

The editor's page and the scripts of the HTML pages share a suite, and it runs in CI as the page job:

cd frontend
npm test          # vitest
npm run typecheck
npm run format:check
npm run build

It is not optional dressing. The bridge between the form and the YAML document is where a bug would be silent — a save that quietly drops what the schema does not describe — so those tests are the ones holding the design up.

The translations of the pages

The Italian catalog of the HTML pages, packages/fastgeoapi-html/fastgeoapi_html/locale/it/LC_MESSAGES/messages.po, is edited by hand, and tests/test_html_catalogs.py keeps it complete: it extracts every string from the templates and from app/html, and fails on each one the catalog does not translate. A string you add to a page therefore needs its msgid and msgstr in the catalog in the same change. The pages read the .po file as it is, so there is no .mo to compile.

Before you push

uv run pre-commit run --all-files

It does not see untracked files

--all-files means every file git knows about. A file you have just created is not one of them, so the hooks skip it and CI is the first thing to complain. git add -N the new files first — this has cost red builds here more than once.

Two traps this suite has sprung repeatedly

Purged modules. Some tests clear sys.modules. After that, a module imported at the top of a test file and the same module imported inside a test are two different objects — so a monkeypatch lands on the one nobody calls, and the test passes alone while failing in the suite. Take the module and the thing you are patching together, inside the test.

Tests that never failed. A green test proves nothing until you have seen it red for the right reason. Where that is impossible — coverage added to code that already works — break the code deliberately and check that the test notices.

The loop must not block

A provider that declares itself natively asynchronous makes a claim the suite can check. blockbuster is in the dev group: inside blockbuster_ctx() any blocking call made on the event loop — a socket, a file, time.sleep — raises BlockingError, while the same call made in a worker thread is allowed, because that is where it belongs.

from blockbuster import blockbuster_ctx

with blockbuster_ctx():
    tile = await async_view(provider).get_tiles(...)

See Writing an async provider for the red-first version of that test.