Skip to content

test: handler-level LSP harness coverage for on_completion / on_goto_definition - #210

Merged
mikebronner merged 2 commits into
mainfrom
chore/207-handler-level-lsp-harness-coverage-for-oncompletio
Jun 18, 2026
Merged

mikebronner merged 2 commits into
mainfrom
chore/207-handler-level-lsp-harness-coverage-for-oncompletio

Conversation

@mikebronner

@mikebronner mikebronner commented Jun 18, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Implements #207 — handler-level LSP harness coverage for the Inertia goto-definition and completion request handlers, the follow-up Holmes flagged in his review of #10 / PR #204.

Prior Inertia coverage stopped at the pure path-math seam (resolve_page_candidates, list_pages in inertia.rs) and never drove the real LSP request handlers that wire those seams to the wire protocol. This adds end-to-end tests that build a real backend through the tower_lsp::LspService harness — the same pattern as flux_goto_def_handler.rs / blade_var_rename_handler.rs — so a regression in the handler arm (a dropped containment guard, an inverted existence check, a phantom or missing target) is now caught.

Changes

  • New laravel-lsp/src/tests/inertia_handler.rs, wired into laravel-lsp/src/tests/mod.rs.
  • Goto tests drive Backend::resolve_inertia_file on a backend primed with a minimal root-only cached_config.
  • Completion tests drive Backend::get_all_inertia_pages on a backend primed with root_path — matching exactly the state each handler reads.
  • All fixtures use real files in a tempfile::TempDir; the document cache is left empty so file_exists_cached falls through to real disk probes, as the live server does.

Acceptance Criteria

  • A new test file laravel-lsp/src/tests/inertia_handler.rs is created and wired into laravel-lsp/src/tests/mod.rs
  • Tests use LspService::new(LaravelLanguageServer::new) to build a real backend — no mock; same harness pattern as flux_goto_def_handler.rs and blade_var_rename_handler.rs
  • goto — happy path (.vue): resolve_inertia_file("Dashboard") on a backend primed with a minimal cached_config (root only) and a real resources/js/Pages/Dashboard.vue returns the correct PathBuf
  • goto — nested page (.tsx): resolve_inertia_file("Auth/Login") with resources/js/Pages/Auth/Login.tsx returns the nested PathBuf
  • goto — unresolvable returns None: resolve_inertia_file("Ghost") with no matching page file returns None
  • goto — extension priority: when both Dashboard.vue and Dashboard.tsx exist with no dominant extension primed, .vue wins (first in PAGE_EXTENSIONS order)
  • completion — pages listed: get_all_inertia_pages() on a backend primed with root_path pointing at a tempdir containing Dashboard.vue and Auth/Login.tsx returns ["Auth/Login", "Dashboard"] (sorted, without extension)
  • completion — empty project: get_all_inertia_pages() with no resources/js/Pages/ directory returns an empty list
  • completion — extension filter: non-Inertia files (.php, .blade.php) under resources/js/Pages/ are excluded from the completion list

Test Plan

  • All 8 new tests pass (cargo test inertia_handler → 7 test fns covering the 8 AC behaviours, all green)
  • Full unit suite green (cargo test lib + bin: 1875 + 395 passed, 0 failed)
  • cargo fmt --check clean
  • cargo clippy --tests clean (CI gates on -D warnings)
  • Test-only change; no production code touched. The 8 integration_tests.rs failures seen locally are pre-existing and environmental — they require the gitignored test-project/ fixture (.env + composer vendor) that CI bootstraps (ci.yml lines 30-59); unaffected by this diff.

Fixes #207

mikebronner and others added 2 commits June 18, 2026 05:42
…etion

Drive the real LSP request handlers Backend::resolve_inertia_file (goto)
and Backend::get_all_inertia_pages (completion) through the tower_lsp
LspService harness, mirroring flux_goto_def_handler.rs. Prior Inertia
coverage stopped at the pure path-math seam (resolve_page_candidates,
list_pages) in inertia.rs and never exercised the request->handler->seam
wiring, so a regression in the handler arm (dropped containment guard,
inverted existence check, phantom or missing target) would slip through.

New tests/inertia_handler.rs covers, with real tempdir fixtures:
- goto: .vue happy path, nested .tsx, unresolvable -> None, and the
  .vue-wins extension priority when no dominant extension is primed
- completion: sorted extensionless listing, empty project, and the
  non-page-extension (.php/.blade.php) filter

The goto tests prime cached_config (root only); the completion tests
prime root_path -- matching exactly the state each handler reads.

Fixes #207

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mikebronner
mikebronner marked this pull request as ready for review June 18, 2026 12:48

@mr-sherlock-holmes mr-sherlock-holmes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Approved

Review Summary

  • Pure test-only PR (237 additions, 0 deletions): one new harness file inertia_handler.rs + a one-line tests/mod.rs wiring. No production code touched. CI green (LSP test/fmt/clippy pass).
  • All 9 acceptance criteria met — verified each behaviour against the real handler arms, not just the test text:
    • goto_backend primes cached_config — exactly what resolve_inertia_file reads (main.rs:18661 → get_cached_config().root); completion_backend primes root_path — exactly what get_all_inertia_pages reads (main.rs:12467 → list_pages). Each fixture primes the state its handler actually consumes. Honest harness.
    • .vue-wins priority confirmed against PAGE_EXTENSIONS = ["vue","tsx","jsx","svelte"] (inertia.rs:25); with root_path unset, inertia_dominant_extension returns None, so the static order decides — the test's "no dominant primed" premise genuinely holds.
    • Empty-project test drives the real list_pages walk on a real empty tempdir (not the None short-circuit) — meaningful coverage, not a trivial pass.
  • Built through LspService::new(LaravelLanguageServer::new), matching the flux_goto_def_handler.rs / blade_var_rename_handler.rs convention. No mocks.
  • For the record, two test-honesty observations were considered and judged non-actionable: the .blade.php fixture is excluded via the same ext=="php" branch as .php (redundant-but-correct, faithful to the AC), and the extension-priority test doesn't isolate the static-order path from the dominant tie-break (the AC scoped it to "no dominant primed," which the test honors exactly). Neither is a defect; forcing changes there would be gold-plating beyond the contract.

What's Good

  • Tests drive the real Backend handler arms (resolve_inertia_file / get_all_inertia_pages), a genuine step up from the already-covered pure path-math seam in inertia.rs — precisely what #207 asked for.
  • Each fixture primes exactly the state its handler reads, and the doc comments explain why (Salsa actor stays inert, document cache left empty so file_exists_cached falls through to live disk probes).
  • The unresolvable-page test seeds a real unrelated page first, so the None proves "missing target," not "empty/unconfigured project." Careful work.

📋 Non-blocking follow-ups

  • Handler-level coverage for the dominant-extension float branch (main.rs:18673-18679) — when a dominant extension is primed (inertia_default_ext = Some(Some("tsx"))), resolve_inertia_file floats that extension ahead of the static PAGE_EXTENSIONS order. This PR deliberately leaves the dominant unset (the AC scoped it that way), so that production branch has only seam-level coverage in inertia.rs, no handler-level test. A belt-and-suspenders add on #207's own theme. General observation about untouched production code, outside this PR's AC — tracked as a new follow-up issue, not a blocker.

Ready for @mikebronner to merge.

@mikebronner
mikebronner merged commit dbc29fb into main Jun 18, 2026
5 checks passed
@mikebronner
mikebronner deleted the chore/207-handler-level-lsp-harness-coverage-for-oncompletio branch June 18, 2026 13:15
mikebronner added a commit that referenced this pull request Jun 18, 2026
PR #210 established handler-harness coverage for the goto/completion arms
but deliberately left the dominant-extension *float* branch unreached: its
priority test ran with no dominant extension primed, so `.vue` won by the
static `PAGE_EXTENSIONS` order. The complementary arm — a primed dominant
extension floating a non-first candidate to the front (main.rs:18673–18679) —
had no handler-level test.

Add a `goto_backend_with_dominant` helper (same shape as `goto_backend` but
with the `inertia_default_ext` cache slot primed to `Some(Some(ext))`) and two
`#[tokio::test]`s on the real handler:

- `inertia_dominant_extension_floats_tsx_over_vue`: both `.vue` and `.tsx`
  exist, dominant `"tsx"` primed → `.tsx` wins (the float fires).
- `inertia_dominant_extension_absent_file_falls_back_to_static_priority`:
  dominant `"tsx"` primed but only `.vue` on disk → `.vue` resolves (the float
  reorders, the existence probe skips the absent dominant candidate).

Expands the existing `inertia_handler.rs` anchor per its module doc; no new
test module or file.

Fixes #212

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
mikebronner added a commit that referenced this pull request Jun 18, 2026
… branch (#216)

* chore: start work on #212

* test: 🧪 cover the Inertia dominant-extension float at handler level

PR #210 established handler-harness coverage for the goto/completion arms
but deliberately left the dominant-extension *float* branch unreached: its
priority test ran with no dominant extension primed, so `.vue` won by the
static `PAGE_EXTENSIONS` order. The complementary arm — a primed dominant
extension floating a non-first candidate to the front (main.rs:18673–18679) —
had no handler-level test.

Add a `goto_backend_with_dominant` helper (same shape as `goto_backend` but
with the `inertia_default_ext` cache slot primed to `Some(Some(ext))`) and two
`#[tokio::test]`s on the real handler:

- `inertia_dominant_extension_floats_tsx_over_vue`: both `.vue` and `.tsx`
  exist, dominant `"tsx"` primed → `.tsx` wins (the float fires).
- `inertia_dominant_extension_absent_file_falls_back_to_static_priority`:
  dominant `"tsx"` primed but only `.vue` on disk → `.vue` resolves (the float
  reorders, the existence probe skips the absent dominant candidate).

Expands the existing `inertia_handler.rs` anchor per its module doc; no new
test module or file.

Fixes #212

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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.

test: handler-level LSP harness coverage for on_completion / on_goto_definition

1 participant