How to Test Apps Built with v0, Lovable, and Bolt
Shiplight AI Team
Updated on July 15, 2026
Shiplight AI Team
Updated on July 15, 2026

Testing an app built by an AI app builder means verifying that the generated flows actually behave the way the preview implies, and that they keep behaving after the next regeneration. The tools that produce these apps optimize for one thing: getting a working-looking interface in front of you fast. What they do not do is prove that signup writes a row, that checkout charges once, or that the change you prompted this morning did not quietly break the flow you shipped yesterday. That verification gap is the same one every AI-generated codebase carries, and it is the part you own the moment the code lands in a repository you control.
This guide is organized around four questions: why app-builder output ships unverified, when and where to add verification, the workflow that turns generated code into an app with maintained end-to-end tests, and the limits you hit while some of the code still lives inside a builder's sandbox. The specifics differ across tools, but the shape of the problem does not. A generated preview is a demo, not a guarantee.
An AI app builder turns a prompt into a running application. v0 by Vercel generates Next.js, React, Tailwind CSS, and shadcn/ui components that render immediately in a live preview (v0 docs). Lovable produces React with a Supabase backend and a deployed URL. Bolt.new, built by StackBlitz, boots a full Node.js runtime inside your browser tab using WebContainers and lets the model drive the filesystem, package manager, and dev server directly (StackBlitz WebContainers). Replit's Agent scaffolds, runs, and deploys across many languages from a single chat.
Each produces something you can click within minutes. That speed is the point, and it is genuinely useful. But the loop inside a builder rewards output that looks right, not output that is proven right. The model generates code, the preview renders, and you move to the next prompt. Nothing in that loop asserts that the form submission reached the database, that the auth boundary blocks an unauthenticated request, or that the payment path handles a declined card. The preview shows the happy path because the happy path is what got prompted.
Three properties make this failure mode predictable:
For the broader version of this problem across all AI-written code, see how to test vibe-coded applications, which covers the reliability techniques that apply regardless of which tool produced the code.
The right place to add real verification is the moment you own the code, which in practice means the moment it lands in your Git repository. Every one of these builders supports that handoff, and it is the natural seam to bolt testing onto.
Once the code is in a repo, you have a filesystem, a package manager, and a CI surface, which is everything a real test suite needs. Verifying flows while the app lives only inside the builder's chat is fighting the tool; verifying them once you own the repo works with it.
The timing question has a clean answer: add verification before the app has real users, and re-run it on every change after that. A generated app taking payments cannot tolerate a single unverified regeneration. If you are gating a launch, the pre-launch testing workflow for vibe-coded apps turns this into a concrete checklist.
Once the code is in your repository and connected to your coding agent, verification becomes part of the build loop rather than a separate phase. This is where Shiplight fits: it is the verification layer for AI-native development, plugging into your coding agent, giving it a real browser to drive, and having the agent author end-to-end tests that live in your repo and heal themselves as the app changes. It installs as an MCP server plus Skills with a one-line setup for Claude Code, Cursor, Codex, VS Code, and 40-plus agents. The workflow has three moves.
Verify the flow right after it generates. When your agent brings v0 or Lovable output into the repo and wires it up, run /shiplight verify. The agent opens the app in a real browser, walks the flow you care about, and confirms the rendered result matches intent rather than trusting the preview. This catches the gap between "the signup page renders" and "a user can actually sign up" at the moment the code arrives.
Author tests from intent, not selectors. Run /shiplight create-yaml-tests and the agent walks the app and writes end-to-end tests in readable YAML, described by what the user is trying to do instead of brittle CSS selectors. That distinction matters more here than almost anywhere else, because app-builder output is refactored on every prompt. A test bound to .btn-primary breaks the next time you ask the builder to restyle a button; a test that says "a new user signs up with email and password" survives the refactor. See verify AI-written UI changes for how intent-based verification holds up under constant UI churn.
Maintain the suite as the app regenerates. The tests live as YAML in your Git repo, not a vendor cloud, and run locally with npx shiplight test. They are Playwright-compatible and run alongside any Playwright tests you already have. When a regeneration moves an element, Shiplight heals the test in a real browser and surfaces the change as a reviewable PR diff, not a silent rewrite. When the app itself is broken rather than just changed, /shiplight fix reproduces the failure, root-causes it, and reports the bug instead of quietly editing the test to pass. Run the suite as a gate on every pull request and the regression question ("did this generation break a flow I already shipped?") gets answered before merge instead of after a user finds it.
The first suite of end-to-end tests exists within the first week of owning the code, and it keeps working as the builder keeps generating. One team's Head of QA went from spending roughly 60 percent of their time maintaining Playwright tests to near zero within a month by moving to this model. The vibe coding testing guide covers how to add this QA layer without slowing the build loop down.
This workflow starts when you own the code, and not all app-builder code is fully yours at every moment. Bolt.new runs inside WebContainers in the browser tab, so until you push to GitHub the app lives in a sandbox you cannot point external tooling at (StackBlitz WebContainers). Lovable's two-way sync is on paid plans; the free tier gives you a ZIP rather than a live connection (Lovable GitHub docs). And a test suite in your repo verifies the code you exported, not necessarily whatever a builder is serving from its own hosting.
Treat the in-builder phase as prototyping and the in-repo phase as production. Iterate freely inside the tool while shaping the idea. The moment the app matters enough to have users, export it, connect your coding agent, and put a real verification gate around it. Every one of these builders ships a path to your own repository, and that path is where verification becomes possible and where it should become mandatory.
Export the generated code to your own Git repository, which all three support, then connect your coding agent and add end-to-end verification. Run a verification pass to confirm the key flows behave as the preview implied, have the agent author intent-based tests in your repo, and run those tests as a gate on every change. The builders confirm that a UI renders; the test suite confirms that signup, login, and checkout actually work and keep working after the next generation.
The preview shows the happy path because that is what was prompted. It does not verify that a form submission reached the database, that an auth boundary blocks unauthenticated access, or that a payment path handles a declined card. Generated backends and the seams between generated modules are where these apps break, and none of that is exercised by a rendering preview.
When the code lands in your Git repository and before the app has real users. A prototype with no users can stay unverified briefly, but a generated app taking payments cannot tolerate a single unverified regeneration. Add verification at the repo handoff, then run it on every change.
Only partially. Tools like Bolt.new run inside browser-based WebContainers, and some builders serve previews from their own hosting, so external test tooling cannot reach the app until you export it. Treat the in-builder phase as prototyping and add real verification once the code is in a repository you control.
Not if they are written from intent rather than bound to CSS selectors. App builders rename elements and refactor component boundaries on nearly every prompt, so selector-bound tests break constantly. Intent-based tests that describe what the user is trying to do survive those refactors, and a self-healing runner surfaces genuine changes as reviewable PR diffs. Shiplight authors and maintains tests in exactly this shape.