Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ jobs:
# Tests that require a live local Ollama daemon skip themselves
# automatically (pytest.mark.skipif) — no CI-specific filtering
# needed.
run: uv run pytest tests -q
# --cov-fail-under guards the 92% the README advertises. The gate is
# 91, not 92: the headline figure is coverage.py rounding ~91.9%
# (1545/1681), and it drifts to ~91.7% between runs.
run: uv run pytest tests -q --cov --cov-report=term --cov-fail-under=91

frontend:
runs-on: ubuntu-latest
Expand All @@ -78,7 +81,7 @@ jobs:

- name: Unit test
working-directory: apps/web
run: npm run test
run: npm run test:coverage

- name: Install Playwright browsers
working-directory: apps/web
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ apps/api/.pytest_cache/
apps/api/.mypy_cache/
apps/api/.ruff_cache/
apps/api/*.egg-info/
apps/api/.coverage

# Node
apps/web/node_modules/
Expand Down
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.PHONY: setup up down migrate ingest ingest-fixtures db-reset \
test test-backend test-frontend test-e2e lint format typecheck \
test test-backend test-frontend test-e2e coverage lint format typecheck \
eval-seed eval-run eval demo

setup:
Expand Down Expand Up @@ -44,6 +44,10 @@ test-frontend:
test-e2e:
cd apps/web && npm run test:e2e

coverage:
cd apps/api && uv run pytest tests -q --cov --cov-report=term-missing
cd apps/web && npm run test:coverage

demo:
./scripts/demo.sh

Expand Down
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
### A local-first AI business analyst that investigates *why* a metric changed — not just that it did

[![CI](https://github.com/Bruce1508/RootLens/actions/workflows/ci.yml/badge.svg)](https://github.com/Bruce1508/RootLens/actions/workflows/ci.yml)
[![Backend coverage](https://img.shields.io/badge/backend%20coverage-92%25-2ea44f?style=flat-square)](#status)
[![License: MIT](https://img.shields.io/badge/license-MIT-black?style=flat-square)](LICENSE)
[![Status](https://img.shields.io/badge/milestones-0--6%20complete-2ea44f?style=flat-square)](#status)
[![Backend](https://img.shields.io/badge/backend-FastAPI%20%2F%20Python%203.13-3776AB?style=flat-square&logo=python&logoColor=white)](apps/api)
Expand Down Expand Up @@ -137,8 +138,21 @@ engine makes — including, since Milestone 6, the engine's own reads.
The dashboard's investigate/history flow (PRD acceptance criterion #4)
is wired end-to-end, not just reachable via the API.

What this *doesn't* mean: RootLens is not under active maintenance,
does not have CI/CD or a hosted deployment, and its [known
**Tests** — 141 backend tests at **92% coverage** over `app/`, 22
frontend unit tests, and 4 Playwright end-to-end tests. Reproduce both
numbers with `make coverage`.

Frontend *unit* coverage is 12.4%, and that figure is a deliberate
consequence of where the tests live rather than a gap: `lib/` and the
presentational components are unit-tested in jsdom, while the four page
components are covered end-to-end by Playwright, which the unit
coverage run cannot see. Vitest is configured to measure the whole
`app/`, `components/`, and `lib/` tree — not only the files a test
happens to import — so that number stays honest as the app grows.

What this *doesn't* mean: RootLens is not under active maintenance, and
while CI runs on every push, there is no continuous deployment and no
hosted demo — evaluating it means running it locally. Its [known
limitations](#known-limitations) are recorded deliberately rather than
smoothed over — read them before assuming a given behavior is a bug.

Expand Down Expand Up @@ -241,6 +255,7 @@ observed here.
| `make eval-seed` / `make eval-run` / `make eval` | Seed and run the incident benchmark |
| `make test` | Run backend (pytest) and frontend (Vitest) tests |
| `make test-e2e` | Run frontend end-to-end tests (Playwright, mocked API) |
| `make coverage` | Print backend and frontend coverage reports |
| `make lint` / `make format` / `make typecheck` | Quality gates for both apps |

<br>
Expand Down
4 changes: 4 additions & 0 deletions apps/api/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@ dev = [
"mypy>=2.3.1",
"pytest>=9.1.1",
"pytest-asyncio>=1.4.0",
"pytest-cov>=7.0",
"ruff>=0.16.5",
]

[tool.pytest.ini_options]
testpaths = ["tests"]
asyncio_mode = "auto"

[tool.coverage.run]
source = ["app"]

[tool.ruff]
line-length = 100
target-version = "py313"
Expand Down
100 changes: 100 additions & 0 deletions apps/api/uv.lock

Large diffs are not rendered by default.

176 changes: 175 additions & 1 deletion apps/web/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"start": "next start",
"lint": "eslint",
"test": "vitest run",
"test:coverage": "vitest run --coverage",
"test:e2e": "playwright test",
"format": "prettier --write .",
"typecheck": "tsc --noEmit"
Expand All @@ -27,6 +28,7 @@
"@types/react": "^19",
"@types/react-dom": "^19",
"@vitejs/plugin-react": "^6.1.1",
"@vitest/coverage-v8": "^4.1.11",
"eslint": "^9",
"eslint-config-next": "15.5.25",
"jsdom": "^29.1.1",
Expand Down
10 changes: 10 additions & 0 deletions apps/web/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,15 @@ export default defineConfig({
// e2e/ holds @playwright/test specs (a different runner, different
// `test()` signature) — excluded so vitest doesn't try to collect them.
exclude: ["**/node_modules/**", "**/e2e/**"],
coverage: {
// Without an explicit include, v8 only reports on files a test
// imported — which reads as high coverage of a very small app.
// Name the real source tree so untested files count against us.
include: ["app/**/*.{ts,tsx}", "components/**/*.tsx", "lib/**/*.ts"],
exclude: ["**/__tests__/**"],
// Text only: the default reporters also write a coverage/ HTML
// bundle whose vendored JS then trips `npm run lint`.
reporter: ["text"],
},
},
});
Loading