Skip to content

Testing and CI

aaalllexxx edited this page Jun 29, 2026 · 2 revisions

Testing & CI

ENPAF has a pytest suite for the framework and GitHub Actions for continuous integration and releases.

Running the tests

pip install -e ".[test]"   # installs the package + pytest + pytest-cov
pytest                      # runs the whole suite
pytest -q                   # quiet
pytest tests/test_storage.py -k collection   # a subset
pytest --cov=enpaf --cov-report=term-missing # with coverage

Tests are also shipped in the sdist, so you can run them from an unpacked release (pip install enpaf-<ver>.tar.gz extracts tests/).

Linting

The code is linted with ruff (pyflakes ruleset):

pip install -e ".[dev]"
ruff check .

Configuration lives in pyproject.toml:

[tool.pytest.ini_options]
minversion = "7.0"
testpaths = ["tests"]
addopts = "-ra"

What's covered

The suite focuses on the desktop/dev-mode behavior — everything that runs without Android/Chaquopy. On-device-only code (real sensors, Java callbacks) is covered at the dispatch/validation level.

File Covers
tests/test_storage.py Key/value store + collections (CRUD, types, isolation).
tests/test_events.py EventEmitter: on/once/off, error isolation, no-recurse.
tests/test_bridge.py Bridge register/handle_call envelopes, SocketIO emit, JS events.
tests/test_router.py Routing, Jinja2 render, bridge-script injection, autoescape.
tests/test_api.py DeviceAPI dev stubs, allow-listed invoke, resolve_permission, URI normalize.
tests/test_app.py EnpafApp wiring, built-in handlers, module attachment, data dir.
tests/test_modules.py Capability-module dispatch + allow-list enforcement.
tests/test_build.py OneDrive detection, build-dir relocation, Java version parsing, file-safety helpers.
tests/test_cli.py paf create scaffolding + argument parsing/dispatch.
tests/test_packaging.py Version consistency, public exports, entry point.

Shared fixtures (tests/conftest.py) build an isolated project in a temp dir, set ENPAF_DATA_DIR, force dev mode, and provide ready-made app, storage, and device_api objects.

Continuous integration

.github/workflows/ci.yml

Runs on every push to main, every pull request, and manual dispatch:

  • lintruff check . (pyflakes ruleset).
  • test — matrix of Python 3.9–3.13 × Ubuntu + Windows; installs ".[test]" and runs pytest with coverage (--cov=enpaf, fails under 30%).
  • build — builds the wheel + sdist with python -m build, validates with twine check, and uploads them as an artifact.
strategy:
  matrix:
    os: [ubuntu-latest, windows-latest]
    python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]

.github/workflows/release.yml

Runs when a version tag (v*) is pushed:

  • Builds the wheel + sdist, runs twine check.
  • Attaches them to the GitHub Release and generates release notes.
git tag v1.2.0
git push origin v1.2.0   # -> builds + publishes the distribution

Why CI doesn't build APKs

Building an APK requires the Android SDK, a pinned JDK, and Chaquopy assembling the Python runtime — heavy and slow for hosted runners. CI therefore validates the framework (tests + distribution). Build app APKs locally (or on a dedicated runner) and attach them to releases — see Release & Signing.

Adding tests

  • Put new tests in tests/ as test_*.py.
  • Reuse the app / storage / device_api fixtures.
  • Keep tests dev-mode-only (no Chaquopy). For device features, assert the dispatch contract (allow-list + invoke) rather than real hardware behavior.

Clone this wiki locally