# Write Playwright Tests for a Laravel App

Yes. An agent sets up your Laravel app in its sandbox, writes Playwright specs for its key flows, runs them headless and opens a pull request.

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

## What the agent does

An end-to-end test of a Laravel app needs the whole app running, so the agent reads what that takes first. In koel/koel, `composer.json` requires PHP 8.3 and `laravel/framework` ^13.0, and runs PHPUnit with `php artisan test --parallel`. The front end is Vue 3 built by Vite (`pnpm-lock.yaml`, `pnpm run build`), with component specs beside each `.vue` file under `resources/assets/js/components`, and nothing that drives a real browser against a running server. `.env.example` defaults to `DB_CONNECTION=mysql` with an empty `APP_KEY` and an empty `MEDIA_PATH`.

So it builds a test environment the app supports without MySQL: an `.env.e2e` with `DB_CONNECTION=sqlite-persistent` (defined in `config/database.php`) pointing at a throwaway file, `php artisan key:generate`, then `php artisan koel:init --no-assets --no-scheduler`, which migrates and seeds the first admin, `admin@koel.dev` with the password `KoelIsCool` from `User::FIRST_ADMIN_*`. It points `MEDIA_PATH` at the MP3 and FLAC files the PHPUnit suite already ships in `tests/songs` and runs `php artisan koel:scan`, so the library has real tracks to play. It builds the assets once with `pnpm run build`.

The Playwright config in `e2e/` starts that app with `php artisan serve` on a fixed port as its `webServer`, after the setup script, so `npx playwright test` works from a clean checkout. The specs cover three flows. Sign-in fills the form `CredentialsLoginForm.vue` renders under `data-testid="login-form"`, submits with `data-testid="submit"`, and checks a wrong password keeps the user on the form. Playing a song opens the library, plays a track scanned from `tests/songs`, and checks the footer `AudioPlayer` reports playback. Creating a playlist goes through `CreatePlaylistForm.vue`, names it, adds a song and reloads to check it was saved.

Headless Chromium plays audio with no sound device, so the agent checks playback through the player's state and the request to the stream endpoint, not through sound. It runs the suite headless several times; a failure caused by the app rather than the test stays in the suite marked `test.fail()`, with its cause written down.

## 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, playing a song and creating a playlist in this Laravel 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-laravel-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/playback.spec.ts` and `e2e/playlist.spec.ts`, a `playwright.config.ts` whose `webServer` runs `php artisan serve`, a setup script that prepares the SQLite database, seeds the admin and scans the bundled songs, and `.env.e2e`. `@playwright/test` is added to `package.json` and `pnpm-lock.yaml`; the PHP code and PHPUnit suite are unchanged.

The description explains how to run the suite from a clean checkout in one command, what the setup script changes (a separate SQLite file, never your `.env`), and every test marked `test.fail()` with the behavior it found and where. The session's trajectory keeps the `koel:init` and `koel:scan` output and every `npx playwright test` run with its full output.

Before merging, a reviewer checks that `.env.e2e` holds no real secrets, that SQLite is close enough to the production database for these flows, and whether each expected failure is a bug to fix. Running the suite in CI needs PHP, pnpm and Chromium on the runner; a follow-up on the same session can add that workflow.

## Run it on every release branch cut

When a release branch is created, a GitHub `create` webhook can send this request with the branch in `resources`, asking the agent to run the e2e suite there and update any spec the release broke. The agent runs it against that exact code in its own sandbox and pushes fixes to a branch of its own.

Set a webhook URL on the API key and Rush POSTs `run.completed` or `run.failed` when the turn finishes, so the release channel hears whether sign-in, playback and playlists still work before the release ships.

## Why run it on Rush?

Running a Laravel app end to end on a laptop means PHP, Composer, Node, a database, a built front end and a browser, all on versions that match the app, and a `.env` you do not want a test to overwrite. In its own sandbox the agent sets all of that up from nothing, seeds a known admin, and scans fixture media, so the tests run against a real server rather than a mocked API.

What it hands back has been run: the trajectory shows every setup command and every Playwright run with its output. Each run is isolated, so `php artisan serve` and the SQLite file never collide with another job, and the same request can add end-to-end tests to several Laravel apps at once.

## Frequently asked questions

### Will it touch my .env or my real database?

No. The suite uses its own `.env.e2e` and a separate SQLite file the setup script creates, and the sandbox has no access to your databases unless you give it one. Your `.env.example` and `.env` stay as they are.

### Does my app need to support SQLite?

It helps, because the setup needs no database server. Koel defines a `sqlite-persistent` connection, so the agent uses it. If your app only works on MySQL or Postgres, the agent runs that server in the sandbox instead and says so in the description.

### How does it test audio playback in a headless browser?

It checks the player's state and the request the browser makes for the track, not the sound. That proves the click reached the player and the server streamed the file, which is the part a regression breaks.

### Will it replace my PHPUnit tests?

No. PHPUnit stays for the server code and the Vue component specs stay beside their components. Playwright adds the one thing neither covers: a real browser against a running app.
