FAQ

What is Hover, in one sentence?

Hover is an open-source Vibe Testing suite built around an MCP server (@hover-dev/mcp) you add to the coding agent you already run; the agent explores your app and crystallizes each flow into a plain @playwright/test spec you own, which runs in your CI with zero AI in the loop.

Do I need the VS Code extension?

No. The MCP is the whole authoring loop — add it to your agent and run /mcp__hover__test_app. The VS Code extension is an optional review cockpit (a Business Map graph + a Dashboard) that drives no agent.

How do I install it?

Install the MCP globally, then register the bin with your agent (Claude Code shown — any MCP-capable agent works):

npm i -g @hover-dev/mcp
claude mcp add hover -- hover-mcp

Prefer the global install — the npx -y @hover-dev/mcp one-liner re-downloads on first launch and can exceed your agent's 30s MCP connect timeout.

That brings both the grounded browser tools and the /mcp__hover__test_app command. There's no plugin in your project, no bundler-config edit, and no keys of Hover's own.

What does "record == replay" mean?

The agent acts through Hover's grounded browser tools (click_control / fill_control / …), which target a control by role+name → testId → text read off the page snapshot. The selector that drove the action is the exact one Hover saves, and crystallization is deterministic (no LLM writes the code). So what you replay is what you recorded — no confabulated selectors. Playwright codegen, Stagehand, and Midscene can't guarantee this.

My UI changed and my saved spec breaks. What now?

This is the central question for any AI-authored e2e test. Hover's answer is three-layered.

1. Most UI churn doesn't break the spec

Hover generates getByRole / getByLabel / getByTestId semantic selectors — never CSS classes or XPath. "Submit button" stays "Submit button" after a layout pass; the spec keeps running. The choice is enforced in packages/core/src/specs/writeSpec.ts, and grounded actuation makes it more than a hope — the grounded target is the selector.

2. When the semantics shift — button renamed, label changed, role swapped — the spec turns red

You have two local options:

  • Edit by hand. The spec is plain @playwright/testgetByRole('button', { name: 'Submit' })'Sign in'. Fast if you know exactly what changed, and the file is yours to own.
  • Re-crystallize. Re-run /mcp__hover__test_app <flow> and let the agent re-author the flow against the current UI.
  • Treat it as a regression. If the test fails because the flow broke (not just the selector), that's the test catching a real bug — fix the app, not the spec.

Automatic, on-failure healing — replaying a spec's intent against the current UI and proposing a diff — is planned as part of Hover Cloud, not a local feature. Locally, CI stays deterministic and free.

3. Why we don't auto-heal at CI time

The Stagehand / Midscene model: tests "self-heal" by calling an LLM mid-run, retrying with new selectors until they pass. It works, but it builds a permanent runtime dependency on a hosted AI provider — every CI run pays an LLM call, every PR, every nightly. Across a year of CI cycles that's measurable money and a fragility surface (rate limits, regional outages, model deprecations).

Hover takes the opposite position: AI is for authoring tests, not running them. The saved .spec.ts is plain Playwright — npx playwright test __vibe_tests__ is deterministic and free. The token cost concentrates at the moment you actually need a model, not amortised across thousands of regression runs.

My button is still in the DOM but moved behind a kebab menu — does the spec catch that?

Yes — and the how is more nuanced than "we added a check." Playwright's .click() / .fill() / .hover() / .selectOption() / .dblclick() all auto-wait on actionability, which includes visibility — so even a bare .click() wouldn't silently fire on a hidden element. It would time out after 30 seconds with a generic actionability error that reads like a flake.

The visibility prelude Hover emits is a fast, semantically-clearer failure rather than net-new detection:

// Hover emits this:
{
  const el = page.getByRole('button', { name: 'Submit' });
  await expect(el).toBeVisible();
  await el.click();
}

When the button drifts into a closed <details> / kebab / drawer, the toBeVisible() line fails in ~3 s with Locator expected to be visible — a category triage engineers immediately recognise as a UI regression rather than dismiss as a network blip. The same drift on a bare .click() would stall for 30 s and produce a Timeout 30000ms exceeded ... element is not visible error that's easy to mis-classify as flake.

The change applies to click / dblclick / hover / fill / selectOption. page.goto is page-level (no element) and stays a one-liner.

What this still doesn't fix:

  • disabled buttons — Playwright auto-waits for actionability there too, so a click on a disabled control still times out at 30 s with a generic message. (Tighten by hand with await expect(el).toBeEnabled() where it matters.)
  • An intermediate step quietly disappearing from the flow — each step still passes individually; re-running the original prompt against the current UI catches this, which is the kind of intent-level repair planned for Hover Cloud.

Will Hover spawn another headless Chromium? My CI is already busy.

No. Hover's engine launches one isolated debug Chrome under <tmpdir>/hover-chrome and connects via CDP, only while you're authoring. It never spawns a fresh Chromium per command, and it doesn't touch your CI's Playwright browsers — those are configured entirely in playwright.config.ts and unrelated to Hover's debug Chrome. In CI there's no Hover at all; you run plain npx playwright test.

Does Hover send my source code or DOM to a hosted service?

No. Hover bundles no model and holds no keys (BYO-CLI). Your coding agent talks to its own provider (Anthropic, OpenAI, Google, or a self-hosted endpoint); @hover-dev/mcp and @hover-dev/core have no LLM SDK code, no telemetry, and no upload path. The engine binds to 127.0.0.1 only.

Does Hover inject anything into my app's build output?

No. Hover drives your app over CDP in an isolated debug Chrome — there's no plugin, no bundler-config edit, no widget in the page. Your app's bundle is unchanged, in dev or in a production build.

What lives in .hover/, and should I commit it?

.hover/ is your app's test knowledge: a Business Map (hover-map.md), remembered business rules (memory/), per-spec sidecars (sidecars/), and disposable working data (cache/). The intended policy in your project is to ignore cache/ and commit the rest — it's plain Markdown and JSON that versions alongside the code it describes.

Can I run Hover in CI to author new tests automatically?

You can wire your agent + the MCP into a CI job, but it's an anti-pattern most of the time. Hover is built around the assumption that a human reviews each generated spec before committing it. Automated authoring without review tends to produce specs that pass once and then accumulate selector debt no one notices until they break.

The supported workflow is: a human runs Hover during development, reviews the crystallized specs, commits them. CI just runs Playwright.