Structured spec output

A Hover spec isn't a flat dump of clicks. The deterministic translator shapes a verified session into a small architecture — readable on its own, and ready to grow as you save more flows.

What the translator emits

  • test.step(...) stages. Each logical step (open the form, fill credentials, verify the result) is wrapped in a named test.step, so the Playwright HTML report reads as stages instead of a flat action list.
  • Visibility-guarded interactions. Every action is wrapped so it asserts the element is visible first — UI drift fails in ~3 s with a named assertion instead of a 30 s actionability timeout.
  • Popup / new-tab pairing. A click that opens a payment popup or OAuth tab crystallises with the Promise.all([context.waitForEvent('page'), …]) pairing Playwright needs, and the subsequent steps are retargeted onto the new page — no race on replay.
  • A structured sidecar. Alongside <slug>.spec.ts, Hover writes .hover/<slug>.json — the structured SpecStep[] plus the signals the run observed. It's the machine-readable record the optimization pass reads, and it keeps the spec file itself clean.

Page Objects from repeated flows

When the same prefix (a login, a setup wizard) recurs across several saved specs, Hover can lift it into a shared Page Object plus a Playwright fixture, so the selectors live in one file instead of five. New specs consume the fixture and call the method (await loginPage.login(...)) instead of repeating the steps inline.

__vibe_tests__/
├── pages/LoginPage.ts      # the lifted Page Object
├── fixtures.ts             # exposes it as a fixture
└── login-and-checkout.spec.ts

Run it over your existing specs with npx hover extract.

Still plain Playwright

Everything here is standard @playwright/test — Page Objects, fixtures, and test.step are Playwright's own primitives. The spec runs in CI with npx playwright test, no agent and no Hover runtime in the loop.