Skip to content
← Back to the blog
software developmentapps

How to add tests to AI-generated code

Which tests to add first to an AI-built app, how to set up Playwright and Vitest, how to get the agent to write useful tests and run them on every change.

By Devonauts Team5 min read
Leer en español →
A smartphone lies next to a laptop whose screen shows lines of code

To stop the next prompt from breaking an AI-built app, start with three to five end-to-end tests for the flows that matter most (sign up, log in, the main action, payment), then add small unit tests for the logic that keeps breaking. Run them before every change is accepted, and tell the agent in its instruction file that a task isn't done until the tests pass. For a typical React, Vite or Next.js app, Playwright covers the browser flows and Vitest covers the logic.

This guide explains why AI changes cause regressions, which tests give the most protection for the least effort, how to set them up, how to get the agent to write tests worth having, and how to make them run automatically.

Why does the next prompt keep breaking things that worked?

The agent only knows what "working" means for the task in front of it. When you ask it to change the pricing page, nothing tells it that the checkout it touched along the way used to work. A person on your team would remember; the agent starts each session with no memory of what you tested by hand last week.

Tests are that memory, written down. They don't make the agent smarter; they make it obvious, within a minute, that something it changed broke something else.

Which tests should I add first?

Add the cheapest tests that cover the most expensive failures.

TypeWhat it catchesToolHow many to start
End-to-end smoke testsA key flow broke: can't sign up, log in, save, payPlaywright3 to 5
Unit testsWrong results from logic: totals, discounts, dates, permission checksVitestOne file per piece of fragile logic
Database access testsOne user can read another user's rowsSQL tests, or an end-to-end test with two accounts1 or 2 for your most sensitive table

Skip snapshot tests of whole pages and tests for simple display components at first. They break often for harmless reasons and teach everyone to ignore failures.

How do I set up Playwright for the main flows?

  1. In the project folder, run npm init playwright@latest and accept the defaults. It creates a config file and an example test.
  2. Start your app (npm run dev) and record a flow with npx playwright codegen http://localhost:5173. Click through sign-in as a user would; Playwright writes the steps for you.
  3. Clean the recording into a test that checks a result, not just clicks:
import { test, expect } from '@playwright/test';

test('a user can sign in and reach the dashboard', async ({ page }) => {
  await page.goto('http://localhost:5173/login');
  await page.getByLabel('Email').fill(process.env.TEST_USER_EMAIL!);
  await page.getByLabel('Password').fill(process.env.TEST_USER_PASSWORD!);
  await page.getByRole('button', { name: 'Sign in' }).click();
  await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
});
  1. Run it with npx playwright test.

Adjust the labels and the URL to your app. Use a dedicated test account in a test database, never a real customer's login. The Playwright getting started guide covers browsers, configuration and running in CI.

How do I add unit tests with Vitest?

Unit tests suit pure logic: a function that takes inputs and returns a result. Install with npm install -D vitest and add "test": "vitest run" to the scripts in package.json. Then write a test next to the code:

import { describe, it, expect } from 'vitest';
import { invoiceTotal } from './invoiceTotal';

describe('invoiceTotal', () => {
  it('applies the discount before tax', () => {
    expect(invoiceTotal({ subtotal: 100, discount: 10, taxRate: 0.2 })).toBe(108);
  });

  it('never goes below zero', () => {
    expect(invoiceTotal({ subtotal: 20, discount: 50, taxRate: 0.2 })).toBe(0);
  });
});

If the logic you care about is buried inside a big component, ask the agent to move it into its own function first, with no behavior change, and test that.

How do I get the AI to write tests that are worth having?

Agents write tests quickly, but not always good ones. A few instructions make a big difference.

  1. Pin current behavior before changing anything. "Write tests that describe how invoiceTotal behaves today. Don't change the function." These are your safety net for the change that follows.
  2. Ask for the failure case. "Include a test with an expired coupon and one with a negative quantity."
  3. Check that the test can fail. Temporarily break the code, for example change + to -, and confirm the test goes red. A test that passes no matter what protects nothing.
  4. Forbid editing tests to make them pass. Add to your rules: "Never change or delete an existing test to make it pass. If a test seems wrong, stop and tell me." Watch diffs for .skip, loosened assertions or deleted test files.
  5. Read the assertions. A test that only checks "the page loaded" won't catch a wrong total.

How do I make the tests run every time?

Tests that only run when someone remembers don't stop regressions. Three layers:

  • In the agent's instructions. "Before you say a task is done, run npm test and npx playwright test and report the result." See writing Cursor rules for a real project.
  • Before you merge. Run them yourself on the branch. Don't take the agent's word that they passed.
  • On every push. A small GitHub Actions workflow in .github/workflows/tests.yml:
name: tests
on: [push, pull_request]
jobs:
  unit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: 24
      - run: npm ci
      - run: npm test

Start with unit tests in CI; add Playwright once the test account and database are set up for it.

Quick answers

How many tests do I need before it helps? Three good end-to-end tests on your main flows already catch most "the last prompt broke login" problems.

Will tests slow down building with AI? A little per change, and a lot less than debugging a broken checkout after launch.

Can I add tests to an app built in Lovable or Bolt? Yes, once the code is in GitHub. The tests live in the repository and run against the app like any other.

What if the existing code is too tangled to test? Start with end-to-end tests, which don't care how the code is organized. They give you the safety net to clean up the inside later.

Want help putting a safety net in place?

If Bolt breaks the app with every change or your Cursor project keeps regressing, tests are usually the first fix. Pair them with a review routine for AI-generated code. If you'd like someone to set up the first tests with you, see our Cursor project help or ongoing maintenance and support, or get in touch.

Still stuck with your app?

Run the free health check on your app's URL, or get the $299 App Rescue Audit: a senior engineer reviews the code and sends you a written report in 2 business days.