# Write Vitest Tests for a Vite React App

Yes. An agent finds the least-tested features in your Vite React app and writes Vitest and Testing Library tests for their loading, error and empty states.

[Run this on Rush](https://cloud.getrush.ai/run/write-vitest-tests/vite-react/), in a Project that has your repository.

## What the agent does

The agent first measures where the tests are, instead of starting with whichever file it opens first. In a Vite React app like the `apps/react-vite` workspace of alan2207/bulletproof-react it reads `package.json` and finds Vitest 2, `@testing-library/react` 15, `@testing-library/user-event` 14, MSW 2 with `@mswjs/data`, `yarn.lock`, and a `test` script that is plain `vitest`. `vite.config.ts` sets `globals: true`, the `jsdom` environment and `src/testing/setup-tests.ts`, which starts the MSW server with `onUnhandledRequest: 'error'`, mocks `zustand` through `__mocks__/zustand.ts`, and seeds and resets the in-memory database around each test. Listing the 12 `__tests__` files against `src/features`, it finds that `auth` has tests for its login and register forms and `discussions` is covered through the route tests in `src/app/routes/app/discussions/__tests__`, while `comments`, `users` and `teams` have none.

So those three are the target, `comments` and `users` first because they have components. In `features/comments/components/comments-list.tsx` the agent finds a `Spinner` while `useInfiniteComments` is loading, a `No Comments Found` heading for an empty list, a `Load More Comments` button shown only when `hasNextPage` is true, and a delete button wrapped in `<Authorization>` with the `comment:delete` policy from `src/lib/authorization.tsx`, which allows an `ADMIN` or the comment's own author. The MSW handler in `src/testing/mocks/handlers/comments.ts` pages comments ten at a time, so a test that seeds eleven comments reaches the second page through the real query and the real handler. In `features/users` it finds `users-list.tsx` with its own loading `Spinner`, `delete-user.tsx` with a confirmation and a pending state, and `update-profile.tsx`, a form that `PATCH`es `/users/profile`; the `/app/users` route is only rendered for `ROLES.ADMIN`.

It writes tests beside the components, in `features/comments/components/__tests__/` and `features/users/components/__tests__/`, using the repository's own helpers in `src/testing/test-utils.tsx`: `createUser`, `createDiscussion`, `loginAsUser`, `renderApp` and `waitForLoadingToFinish`. Each component is tested for its loading state, its empty state, its populated state, and its error state, which the test produces by overriding one handler with `server.use(...)` to answer `500`, then checking that the error notification `src/lib/api-client.ts` adds through `useNotifications` appears. Permission cases render the same list as an admin, as the author and as another user, and check whether the delete button is there.

`yarn test` starts Vitest in watch mode, so the agent runs `yarn test --run` to get one pass that exits, then `yarn check-types` and `yarn lint`, because the ESLint config includes `eslint-plugin-testing-library` and `eslint-plugin-vitest` rules that the new files must follow.

## Start it with one API call

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

```json
{
  "agent": "claude",
  "input": "In apps/react-vite, find the feature modules with the fewest tests and write Vitest and React Testing Library tests for their components and hooks, covering loading, error and empty states. List each feature with its existing test files before writing anything. Use the repository's own test utilities, data generators and MSW handlers; produce error states by overriding a handler for one test, not by mocking the feature's hooks. Cover permission-dependent UI for each role the authorization policies name. Put the tests in __tests__ folders beside the components, like the existing ones. Run yarn test --run, yarn check-types and yarn lint, and fix what they report in the new files. Do not change application code. Open a pull request with the before and after list of tested components.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
```

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

The pull request adds test files only, for a codebase shaped like bulletproof-react under `src/features/comments/components/__tests__/` and `src/features/users/components/__tests__/`, with tests for `comments-list`, `create-comment`, `delete-comment`, `users-list`, `delete-user` and `update-profile`. The description opens with the list of features and the test files each had before and has after, and says why `teams` is left with no component tests: it has only the `get-teams` API module, whose one caller is the register route in `src/app/routes/auth/register.tsx`.

The evidence is the run output. The session keeps the agent's `yarn test --run`, `yarn check-types` and `yarn lint` from its own sandbox in full, so the reviewer sees every test name pass with no unhandled MSW request, which the setup file turns into an error. If the repository's CI runs Vitest, its check on the pull request runs the same suite.

A reviewer checks that the tests query by role and label rather than by class name or test id where the component offers one, that each error-state override is reset by the `server.resetHandlers()` call in the setup file, and that the permission cases match how the team wants the policies to behave rather than only how they behave today.

## Run it on every new feature folder

Bulletproof React's layout puts each feature in its own folder under `src/features`, which makes new untested code easy to spot. Have a GitHub `pull_request` webhook send this request when a pull request adds files under `src/features/` and none under a `__tests__` folder, with the pull request URL in `resources`, so the agent writes the tests on that branch in its own session and sandbox.

With a webhook URL on the API key, Rush POSTs `run.completed` or `run.failed` when the turn finishes, with the session URL; your server can then comment on the feature pull request with a link to the tests.

## Why run it on Rush?

Writing tests for six components means running Vitest over and over while each one goes from failing to passing, alongside the type check and the linter, and doing that on your laptop ties up the working tree you were building the feature in. On Rush the agent installs with Yarn in its own sandbox, runs the suite there as often as it needs, and nothing on your machine changes until you pull the branch.

The tests come with the output that proves them: every `vitest` pass the agent ran is kept in the session, so a reviewer can see the error-state tests pass for the right reason and not because a request went unhandled. And because the request names states to cover rather than files, the same request works on any Vite React app, and can run on several of them at once, each in its own sandbox.

## Frequently asked questions

### How does it decide which features need tests most?

It lists each feature folder with the test files that exercise it, including route-level tests elsewhere in `src/app`, and starts with the folders that have components and no tests. The pull request shows that list, so you can see why `comments` and `users` came before `discussions`.

### Will it mock my hooks or API calls?

It mocks the network at the same place your existing tests do. In bulletproof-react that is MSW, with the handlers in `src/testing/mocks/handlers`, so components run their real React Query hooks and axios client against those handlers. An error state comes from overriding one handler for one test, not from replacing the hook.

### Does it need my backend running?

No. The tests run in jsdom against the MSW handlers and the `@mswjs/data` database the setup file seeds and resets for each test, so there is no server to start and no network call leaves the sandbox.

### What about Playwright end-to-end tests?

This job writes component and hook tests only. The app's `e2e` folder and `test-e2e` script, which starts the mock server with pm2 and then Playwright, are left alone. Ask for end-to-end coverage in the prompt and the agent runs that script in its sandbox instead.
