Skip to content

Spec 040 — Core-flow test coverage + believable seeder - #119

Merged
Copxer merged 2 commits into
mainfrom
spec/040-core-flow-test-coverage
Jul 1, 2026
Merged

Spec 040 — Core-flow test coverage + believable seeder#119
Copxer merged 2 commits into
mainfrom
spec/040-core-flow-test-coverage

Conversation

@Copxer

@Copxer Copxer commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Closes #118

Spec: `specs/phase-9-polish/040-core-flow-test-coverage.md`

Phase 9's acceptance criterion said "every critical flow has an end-to-end test." Today the suite had none — every test was single-action. This spec ships 5 end-to-end tests + a rich seeder that fills every dashboard page with real data on `db:seed`.

Summary

  • 3 helpers on `tests/TestCase.php` — `verifiedUser`, `projectWithRepository`, `signedGitHubWebhook`. Bulk-stripped 25 identical private `verifiedUser` duplicates across existing test files (perl regex on the exact 4-line body; all tests still green post-strip).
  • 5 end-to-end tests under `tests/Feature/EndToEnd/`:
    • `RegistrationAndOverviewTest` — POST /register → unverified user blocked from /overview → signed verify link → verified → /overview 200.
    • `ProjectAndRepositoryFlowTest` — POST /projects → `ImportRepositoryAction` → sync job dispatched → run inline with `Http::fake` → repo lands `synced` with real metadata.
    • `WebhookToAlertFlowTest` — signed `workflow_run` webhook → POST /webhooks/github → `ProcessGitHubWebhookJob` inline → workflow_run row upserted + alert opens → POST /alerts/{id}/resolve → alert Resolved.
    • `AgentTelemetryAndRecoveryFlowTest` — issue token → telemetry POST → host pending→online → force stale last_seen_at → `DetectOfflineHostsAction` → host offline + alert opens → fresh telemetry → recovery + alert auto-resolves.
    • `WebsiteProbeAndAlertFlowTest` — Website Up → `RecordWebsiteCheckAction(Down)` → website Down + alert opens → `RecordWebsiteCheckAction(Up)` → recovery + auto-resolve.
  • 3 new seeders + extended `RepositorySeeder`:
    • `AlertSeeder` — 4 alerts (open critical, ack'd warning, resolved, muted) so the /alerts page, Overview KPI, and TopBar bell all render.
    • `WebsiteSeeder` — 3 websites with 20-minute check history (up / slow / down) so the uptime aggregate has data.
    • `HostSeeder` — 2 hosts: 1 online with 5 containers + metric snapshots, 1 offline (past heartbeat threshold).
    • `RepositorySeeder` extended with `seedWorkItems()` — 5 issues + 3 PRs + 4 workflow_runs per synced repo (~25 issues total, drives Work Items page).
    • `DatabaseSeeder` wires them in dependency order.
  • `DemoSeedSmokeTest` runs `db:seed` against a fresh test DB and asserts threshold counts (≥4 projects, ≥8 repos, ≥20 issues, ≥2 hosts w/ 1 online + 1 offline, ≥3 websites, ≥4 alerts with an open + resolved present).

Test plan

  • Five end-to-end test files exist under `tests/Feature/EndToEnd/`, one per flow.
  • `tests/TestCase.php` exposes `verifiedUser`, `signedGitHubWebhook`, `projectWithRepository` helpers.
  • `php artisan db:seed` against a fresh DB produces ≥4 projects, ≥8 repos with linked issues + PRs + workflow runs, ≥2 hosts, ≥3 websites, ≥4 alerts.
  • `DemoSeedSmokeTest` runs `db:seed` and asserts those counts.
  • Full suite runtime stays under 90s on CI (~34s local; +6 tests → estimate +5s).
  • Pint clean. `php artisan test` green (782 / 2964, was 776 before). `npm run build` clean.

Self-review notes

Automated code-reviewer subagent errored out (not-logged-in state), so this is a manual pass through my prep questions:

  1. Bulk-strip risk — perl regex only matched the exact 4-line signature+body pattern of the identical duplicate. Any file with a variant kept its version (would have shown up as unstripped). All 782 tests pass post-strip, so no runtime break; if any file had a subtle variant that the strip missed, it would still work (parent method inherited).

  2. Queue boundary in end-to-end tests — Chose inline `(new Job($id))->handle()` after asserting dispatch in one test (Project+Repo flow). The rest run the job or action directly since they need to observe side-effects on the persisted state. This is what Laravel's testing docs suggest for pipeline chains: mock outbound network, exercise real container resolution + queue dispatch path where it matters, run the target job inline where the assertion needs its outcome.

  3. `signedGitHubWebhook` sets config side-effect — Acceptable. The helper's purpose IS to make a signed webhook request the controller accepts; that requires the config value to match. Alternative (return the secret, let caller set it) is more verbose without a real benefit.

  4. Issue threshold at 20 — Justified: `seedWorkItems()` scopes to `sync_status = synced` because unsynced repos wouldn't have issues in real usage. ~5 of ~10 seeded repos are synced (first per project + random subset), yielding ~25 issues. Threshold ≥20 gives headroom for random-seeder variance.

  5. `forceFill(['last_seen_at' => now()->subMinutes(5)])` in agent flow test — Standard test practice. `travel()->minutes()` would advance the whole clock, which then breaks `recorded_at` on the earlier POST + the recovery POST that follows. Force-fill is targeted + doesn't drift other state.

  6. Mixed Bus::fake usage across the 5 tests — Intentional. When a test asserts on side-effects that fire via dispatched jobs (webhook → alert opens, telemetry → offline transition), faking would suppress the observable state change. When the test only cares that dispatch happened (Project+Repo), fake is used. Documented in inline comments per test.

  7. `DemoSeedSmokeTest` as one big method — Runs in ~250ms with 16 assertions across 6 domain slices. Splitting into 6 per-seeder tests would 6x the DB refresh cost. Not worth the split.

Deferred follow-ups (non-blocking):

  • Idempotent seeders (currently expect fresh DB via `migrate:fresh --seed`).
  • Vitest + JS unit tests (separate chore PR).
  • More end-to-end variants covering error paths (auth denials, invalid payloads).

@Copxer
Copxer merged commit 2a99735 into main Jul 1, 2026
1 check passed
@Copxer
Copxer deleted the spec/040-core-flow-test-coverage branch July 1, 2026 22:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spec 040 — Core-flow test coverage + believable seeder

1 participant