# Write Playwright Tests for a React Router App

Yes. An agent adds Playwright specs for a React Router app's routes, runs them headless against the dev server, and opens a pull request.

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

## What the agent does

The agent starts inside the template package you care about, not the monorepo root alone. In remix-run/react-router-templates the default app lives under `default/`: `package.json` scripts are `dev` (`react-router dev`), `build`, `start` (`react-router-serve ./build/server/index.js`) and `typecheck`; dependencies use `react-router` and `@react-router/node` / `@react-router/serve` on React `19.2.x` with Vite `^8` and Tailwind `^4`. `default/app/routes.ts` registers a single index route pointing at `routes/home.tsx`, which renders `Welcome` from `welcome/welcome.tsx` (logo, "What's next?" links to the docs and Discord). `default/app/root.tsx` supplies `Layout`, `ErrorBoundary` and the font links. The stock home module has no `loader` or `action` export yet.

The repository's own smoke tests sit under `.tests/` (`playwright.config.ts` with `testMatch` `**/test.*.ts`, `test.default.ts` driving `pnpm dev` / `pnpm build` + `pnpm start` and asserting the title `New React Router App` plus the Docs and Discord links). Your application checkout usually has none of that under `e2e/`. The agent adds an app-local Playwright layout: `e2e/` specs, a `playwright.config.ts` whose `webServer` runs the package manager's `dev` script (pnpm in the templates workspace, npm or yarn when that is what the lockfile shows), and Chromium-only headless project settings.

Specs cover the real routes: home renders the welcome heading and resource links, unknown paths hit the `ErrorBoundary` (`404` message from `isRouteErrorResponse`), and when the app has grown a route `action` (a `<Form method="post">` posting to a resource route) the agent adds a case that fills the fields, submits, and asserts on the redirect or pending UI. If the stock template still has no `action`, the pull request says so and keeps the suite to routing, meta (`meta` export on home) and the error boundary instead of inventing a fake form in production code.

It installs `@playwright/test`, installs browsers, runs the suite headless against the config's webServer, and only then opens the pull request. Failures that expose a real defect are marked expected to fail with an explanation in the description, matching the prompt's instruction not to hide bugs.

## Start it with one API call

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

```json
{
  "agent": "claude",
  "input": "Write Playwright end-to-end tests for the default template's routes and its form action in this React Router app. Put them in e2e/ with a playwright.config that starts the dev server, run them headless, and open a pull request with the passing suite. If a test exposes a real bug, mark it expected to fail and explain it in the description.",
  "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

What comes back is a pull request on a new branch. It adds `e2e/` specs and `playwright.config.ts` (plus `@playwright/test` in the app `package.json` when it was missing). Route modules under `app/` stay unchanged unless the only way to assert a form action is a tiny fixture route the description calls out.

The description lists which routes were covered, whether a route `action` existed, the headless command that passed, and any `test.fail` cases with the defect they document. The trajectory keeps Playwright's output and the dev server logs.

Before merging, a reviewer checks that the webServer command matches the app's package manager, that the suite does not depend on the templates monorepo's `.tests/` harness, and that expected-to-fail cases are real bugs rather than flaky selectors. Once merged, the same config can run in CI on pull requests.

## Run it on every new React Router resource route

When a pull request adds a file under `app/routes/` (or a new entry in `routes.ts`), have your server send this request so Playwright coverage for that route lands before merge. Pass the branch name in the prompt so the run works on the pull request head.

Subscribe to `run.completed` on the API key webhook to post the pull request link back to the review thread. Keep concurrency at or below `max_concurrent`.

## Why run it on Rush?

React Router framework mode needs the Vite dev server (or `react-router-serve` after build) and a real browser for confidence in loaders, actions and the error boundary. Running that loop on a laptop blocks the same port you use for daily work. On Rush the agent owns the server in its sandbox, runs Chromium headless, and returns a pull request with a green suite.

The trajectory shows every failure the agent fixed, including bugs it refused to hide. You can point the same request at many RR apps and review each pull request on its own.

## Frequently asked questions

### The default template has no form action. What gets tested?

The agent says so in the pull request. It still covers the index route, welcome links, meta title and the root `ErrorBoundary` for unknown paths. When your app later adds a route `action`, the same job extends the suite to submit that form.

### Does it use the monorepo .tests/ harness?

Not for your app pull request. `.tests/test.default.ts` is how the templates repo smoke-tests packages; the agent adds an `e2e/` layout inside your application package so CI for that app stays self-contained.

### pnpm, npm or yarn?

Whatever the app lockfile shows. The templates workspace root has `pnpm-workspace.yaml` and `pnpm-lock.yaml`; a standalone app copied from `default/` may have its own lockfile after you create the project.

### What if a test finds a bug in the template?

It marks that case expected to fail and explains the defect in the pull request description instead of loosening the assertion. Production code stays unchanged unless you ask it to fix the bug in a separate request.
