Integration Guides
- Python - Track coverage with
requests,httpx, Django, Flask, or Schemathesis - pytest Plugin - Zero-boilerplate coverage reports in your pytest runs
- CLI - Reports from traffic files or live proxy capture
- JavaScript - Track coverage with Playwright, Vitest, or any HTTP client
AI-assisted setup
Don't want to wire it up by hand? Copy the prompt below and paste it into Claude Code (or any capable coding agent). It detects your stack, picks the right integration, wires TraceCov in, and generates a first coverage report.
Copy the integration prompt
# Integrate TraceCov into this project
You are integrating **TraceCov** — an API specification coverage tool — into the current Python project, end to end, and proving it works. TraceCov measures how thoroughly a test suite exercises an OpenAPI/Swagger spec: operations, parameters, JSON Schema keywords, and responses.
Work through the five phases below in order. Obey these rules throughout:
- **One path only.** Choose exactly one integration path in Phase 2. Never partially wire multiple paths.
- **Idempotent.** On a re-run, do not duplicate hook files, fixtures, env exports, or dependency entries. Check whether each edit already exists before adding it.
- **Ask only when stuck.** Auto-detect first. Ask the user only for the spec when you genuinely cannot find or generate it.
- **Python only.** Supported paths: Schemathesis, the pytest plugin, and the Python API. If this is not a Python project, stop and say so.
- **Verify before declaring done.** You are not finished until a coverage report exists and you have shown its path and headline coverage number.
## Phase 1 — Detect
Inventory the repo and report what you find before continuing:
1. **Test framework** — Is `pytest` the runner? Check `pyproject.toml`, `pytest.ini`, `tox.ini`, `conftest.py`. Is `schemathesis` a dependency, and is `schemathesis run` an actual command this project uses (CI, Justfile/Makefile, docs)?
2. **HTTP client / app framework** — Detect `requests`, `httpx`, FastAPI, Django/DRF, or Flask from test imports and dependencies.
3. **Client acquisition** — Do tests obtain their HTTP client from a shared, overridable fixture (e.g. `client`, `api_client`), or construct it inline in each test? TraceCov records nothing unless the exercised client is wrapped, so this decides whether the pytest path can work transparently.
4. **Spec source** — Search for `openapi.*` / `swagger.*` files. Otherwise a framework that generates one: FastAPI `app.openapi()`, a DRF schema endpoint, or Flask. If none is found, **ask the user** for a path or URL. Do not guess.
5. **Environment manager** — pip/venv, uv, poetry, pdm, pipenv, or conda. Check lockfiles: `uv.lock`, `poetry.lock`, `pdm.lock`, `Pipfile.lock`.
6. **Test command** — how the suite is actually run.
## Phase 2 — Plan
Choose exactly one integration path:
1. **Schemathesis** — if `schemathesis run` is (or will be) the command used for coverage.
2. **pytest plugin** — if pytest is the runner.
3. **Python API** — otherwise: no pytest; a standalone script or notebook flow.
State the chosen path and a one-line reason. Then implement only that branch in Phase 4.
## Phase 3 — Install
Add `tracecov` using the project's environment manager (do not use a bare `pip install` if the project uses something else):
| Manager | Command |
|---|---|
| uv (project) | `uv add tracecov` |
| uv (bare venv) | `uv pip install tracecov` |
| poetry | `poetry add tracecov` |
| pdm | `pdm add tracecov` |
| pipenv | `pipenv install tracecov` |
| pip / venv | `pip install tracecov` |
After installing (and running the manager's sync/lock step if required), confirm it imports in that environment:
```
python -c "import tracecov; print(tracecov.__version__)"
```
## Phase 4 — Integrate
Implement only the branch chosen in Phase 2. Keep every edit idempotent.
### Branch A — Schemathesis
1. Create `hooks.py` at the repo root, or append to an existing hooks module. Skip if `tracecov.schemathesis.install()` is already present:
```python
import tracecov
tracecov.schemathesis.install()
```
2. Export the hooks variable wherever `schemathesis run` runs (shell, CI step, or Justfile/Makefile target):
```
export SCHEMATHESIS_HOOKS=hooks
```
3. Add `--coverage-format=html` to the run command, against the spec you located in Phase 1:
```
schemathesis run <the spec URL or path from Detect> --coverage-format=html
```
4. TraceCov requires Schemathesis >= 4.0. Check `schemathesis --version` and warn the user if it is older.
Report file: `./schema-coverage.html`.
### Branch B — pytest plugin
TraceCov's pytest plugin does **not** auto-track requests. Overriding `tracecov_schema` only turns on the summary; recording happens only when the exercised client is wrapped. This branch is two coordinated edits.
**1. Activate** — in `conftest.py`, override the session-scoped `tracecov_schema` fixture to return the spec dict. Returning `None` (the default) keeps the plugin dormant, so adding this is safe:
```python
import json
from pathlib import Path
import pytest
@pytest.fixture(scope="session")
def tracecov_schema():
return json.loads(Path("openapi.json").read_text())
```
**2. Wrap the client** — override the project's existing client fixture to wrap it, guarded with `if tracecov_map is not None`, using the adapter that matches the client:
```python
# requests
@pytest.fixture(scope="session")
def api_client(tracecov_map):
session = requests.Session()
if tracecov_map is not None:
tracecov_map.requests.track_session(session)
return session
```
```python
# httpx — also FastAPI's TestClient, which subclasses httpx.Client
@pytest.fixture
def api_client(tracecov_map):
client = httpx.Client()
if tracecov_map is not None:
tracecov_map.httpx.track_client(client)
return client
```
Adapters: `tracecov_map.requests.track_session(...)`, `tracecov_map.httpx.track_client(...)`, `tracecov_map.django.track_client(...)`, `tracecov_map.flask.track_client(...)`. Async clients work too — `track_client` accepts an `httpx.AsyncClient` or Django's `AsyncClient`.
**If no shared client fixture exists** (tests build their client inline): stay in pytest so reporting still works. Either (a) introduce a client fixture and refactor tests to use it, only if trivial, or (b) keep `tracecov_schema` active and record each call manually with `tracecov_map.<adapter>.record(request=..., response=...)`. Do not switch to Branch C — a pytest run has no single place to call `save_report()`.
Run with both the terminal summary and an HTML report, so you see the headline number immediately and still get the full report:
```
pytest --tracecov-format=text,html
```
Report file: `tracecov-report.html` (override via `--tracecov-report-html-path`).
### Branch C — Python API
Build a map, wrap the client, exercise the API, then save the report at the flow's single exit point:
```python
import tracecov
import requests
coverage = tracecov.CoverageMap.from_path("openapi.json") # or from_url(...) / from_dict(...)
session = coverage.requests.track_session(requests.Session())
# ... exercise the API through `session` ...
coverage.save_report(output_file="coverage.html")
```
Adapters mirror Branch B (`requests` / `httpx` / `django` / `flask`), including async clients (`httpx.AsyncClient`). For FastAPI, `tracecov.CoverageMap.from_dict(app.openapi())` works, but importing the app can trigger DB/settings side effects or be slow — prefer a static spec file or `from_url` when the app is heavy to import.
Report file: `coverage.html`.
## Phase 5 — Verify
Run the relevant command (the project's test command, or `schemathesis run` for Branch A). Then:
1. Confirm the branch's report file exists: `tracecov-report.html` (B), `schema-coverage.html` (A), or `coverage.html` (C).
2. **Assert traffic was actually recorded** — confirm at least one operation is not `uncovered` (in the report or terminal summary). A clean test run with an all-`uncovered` report means nothing was tracked; do not declare done — go to the diagnosis below.
3. Show the user the report path and the headline coverage number from the summary.
**If nothing was recorded (every operation `uncovered` / 0% across the board)**, diagnose in this order:
1. **Was a tracked client actually exercised?** Most common cause: the wrapped client was never used (inline-constructed client, or the wrong fixture overridden), or the HTTP layer is mocked so no real traffic flows. Fix the wiring so the exercised client is the tracked one.
2. **`base_path` mismatch.** If spec paths are `/users` but real calls hit `/api/v1/users`, set `base_path="/api/v1"` on the `CoverageMap` constructor and re-run once. In Branch B the default `tracecov_map` fixture builds the map without a `base_path`, so override `tracecov_map` directly to call `tracecov.CoverageMap.from_dict(schema, base_path="/api/v1")` — setting `base_path` on `tracecov_schema` has no effect.
Stop after these two checks; deeper tuning is out of scope.
## Done
Report to the user: the path you chose and why, the files you changed, the report path, and the headline coverage number. If traffic could not be recorded, give the specific diagnosis from Phase 5.