fix(playwright): close out remaining 8 dashboard test failures#217
Merged
fix(playwright): close out remaining 8 dashboard test failures#217
Conversation
CI on main has had Playwright failing for ~25 runs straight. After PR #214 bumped the per-test timeout to 60s the cascading timeout failures (graph viewer, variant nav) cleared, leaving eight real failures in the latest run on 58801b6: 1. artifacts.spec.ts:70 — mermaid-in-description not in svg-viewer 2. diagram-viewer.spec.ts:27,46 (schema-linkage) — wrong URL 3. filter-sort.spec.ts:225 — fill() doesn't fire keyup 4. filter-sort.spec.ts:253 — duplicate #cmd-k-input after reload 5. rivet-delta.spec.ts:142 — REQ-NEW-1 inside collapsed <details> 6. serve-variant.spec.ts:25 — selectOption + inline onchange flaky 7. api.spec.ts:291 — /embed/artifacts/REQ-001 returned 404 This commit fixes all eight, split between tests, render, and serve: * `rivet-cli/src/render/artifacts.rs`: wrap any `<pre class="mermaid">` emitted by `render_markdown(description)` in the same `.svg-viewer` toolbar shell used by the dedicated `diagram:` field. Adds `wrap_markdown_mermaid_in_svg_viewer` helper with three unit tests (single-block, multi-block, no-op). Pins the diagram-viewer parity contract for ARCH-CORE-001 and any other artifact whose description embeds a fenced mermaid block. * `rivet-cli/src/serve/layout.rs`: replace the inline `onchange` attribute on `#variant-selector` with a delegated `change` event listener in the variant-sync script. Inline event handlers are silently dropped by some headless Chromium configurations (the test case observed `[selected]` on the option but the URL never changed), while addEventListener fires reliably under Playwright's selectOption(). * `rivet-cli/src/serve/mod.rs`: two middleware fixes. - Build the rewritten /embed URI directly from the path+query string instead of round-tripping through `Uri::into_parts` / `Uri::from_parts`. The round-trip preserved an empty scheme/authority pair that confused the axum 0.8 router so the handler-side path was empty, returning a wrapped 404. The relative-form URI is what hyper actually hands axum for incoming requests, and it routes correctly. - Add `/search` to the wrap_full_page bypass list. The Cmd+K JS fetches `/search?q=...` via `fetch()` (no HX-Request header) and dumps the body into `#cmd-k-results`; without this bypass, the fragment was being wrapped in the full layout, so a second `<input id="cmd-k-input">` ended up inside `#cmd-k-results`, tripping Playwright's strict-mode locator on reload. * `tests/playwright/diagram-viewer.spec.ts`: schema-linkage URL is `/help` (where the diagram lives), not `/help/schema` (the type-list table). * `tests/playwright/filter-sort.spec.ts`: switch from `fill("OSLC")` to `pressSequentially("OSLC")`. The HTMX trigger is `keyup changed delay:300ms`; `fill()` only fires `input`, so HTMX never saw the trigger and the URL never picked up `?q=OSLC`. * `tests/playwright/rivet-delta.spec.ts`: open the `<details>Added` block before asserting REQ-NEW-1 is visible — the artifact ID lives inside that collapsed disclosure (rendered by scripts/diff-to-markdown.mjs:181-188). The serve middleware tweak is the only behaviour change visible to end-users; everything else is test-code or a layout-equivalence fix. Implements: REQ-007 Fixes: REQ-007 Verifies: REQ-007 Refs: FEAT-001
📐 Rivet artifact deltaNo artifact changes in this PR. Code-only changes (renderer, CLI wiring, tests) don't touch the artifact graph. |
Clippy's `items_after_test_module` lint (escalated to deny in PR #195's restriction-family bump) was flagging the new `mermaid_wrap_tests` module added in the previous commit because many production functions (`render_artifact_detail`, `linkify_source_refs`, `find_source_ref`, etc.) follow it in source order. Move the `#[cfg(test)] mod tests` to the bottom of the file — same behaviour, satisfies the lint. No production code change. Trace: skip
There was a problem hiding this comment.
⚠️ 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: ef3d00b | Previous: 58801b6 | Ratio |
|---|---|---|---|
store_lookup/100 |
2173 ns/iter (± 14) |
1718 ns/iter (± 16) |
1.26 |
store_lookup/1000 |
25362 ns/iter (± 100) |
19320 ns/iter (± 203) |
1.31 |
traceability_matrix/1000 |
61117 ns/iter (± 450) |
41047 ns/iter (± 91) |
1.49 |
query/100 |
772 ns/iter (± 4) |
630 ns/iter (± 1) |
1.23 |
query/1000 |
7369 ns/iter (± 33) |
5229 ns/iter (± 124) |
1.41 |
This comment was automatically generated by workflow using github-action-benchmark.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
PR #217 was meant to fix `tests/playwright/api.spec.ts:291` (oEmbed iframe page returning 404), but the in-place URI rewrite in `wrap_full_page` middleware turned out to be insufficient under axum 0.8: the router uses internal path state set up before `from_fn_with_state` middleware runs, so `head.uri = rewritten` is silently ignored. Added integration test `embed_artifact_returns_200_with_embed_layout` which reproduces the original 404 and pins the desired behaviour. Replace the URI-mutation approach with the axum-supported `Router::nest("/embed", view_routes())` pattern: extract the dashboard view routes into a small `view_routes` builder closure, mount it at both `/` and `/embed`. axum's `nest` strips the prefix when delegating to the inner router, so `/embed/artifacts/REQ-001` reaches the same `artifact_detail` handler as `/artifacts/REQ-001`. The `wrap_full_page` middleware still detects `is_embed = path.starts_with("/embed/")` to pick the embed layout (no nav, no sidebar), but no longer touches the request URI. The route inventory is preserved bit-for-bit: * All previously-routed paths still resolve at `/`. * Asset/API/hook routes (`/source-raw/{*path}`, `/api/links/{id}`, `/oembed`, `/api/v1/*`, `/wasm/{*path}`, `/docs-asset/{*path}`, `/assets/htmx.js`, `/assets/mermaid.js`, `/reload`, `/mcp`) stay at the root only — they were never useful under `/embed`. Tests: * `embed_artifact_returns_200_with_embed_layout` — regression guard (previously failing, now passing). * `embed_unknown_artifact_returns_200_with_not_found_body` — embed wrapping still applies for missing-artifact case. * All existing `oembed_*` and `embed_*` tests still pass (10/10). Implements: REQ-007 Fixes: REQ-007 Verifies: REQ-007 Refs: FEAT-001
This was referenced Apr 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
CI on
mainhas been failing Playwright for ~25 consecutive runs. AfterPR #214 bumped the per-test timeout to 60s the cascading timeout failures
(graph viewer, variant nav) cleared, leaving eight real failures in
the latest run on 58801b6. This PR fixes all eight, split between tests,
render, and serve.
artifacts.spec.ts:70artifact mermaid → svg-viewer<pre class=\"mermaid\">from description in.svg-viewerdiagram-viewer.spec.ts:27schema-linkage toolbar/help/schema(type-list); diagram lives on/helpdiagram-viewer.spec.ts:46schema-linkage fullscreenfilter-sort.spec.ts:225?q=push-urlfill()doesn't firekeyup; switch topressSequentially()filter-sort.spec.ts:253Cmd+K reload/searchinwrap_full_pagemiddleware (was duplicating#cmd-k-inputinto#cmd-k-results)rivet-delta.spec.ts:142shipping summaryREQ-NEW-1lives inside collapsed<details>Added; expand before asserting visibilityserve-variant.spec.ts:25variant navonchangewas occasionally skipped under selectOption; switch to delegatedchangelistenerapi.spec.ts:291/embed/* returns 404/embedviaRouter::nest(axum 0.8 ignores middleware-driven URI rewrites — see commit ef3d00b)Why these are the right fixes
artifacts.spec.ts:70 — render fix
ARCH-CORE-001has a fenced```mermaidblock in itsdescription, not in the structured
diagram:field. The dedicatedfield already wraps in
.svg-viewer; the description path emitted abare
<pre class=\"mermaid\">fromrender_markdown. New helperwrap_markdown_mermaid_in_svg_viewerpost-processes the rendereddescription and wraps each mermaid block in the same toolbar shell
(zoom-fit / fullscreen / popout). Three unit tests pin the wrapping
behaviour.
serve middleware —
/searchbypassThe Cmd+K JS does
fetch('/search?q=...')(no HX-Request header) anddumps the response into
#cmd-k-results. Without bypass, thewrap_full_pagemiddleware wraps/searchin the full layout — thatlayout contains another
<input id=\"cmd-k-input\">, and after thefetch resolves you have two
#cmd-k-inputnodes in the DOM. Playwright'sstrict-mode locator was failing on the duplicate after reload.
serve routing —
/embed/*via Router::nestThe previous wrap_full_page middleware tried to strip /embed by
mutating the request URI in-place:
axum 0.8 routes against internal path state set up before
from_fn_with_statemiddleware runs, so the URI mutation is silentlyignored — the inner router still sees
/embed/...and returns 404. Newintegration test
embed_artifact_returns_200_with_embed_layoutreproduces this exact 404 and pins the desired behaviour.
The fix is to use the axum-supported
Router::nest(\"/embed\", view_routes())pattern: extract the dashboard view routes into a builder closure and
mount them at both
/and/embed. axum'sneststrips the prefixwhen delegating to the inner router, so
/embed/artifacts/REQ-001reaches the same
artifact_detailhandler as/artifacts/REQ-001.The middleware still picks the embed layout when wrapping the response
body, but no longer touches the URI.
Variant onchange — inline → addEventListener
Inline
onchange=\"...\"attributes are flaky under headless Chromiumwhen the change event is fired by Playwright's
selectOption()— theattribute parses fine but is occasionally not invoked (visible in the
trace: option shows
[selected], URL unchanged). Delegating to asingle
addEventListener('change', ...)in the variant-sync scriptfires reliably across all environments and is also more CSP-friendly.
Test-code fixes
pressSequentiallyinstead offillbecause the HTMX trigger iskeyup changed delay:300ms;fill()only firesinput.<details>Added</details>must be expanded before assertingvisibility on its content — REQ-NEW-1 lives inside.
/helpis where the schema-linkage mermaid renders;/help/schemais the type-list table.Test plan
cargo build --release— cleancargo clippy --release -p rivet-cli --all-targets -- -D warnings— cleancargo test --release --bin rivet -- mermaid_wrap— 3/3 passcargo test --release --test serve_integration -- embed— 10/10 pass(including new
embed_artifact_returns_200_with_embed_layout,embed_unknown_artifact_returns_200_with_not_found_body)cargo test --release --test serve_integration -- oembed— 6/6 passthe pre-existing flakes outside this PR's scope)
🤖 Generated with Claude Code