# Write Playwright Tests for a Vue App

Yes. An agent writes Playwright specs for your Vue app's main flows, runs them headless against the Vite dev server in its sandbox, and opens a pull request.

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

## What the agent does

The agent starts from the test wiring the repository already has. In realworld-apps/vue-realworld-example-app, `package.json` has Vue 3.5, Pinia 3, `vue-router` 5, Vite 8 and `@playwright/test` ^1.60, uses Bun (`bun.lock`), and its `test` script is `playwright test`. But `playwright.config.ts` sets `testDir: './realworld/specs/e2e'` and imports `baseConfig` from the `realworld` git submodule, so the only specs are a shared suite that a clone without `git submodule update` does not have. Nothing in the repository tests this app's own Pinia stores or components in a browser.

It also reads the server settings before writing the config, because they decide whether the first run even connects. `vite.config.js` binds `127.0.0.1:8080` with `strictPort: true`, and its comment explains why: under Bun, `localhost` can resolve to `::1` while the readiness probe uses IPv4. The existing config's `webServer.url` is `http://127.0.0.1:8080` but `use.baseURL` is `http://localhost:8080`. The agent's new `e2e/` config uses `127.0.0.1` in both, runs `bun run serve` as the web server, and points `testDir` at `./e2e`.

The specs follow the app's routes in `src/router/index.js` and its stores. Sign-in fills `Email` and `Password` on `/login`, checks the header shows the username, and checks the token lands in `localStorage` under `jwtToken`, the key `src/common/jwt.service.js` uses. The feed spec checks the Global Feed loads articles, that `Your Feed` (`/?feed=following`) only appears when signed in and shows the empty-feed message for a new user, and that a tag link filters the list. The favoriting spec favorites an article from the home list and from the article page, checks the counter goes up by one in both places (the `updateArticleInList` path in `src/store/home.js`), and checks a signed-out click goes to `/login`, as `ArticleMeta.vue` does.

The API base is `VITE_API_URL` or `https://api.realworld.show/api` (`src/common/config.js`), a public backend shared with other users, so each run registers its own users. The agent runs the suite headless several times, including a fast double click on the favorite button, and any test that fails because of the app stays in the suite as `test.fail()` with its cause.

## 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 sign-in, the article feed and favoriting in this Vue 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-vue-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 that adds `e2e/auth.spec.ts`, `e2e/feed.spec.ts` and `e2e/favorite.spec.ts`, a fixture that registers a unique user and stores its signed-in state, and a `playwright.config.ts` with `testDir: './e2e'`, `bun run serve` as its web server and `127.0.0.1:8080` as both its URL and `baseURL`. `src/` is untouched.

The description lists each spec and the store or component it exercises, explains the `localhost` to `127.0.0.1` change, and names every test marked `test.fail()` with the file behind it. The session's trajectory keeps every `npx playwright test` run with its output, so a reviewer can see the suite passing on more than one run.

Before merging, a reviewer decides whether to keep the submodule's shared suite as a second Playwright project, whether the specs should set `VITE_API_URL` to a backend the team controls, and which expected failures to fix. Adding the suite to CI is a follow-up on the same session.

## Run it on every Vite or Vue major upgrade

When a dependency bot opens a pull request that moves Vite, Vue, Pinia or `vue-router` to a new major, a GitHub webhook can send this request with that pull request in `resources`, asking the agent to run the e2e suite and fix what broke. Router and store upgrades are what change sign-in redirects and list updates, which are exactly what these specs check.

Set a webhook URL on the API key and Rush POSTs `run.completed` or `run.failed` when the turn finishes, with the session URL, so the upgrade pull request gets a comment before anyone merges it.

## Why run it on Rush?

End-to-end tests for a Vue app need a dev server on a fixed port, a browser, and a backend, and small things like `localhost` resolving to IPv6 under Bun break the first run on some machines and not others. In its own sandbox the agent starts the server, installs Chromium and runs the suite from a clean environment, so the config it hands back is one that worked from nothing.

Every command and its output is in the trajectory, so the pull request carries its own proof. Because runs are isolated, the same request can add end-to-end tests to each of your Vue front ends at once, and `strictPort` on 8080 never conflicts between them.

## Frequently asked questions

### Will it replace the shared RealWorld spec suite?

It points the default config at the app's own `e2e/` specs so the suite runs without the submodule, and says so in the description. If you want both, ask for two Playwright projects, one per test directory, and the agent keeps the shared suite as the second.

### Can it test against my own API instead of the public one?

Yes. The app reads `VITE_API_URL`, so name your backend's URL or the command that starts it locally in the prompt. The agent sets it for the web server and the specs then create their users there.

### Does it work with npm or pnpm instead of Bun?

It uses whatever the lockfile says. This repository has `bun.lock` and serves with `bun run serve`, so the config uses that. With `package-lock.json` or `pnpm-lock.yaml`, the web server command changes to match.

### Why does the config use 127.0.0.1 instead of localhost?

`vite.config.js` binds the server to `127.0.0.1` only. Under Bun, `localhost` can resolve to the IPv6 address `::1`, where nothing is listening, so tests using `localhost` as `baseURL` can fail to connect. Using one address for both the server check and the tests removes that difference.
