GeoLibre Testing Strategy and Coverage Floors in CI: A Complete Guide
GeoLibre enforces minimum test coverage thresholds ("floors") through a layered CI gate that runs unit tests, integration tests, and end-to-end tests across TypeScript, Python, and Rust components, failing builds that drop below 78% frontend or 55% backend coverage.
The opengeos/GeoLibre repository uses a multi-language quality gate to maintain code reliability across its entire stack. Understanding how coverage floors work in CI helps contributors meet merge requirements and prevents test health from regressing over time.
The Layered Test Architecture
GeoLibre splits testing across four distinct layers, each with dedicated npm scripts defined in package.json. This separation allows focused feedback during development while the full gate runs in CI.
Frontend Unit Tests
The fastest feedback loop covers TypeScript source files with Node's built-in test runner:
# Quick unit tests only
npm run test:frontend
# With coverage enforcement (78% lines, 78% branches, 63% functions)
npm run test:frontend:coverage
Tests live in tests/*.test.ts and execute without build steps, keeping the loop tight for TDD workflows.
Worker Tests
The Cloudflare viewer worker (workers/viewer) has its own validation:
npm run test:worker
This command type-checks the worker code and runs its unit tests, isolating edge-runtime logic from browser assumptions.
Backend Python Tests
The FastAPI sidecar (backend/geolibre_server) uses pytest with coverage reporting:
# Run Python tests
npm run test:backend
# With 55% coverage floor enforced
npm run test:backend:coverage
The backend coverage floor is defined via pytest-cov with --cov-fail-under=55 as specified in CLAUDE.md.
End-to-End Smoke Tests
Playwright validates the built application:
npm run test:e2e
These tests in e2e/ require a production build and exercise full user flows, catching integration issues unit tests miss.
Rust Validation
The Tauri desktop shell undergoes static analysis:
npm run check:rust
This runs cargo check without full compilation, flagging type errors in the native layer.
How Coverage Floors Work in CI
The .github/workflows/ci.yml workflow implements a ratchet mechanism that prevents coverage backsliding. When a PR triggers CI, the Run CI gate step executes npm run ci after dependency installation, as shown in lines 20-22 of the workflow file.
Numeric Thresholds
| Component | Line Coverage | Branch Coverage | Function Coverage |
|---|---|---|---|
| Frontend | 78% | 78% | 63% |
| Backend | 55% overall | — | — |
These floors are intentionally set below current actual coverage, creating headroom for refactoring while blocking genuine regressions. When the test suite consistently exceeds a floor by a comfortable margin, maintainers raise the threshold in a future commit to lock in the gain.
The Hidden Module Effect
Coverage calculation in GeoLibre only includes actually imported files. Modules without any test imports simply do not appear in reports—they are not scored as 0%. As noted in CLAUDE.md (lines 43-45), this design incentivizes developers to add tests for new modules, since untested code becomes invisible to metrics rather than dragging averages down.
Running the Full Quality Gate Locally
Contributors can replicate CI behavior before pushing:
# Executes: build → lint → test → coverage → rust
npm run ci
The script runs all layers in dependency order, failing fast on any violation. For faster iteration during focused changes, individual layer commands (shown above) provide targeted feedback.
Key Implementation Files
.github/workflows/ci.yml— Defines the automated gate, dependency installation, andnpm run ciinvocationCLAUDE.md— Documents exact coverage thresholds and the ratchet policy philosophydocs/contributing.md— Explains local testing commands for new contributorspackage.json— Ships all test scripts as npm run targetsbackend/geolibre_server/pyproject.toml— Configures the Python package under coverage measurement
Summary
- GeoLibre uses a four-layer test strategy: frontend units, worker checks, backend pytest, and Playwright E2E
- Coverage floors enforce 78% frontend and 55% backend minimums, failing CI below threshold
- The ratchet mechanism lets floors rise over time as coverage improves, preventing backsliding
- Untested modules do not count against coverage, encouraging test creation for new code
- Run
npm run cilocally to verify changes match CI requirements before submitting PRs
Frequently Asked Questions
What happens if my PR drops coverage below the floor?
The CI job fails and blocks merging. You must add tests for your new code or modify existing tests to maintain the 78% frontend / 55% backend thresholds. The failure appears in the GitHub Actions log with the specific shortfall.
Why are backend coverage floors lower than frontend?
The Python FastAPI sidecar is younger and has less test infrastructure than the TypeScript frontend. The 55% floor reflects pragmatic current state while still preventing regression. Community contributions that raise backend coverage can trigger a floor increase via CLAUDE.md and workflow updates.
Can I skip the full CI gate for documentation-only changes?
The workflow in .github/workflows/ci.yml runs unconditionally on PRs. While path-based skipping is technically possible, the maintainers currently enforce the full gate to guarantee coverage floors are respected regardless of which files appear changed.
How do I see my coverage report locally?
Run npm run test:frontend:coverage or npm run test:backend:coverage depending on which component you modified. The frontend outputs per-file summaries to stdout; the backend generates detailed HTML reports via pytest-cov that you can open in a browser.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →