Skip to content

feat(tests/playwright): rendering invariant coverage — 10 new tests#215

Merged
avrabe merged 1 commit intomainfrom
feat/playwright-rendering-coverage-audit
Apr 26, 2026
Merged

feat(tests/playwright): rendering invariant coverage — 10 new tests#215
avrabe merged 1 commit intomainfrom
feat/playwright-rendering-coverage-audit

Conversation

@avrabe
Copy link
Copy Markdown
Contributor

@avrabe avrabe commented Apr 26, 2026

Summary

Audit-driven Playwright coverage expansion. Cross-referenced every .route(...) declaration in rivet-cli/src/serve/mod.rs against every page.goto(...) / page.request.get(...) in tests/playwright/*.spec.ts to identify rendering paths the dashboard silently relies on but that no test exercises end-to-end.

10 new tests pinned in tests/playwright/rendering-invariants.spec.ts. No production code was changed — all audit findings are either already-correct behavior worth pinning, or known asymmetries that should be gated against silent regression.

Audit table

Route Status before Test added
/ Covered
/artifacts Deeply covered
/artifacts/{id} Covered — for ? happy path; NEW for unknown ID
/artifacts/{id}/preview None NEW
/artifacts/{id}/graph None NEW
/validate Covered
/matrix Covered
/matrix/cell None NEW
/graph Covered NEW for ?variant=...
/stats Covered
/coverage Covered
/documents, /documents/{id} Covered
/search Smoke (status only) NEW for empty + no-results fragments
/verification Covered
/stpa Deeply covered
/eu-ai-act None NEW
/results, /results/{run_id} Covered
/source, /source/{*path} Covered
/diff Covered
/doc-linkage Covered
/traceability, /traceability/history Covered
/help, /help/schema, /help/links, /help/rules, /help/docs Covered
/help/docs/{*slug} None NEW
/externals, /externals/{prefix} Covered
/variants Covered
/oembed Covered (api.spec)
/embed/* None (URL pattern referenced by oembed but never navigated) NEW
/api/v1/* Covered (api.spec)
/assets/*, /wasm/*, /source-raw/*, /docs-asset/* Covered (asset-loading.spec)

Per-test summary

  1. /eu-ai-act — full-page render through middleware. Pins that the route renders the EU-AI-Act compliance heading and the layout middleware wraps it with <nav>. Whole route was a black box before.

  2. /help/docs/{slug} — topic page renders with back-link. /help/docs index was tested; clicking through to a topic was not. Pins the <a href=\"/help/docs\"> back-link contract on a real slug (cli).

  3. /artifacts/{id}/preview — hover-tooltip fragment shape. This endpoint is hit by hx-get on hover but never directly navigated. Pins the .art-preview / .art-preview-header / .art-preview-title class hierarchy that the hover-tooltip CSS relies on.

  4. /artifacts/{id}/graph — ego-graph wraps in #ego-graph-viewer. The diagram-viewer parity test (diagram-viewer.spec.ts) covered /graph, /doc-linkage, /help/schema but not the per-artifact ego-graph. Closes that gap with the same toolbar contract.

  5. /matrix/cell<ul> fragment as direct child of main#content. The matrix-cell drill-down (HTMX-loaded into /matrix) was never exercised end-to-end. Pins the wrapper shape so the matrix view's HTMX target keeps working.

  6. /embed/{url}embed_layout (no nav, no .shell). The oEmbed test in api.spec.ts confirms the URL pattern is generated but never navigates to it. Pins the structural difference: embed has <main id=\"content\"> but no <nav role=\"navigation\"> and no body > .shell — the contract VS Code WebView relies on.

  7. Mermaid in artifact description — emitted as <pre class=\"mermaid\">, NOT wrapped in .svg-viewer. ARCH-CORE-001 has a fenced ```mermaid block in its description (see artifacts/architecture.yaml). Pins TWO things: (a) the markdown renderer recognises and emits <pre.mermaid>, (b) description-mermaid is currently NOT wrapped in .svg-viewer (only the dedicated diagram: field is). This is a known UX asymmetry; pinning it forces any future fix to be intentional.

  8. /graph?variant=... silently unscoped. graph_view uses GraphParams (not ViewParams) and has no variant field — the URL param is dropped at the handler level. But the layout middleware extracts variant= from the URL and injects the variant-banner anyway. Pins the surprising current state: banner says "Filtered to variant: minimal-ci" but the graph is the unfiltered full graph. Gated against silent change.

  9. /artifacts/UNKNOWN-ID returns 200 (not 404) with "Not Found" body. artifact_detail always returns Html(...).into_response() — i.e. status 200 — even when the artifact is missing. Consistent with /externals/<unknown-prefix> (already pinned at externals.spec.ts:80) but inconsistent with the gut expectation. Now gated.

  10. /search empty-query + no-results fragments emit .cmd-k-empty. routes.spec.ts smoke-tested /search?q=OSLC. Both edge cases (no query, no results) emit a specific .cmd-k-empty placeholder with distinct copy ("Type to search" vs "No results"). The cmd-k overlay UI keys off this class.

Audit gaps NOT pinned (deferred)

The audit also surfaced rendering invariants that warrant attention but weren't pinned in this PR — they require a product decision rather than a test:

  • Variant-scoping coverage gap. Beyond graph_view, these handlers also lack a variant param: verification_view, eu_ai_act_view, traceability_view, doc_linkage_view, documents_list, results_view, externals_list, search_view. The layout still shows the banner for any URL with ?variant=.... Test feat: cross-repository artifact linking #8 pins the most prominent case (/graph); the others are similarly inconsistent and should probably either all opt in or all opt out. Tracked separately.
  • Empty-state structural pins. /results (no test results), /externals (no externals configured), /coverage (empty rules) all have bespoke empty-state HTML that's never exercised in dogfood data. These need a feature-flagged test fixture rather than a runtime test.
  • HTMX-vs-direct rendering parity. The wrap_full_page middleware decides per-request whether to wrap in layout. The decision tree (is_htmx, is_print, is_embed, path prefixes) is non-trivial; only the obvious cases are tested.

Test plan

  • npx playwright test tests/playwright/rendering-invariants.spec.ts passes locally
  • CI runs the full Playwright suite — no regression in existing specs
  • If any test fails on CI, the failure points to either a real regression or a deliberate behavior change that the test correctly gated

Refs: FEAT-001

Audit of serve/mod.rs route inventory vs Playwright goto/request URLs
identified rendering paths that lacked end-to-end test coverage. New
spec file rendering-invariants.spec.ts pins ten such invariants:

  1. /eu-ai-act renders the compliance dashboard heading + nav.
  2. /help/docs/{slug} renders a topic page with back-link to index.
  3. /artifacts/{id}/preview emits the .art-preview hover-tooltip
     fragment with header + title structure.
  4. /artifacts/{id}/graph wraps the ego-graph in #ego-graph-viewer
     with the standard svg-viewer toolbar (zoom/fullscreen/popout) —
     same invariant as /graph and /doc-linkage.
  5. /matrix/cell returns a <ul> fragment as direct child of
     main#content (the cell drill-down used by HTMX in /matrix).
  6. /embed/* uses embed_layout (no nav, no .shell) — distinct from
     page_layout. Pins the structural difference referenced by oembed.
  7. Mermaid in artifact `description` field is emitted as
     <pre class="mermaid"> by the markdown renderer but is NOT
     wrapped in .svg-viewer (only the dedicated `diagram:` field
     gets that). Pins the current asymmetry; any future intent
     change is gated.
  8. /graph?variant=... silently UNSCOPED (graph_view uses GraphParams
     not ViewParams). The layout still injects the variant-banner
     because it extracts variant from the URL — a known asymmetry
     vs /artifacts/coverage/etc that DO honour variant scoping.
  9. /artifacts/UNKNOWN-ID returns 200 (not 404) with "Not Found"
     body, consistent with /externals/<unknown-prefix>. Pins the
     status-code convention so any future move to proper 404 is
     a conscious decision.
 10. /search empty-query and /search?q=zzznonexistent both emit
     .cmd-k-empty fragments with distinct copy ("Type to search"
     vs "No results"). Pins the cmd-k UI contract; previously only
     /search?q=OSLC was smoke-tested.

No production code changed. The audit also documented gaps that were
NOT pinned (variant-scoping for /verification, /traceability,
/doc-linkage, /documents, /results, /externals — all lack the
variant param entirely; that's a separate FEAT decision).

Refs: FEAT-001
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 26, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Rivet Criterion Benchmarks'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.20.

Benchmark suite Current: bdc9a10 Previous: 58801b6 Ratio
store_lookup/1000 24942 ns/iter (± 38) 19320 ns/iter (± 203) 1.29
traceability_matrix/100 4918 ns/iter (± 51) 3903 ns/iter (± 7) 1.26
diff/1000 719936 ns/iter (± 14484) 597822 ns/iter (± 2900) 1.20
query/100 773 ns/iter (± 7) 630 ns/iter (± 1) 1.23
query/1000 6799 ns/iter (± 183) 5229 ns/iter (± 124) 1.30

This comment was automatically generated by workflow using github-action-benchmark.

@avrabe avrabe merged commit 7a22f3e into main Apr 26, 2026
22 of 27 checks passed
@avrabe avrabe deleted the feat/playwright-rendering-coverage-audit branch April 26, 2026 13:09
avrabe added a commit that referenced this pull request Apr 27, 2026
feat(serve): variant scoping for 8 handlers (close incoherence flagged in PR #215)
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.

1 participant