# GeoLibre Testing Strategy and Coverage Floors in CI: A Complete Guide

> Explore the GeoLibre testing strategy and coverage floors in CI. Learn how layered gates ensure high quality across TypeScript, Python, and Rust components.

- Repository: [Open Geospatial Solutions/GeoLibre](https://github.com/opengeos/GeoLibre)
- Tags: best-practices
- Published: 2026-08-05

---

**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`](https://github.com/opengeos/GeoLibre/blob/main/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:

```bash

# 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:

```bash
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:

```bash

# 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`](https://github.com/opengeos/GeoLibre/blob/main/CLAUDE.md).

### End-to-End Smoke Tests

Playwright validates the built application:

```bash
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:

```bash
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`](https://github.com/opengeos/GeoLibre/blob/main/.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`](https://github.com/opengeos/GeoLibre/blob/main/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:

```bash

# 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`](https://github.com/opengeos/GeoLibre/blob/main/.github/workflows/ci.yml)** — Defines the automated gate, dependency installation, and `npm run ci` invocation
- **[`CLAUDE.md`](https://github.com/opengeos/GeoLibre/blob/main/CLAUDE.md)** — Documents exact coverage thresholds and the ratchet policy philosophy
- **[`docs/contributing.md`](https://github.com/opengeos/GeoLibre/blob/main/docs/contributing.md)** — Explains local testing commands for new contributors
- **[`package.json`](https://github.com/opengeos/GeoLibre/blob/main/package.json)** — Ships all test scripts as npm run targets
- **[`backend/geolibre_server/pyproject.toml`](https://github.com/opengeos/GeoLibre/blob/main/backend/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 ci` locally 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`](https://github.com/opengeos/GeoLibre/blob/main/CLAUDE.md) and workflow updates.

### Can I skip the full CI gate for documentation-only changes?

The workflow in [`.github/workflows/ci.yml`](https://github.com/opengeos/GeoLibre/blob/main/.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.