ci: add end-to-end test tier, CI workflow, and coverage gating #1

Merged
alexion merged 3 commits from task-0019-ci-integration-tier into main 2026-07-11 14:03:45 -04:00
Owner

Summary

Adds the third (end-to-end) test tier and the CI workflow that runs all three tiers, plus coverage reporting with regression thresholds. Implements task 0019 (.claude/tasks/0019-ci-integration-tier.md); the coverage work rides along on the same branch as a separate concern.

Three commits, each self-contained:

  1. ci: end-to-end tier + Gitea Actions workflow — the task 0019 deliverable.
  2. test: coverage tooling + regression thresholds — v8 coverage, gated in CI.
  3. test: close tea/error-classifier gaps, raise thresholds — lifts coverage and the ratchet.

End-to-end tier (task 0019)

  • .gitea/workflows/ci.yml — runs on push-to-main and on PRs. Executes the unit + integration tiers (npm run test:coverage) and the end-to-end tier (npm run test:e2e) against a disposable gitea/gitea:1.23.5 service container. The job runs inside a node:20-bookworm container so the service is reachable by name (gitea:3000) on both Gitea Actions and GitHub Actions — the file stays near-verbatim GitHub-compatible.
  • test/e2e/ — provisions its own repo, token, and seed issues on the live instance entirely over HTTP (health-wait → first-user web sign-up → scoped token → repo/issue seeding, no docker exec), then drives the real CLI seam and asserts output + exit codes for the tracer command set (issue list, --state, --limit, REPO_NOT_FOUND, invalid --state, home view).
  • Fixture-vs-live guard — a single exported COVERED_ISSUE_PATHS contract (the paths the issue-list extractors read) is asserted against both the recorded fixture and the live response, so a drift in either fails the tier.
  • The suite is gated on GITEA_AXI_E2E_URL, so the default npm test stays dependency-free.

Coverage

  • v8 coverage via npm run test:coverage; src/** only, excluding the types-only deps.ts and the bin entrypoint main.ts.
  • Regression-ratchet thresholds enforced in CI: statements 92 / branches 87 / functions 95 / lines 92.
  • Added tests for previously-uncovered credential and error-classification paths brought overall coverage from ~87% to ~93% statements / ~89% branches / 100% functions (errors.ts now 100%; tea.ts 96%, remainder is defensive code unreachable through the seam).

Verification

  • Ran the e2e tier against a real gitea/gitea:1.23.5 container — 7/7 green, which also confirms the pinned tag pulls.
  • The live run caught a real bug the earlier mock could not: creating a repo under a user (POST /user/repos) requires the write:user token scope on Gitea 1.23, not write:repository — fixed in provision.ts. Exactly the fixture-vs-live divergence class this tier exists to catch.
  • Default suite green (68 tests); typecheck clean.

Acceptance criteria (task 0019)

  • Workflow runs on push/PR, executing unit+integration and e2e tiers
  • Disposable Gitea as a service container pinned to a specific stable tag
  • E2e tests provision their own repo/token/seed data and assert real CLI output + exit codes for the tracer set
  • Workflow uses only near-verbatim GitHub-Actions-compatible syntax
  • A fixture-vs-live divergence in a covered response shape fails the e2e tier

Reviewer notes

  • CI needs a Docker-backed runner (the workflow uses container: + services:).
  • gitea/gitea:1.23.5 was chosen to match the gitea-js client line (^1.23.0); bump deliberately.
## Summary Adds the third (end-to-end) test tier and the CI workflow that runs all three tiers, plus coverage reporting with regression thresholds. Implements task `0019` (`.claude/tasks/0019-ci-integration-tier.md`); the coverage work rides along on the same branch as a separate concern. Three commits, each self-contained: 1. **`ci:` end-to-end tier + Gitea Actions workflow** — the task 0019 deliverable. 2. **`test:` coverage tooling + regression thresholds** — v8 coverage, gated in CI. 3. **`test:` close `tea`/error-classifier gaps, raise thresholds** — lifts coverage and the ratchet. ## End-to-end tier (task 0019) - **`.gitea/workflows/ci.yml`** — runs on push-to-`main` and on PRs. Executes the unit + integration tiers (`npm run test:coverage`) and the end-to-end tier (`npm run test:e2e`) against a disposable `gitea/gitea:1.23.5` service container. The job runs inside a `node:20-bookworm` container so the service is reachable by name (`gitea:3000`) on both Gitea Actions and GitHub Actions — the file stays near-verbatim GitHub-compatible. - **`test/e2e/`** — provisions its own repo, token, and seed issues on the live instance entirely over HTTP (health-wait → first-user web sign-up → scoped token → repo/issue seeding, no `docker exec`), then drives the real CLI seam and asserts output + exit codes for the tracer command set (`issue list`, `--state`, `--limit`, `REPO_NOT_FOUND`, invalid `--state`, home view). - **Fixture-vs-live guard** — a single exported `COVERED_ISSUE_PATHS` contract (the paths the issue-list extractors read) is asserted against *both* the recorded fixture and the live response, so a drift in either fails the tier. - The suite is gated on `GITEA_AXI_E2E_URL`, so the default `npm test` stays dependency-free. ## Coverage - v8 coverage via `npm run test:coverage`; `src/**` only, excluding the types-only `deps.ts` and the bin entrypoint `main.ts`. - Regression-ratchet thresholds enforced in CI: **statements 92 / branches 87 / functions 95 / lines 92**. - Added tests for previously-uncovered credential and error-classification paths brought overall coverage from ~87% to **~93% statements / ~89% branches / 100% functions** (`errors.ts` now 100%; `tea.ts` 96%, remainder is defensive code unreachable through the seam). ## Verification - Ran the e2e tier against a real `gitea/gitea:1.23.5` container — **7/7 green**, which also confirms the pinned tag pulls. - The live run caught a real bug the earlier mock could not: creating a repo under a user (`POST /user/repos`) requires the `write:user` token scope on Gitea 1.23, not `write:repository` — fixed in `provision.ts`. Exactly the fixture-vs-live divergence class this tier exists to catch. - Default suite green (68 tests); typecheck clean. ## Acceptance criteria (task 0019) - [x] Workflow runs on push/PR, executing unit+integration and e2e tiers - [x] Disposable Gitea as a service container pinned to a specific stable tag - [x] E2e tests provision their own repo/token/seed data and assert real CLI output + exit codes for the tracer set - [x] Workflow uses only near-verbatim GitHub-Actions-compatible syntax - [x] A fixture-vs-live divergence in a covered response shape fails the e2e tier ## Reviewer notes - CI needs a **Docker-backed** runner (the workflow uses `container:` + `services:`). - `gitea/gitea:1.23.5` was chosen to match the gitea-js client line (`^1.23.0`); bump deliberately.
alexion added 3 commits 2026-07-11 13:54:23 -04:00
Add the end-to-end test tier: a Gitea Actions workflow (GitHub-compatible)
that runs the unit+integration tiers plus e2e tests against a pinned
disposable Gitea service container. The e2e suite provisions its own repo,
token, and seed data over HTTP and drives the real CLI seam, gated on
GITEA_AXI_E2E_URL so the default suite stays dependency-free.

A fixture-vs-live shape guard anchors the issue-list FieldDef paths against
both the recorded fixture and the live response, failing on divergence.
Add v8 coverage via a test:coverage script and vitest config: measure src
only, exclude the types-only deps.ts and the bin entrypoint main.ts, and
gate on ratcheted thresholds (statements 85, branches 78, functions 90,
lines 85) set just under current coverage. CI runs the unit+integration
tier through coverage so a real drop fails the build.
test: close tea and error-classifier coverage gaps, raise thresholds
All checks were successful
CI / test (pull_request) Successful in 53s
CI / test (push) Successful in 21s
ae0f4c2675
Cover the previously untested credential and error-classification paths:
- tea.ts: failing/invalid/non-array `tea login list`, a failing token
  helper, and an empty token, all driven through the CLI seam via the fake
  tea harness (now parametrizable for exit codes and output).
- errors.ts: a unit-tier test of classifyHttpError for the pure-classifier
  branches no shipped command reaches yet (issue/pull 404s, the
  already-classified passthrough, transport failures, no-body defaults).

errors.ts is now fully covered and tea.ts is at 96% (the remainder is
defensive code unreachable through the seam). Overall coverage rose from
~87% to ~93% statements / ~89% branches; the ratchet is raised to
92/87/95/92 accordingly.
alexion merged commit ae0f4c2675 into main 2026-07-11 14:03:45 -04:00
alexion deleted branch task-0019-ci-integration-tier 2026-07-11 14:03:45 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: alexion/gitea-axi#1