# Add Missing Tests to Every Pull Request in a Next.js App

Yes. An agent reads each pull request to your Next.js app, writes Vitest tests for the posts editor and API routes it changes and pushes them back.

[Run this on Rush](https://cloud.getrush.ai/run/test-every-pull-request/nextjs/), in a Project that has your repository.

## What the agent does

The agent reads the pull request's diff and finds the route handlers and components it changes. In a Next.js app-router app like shadcn-ui/taxonomy the posts API is `app/api/posts/route.ts` (`GET` lists the signed-in user's posts, `POST` creates one) and `app/api/posts/[postId]/route.ts` (`PATCH` and `DELETE`), each checking the session with `getServerSession(authOptions)` and validating input with zod. The editor is `components/editor.tsx`, which posts its form to `/api/posts/${post.id}`, with its schema in `lib/validations/post.ts`. It notes rules the diff adds or changes, such as the free-plan limit in `POST`, where a user who is not on a pro plan gets `402 Requires Pro Plan` after three posts.

Then it finds that taxonomy has no tests and no test runner at all: `package.json` has `dev`, `build`, `lint` and `preview` scripts, no `test`, and no Vitest or Jest in `devDependencies`. So the first run on a repository like this adds the smallest setup that runs: `vitest` as a dev dependency installed with pnpm (the repository has `pnpm-lock.yaml` at `lockfileVersion: '6.0'`), a `vitest.config.ts` that maps the `@/` import alias from `tsconfig.json`'s `paths`, and a `test` script of `vitest run`. It says in its comment that it added these and why, because a reviewer should decide whether to keep a new tool.

The route tests import the handlers directly and call them with a `Request` and a `{ params: { postId } }` context, the shape `routeContextSchema` parses. The handlers read a session, a Prisma client from `lib/db.ts` and a subscription plan from `lib/subscription.ts`, and `env.mjs` validates more than a dozen server variables with `@t3-oss/env-nextjs` at import, so the agent substitutes those modules at the test boundary with `vi.mock` and sets test values for the environment. Each test then checks one rule a client depends on: `403` with no session, `422` with the zod issues for a title shorter than 3 characters, `402` on the fourth post on the free plan, `204` after a delete by the owner.

It runs `npx vitest run` until the new tests pass, and `pnpm lint` so the new files meet the existing `next lint` setup. A test that fails because the handler is wrong stays out of the commit, since the prompt forbids application changes, and the agent describes the failing request and response in its comment.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "claude",
  "input": "This pull request changes the posts editor and API routes. Read the diff against the base branch and list the new or changed behavior in app/api/posts, components/editor.tsx and lib/validations/post.ts that no existing test covers. If the repository has no test runner, add Vitest with pnpm, a vitest.config.ts that maps the @/ alias from tsconfig.json and a test script, and say so in your comment. Write Vitest tests next to the code they cover: call the route handlers with a Request and route params, replace the session, the Prisma client and the subscription lookup with vi.mock at the module boundary, and set test values for env.mjs. Run npx vitest run until the new tests pass. Do not change application code: if a test fails because the code is wrong, leave it out and describe the failure. Push the tests to this pull request's branch and post a comment listing each test and the behavior it covers.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app/pull/123"
    }
  ]
}
```

1. **Get an API key.** In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
2. **Send the request.** POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
3. **Read what came back.** Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

## What comes back

What comes back is a commit on the pull request's branch. On a repository with no test setup, like taxonomy, it adds `vitest.config.ts`, a `test` script and the `vitest` entry in `package.json` and `pnpm-lock.yaml`, plus test files such as `app/api/posts/route.test.ts` and `app/api/posts/[postId]/route.test.ts`, and a test for `postPatchSchema` when the pull request changed it. On a repository that already has Vitest, the commit is only the new test files. Application files are not touched.

The agent's comment on the pull request lists each test with the status code or rule it checks, names any setup it added, and gives the command it ran. If a test found a defect, for example a `PATCH` that lets a user edit a post they do not own, the comment shows the request, the response and the line in the route handler. Once the `test` script exists, add it to your CI so later pull requests run these tests as a check.

Before merging, a reviewer checks that the mocked modules stand in only for the session, the database and Stripe, so each test still exercises the real handler and the real zod schema, and that the test environment values in the setup are placeholders, never real keys.

## Run it on every pull request opened

Create an automation on the Project bound to your Next.js repository with this prompt and a GitHub trigger on `pull_request.opened`. Each pull request opened by someone with write access starts its own run, and the run's prompt carries its number, URL, title, author and base branch. After the first run adds Vitest, the same prompt finds the runner already there and only adds tests. Pull requests from forks never fire the trigger.

To start runs from your own code, handle GitHub's `pull_request` webhook and, on `opened`, send this request with the pull request's URL in `resources`, which clones its branch. Send the delivery id as `Idempotency-Key` so a redelivery returns the run it already started.

## Why run it on Rush?

Adding tests to a Next.js app that has none is a setup problem before it is a writing problem: the alias, the environment validation at import and the server-only modules all have to be handled before the first test runs. On Rush the agent works that out in its own sandbox, installing with pnpm and running Vitest at the pull request's branch, while your dev server and your `.env` stay untouched on your machine.

The run hands back proof rather than a claim. Its trajectory keeps every install and `vitest run` with its output, including the first failing attempts, and the comment says which setup was added and why. Since each pull request gets its own run, a week of pull requests leaves the app with tests for each change instead of a single large backfill nobody reviews.

## Frequently asked questions

### Why Vitest and not Jest?

The prompt asks for Vitest because it reads TypeScript and the `@/` alias with one small config and no Babel setup. If your repository already uses Jest, change the prompt to Jest and the agent writes tests for the setup you have instead of adding a second runner.

### Does it test React components like the editor?

When the pull request changes component logic, yes, with a DOM environment such as `jsdom` and Testing Library added alongside Vitest. For taxonomy's editor, most of the behavior worth pinning sits in the API route and the zod schema it posts to, so those get tests first.

### Does it need my database or Stripe account?

No. The tests replace the Prisma client, the session and the subscription lookup at the module boundary and set placeholder values for the variables `env.mjs` requires. Nothing connects to your database, NextAuth provider or Stripe.

### Will it add the test step to my CI?

Not unless you ask, because the prompt limits it to test files and the runner they need. The comment suggests adding `pnpm test` to your workflow so the tests run on every later pull request.
