# Write Unit Tests for a Laravel Project

Yes. An agent runs Pest coverage on a Laravel app, adds tests for the thinnest logic, and opens a pull request with the before and after.

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

## What the agent does

The agent learns the app's PHP and test stack from the repo, not from a generic Laravel tutorial. In laravelio/laravel.io it reads `composer.json`: PHP `8.4.*`, `laravel/framework` `^11.5`, Livewire `^3.3`, Filament `^4`, and dev tools `pestphp/pest` `^3.0` with `pest-plugin-laravel` and `pest-plugin-livewire`. `phpunit.xml` defines Unit, Integration and Feature suites, sets `APP_ENV=testing`, `DB_CONNECTION=mysql` / `DB_DATABASE=testing`, and nulls Scout and Telegram. `tests/Pest.php` is present; unit examples such as `tests/Unit/Rules/HttpImageRuleTest.php` use Pest's `it(...)` closures against rules like `HttpImageRule`.

Jobs under `app/Jobs/` are the densest behaviour surface: forty-plus classes such as `CreateThread`, `ReportSpam`, `BlockUser`, `LikeReply`, with many already covered under `tests/Integration/Jobs/`. Comparing directories shows gaps such as `ApproveArticle`, `DeclineArticle`, `DisapproveArticle`, `SaveNotificationSettings`, `UpdatePassword`, `UpdateReply`, `UpdateThread`, `VerifyAuthor` and `UnVerifyAuthor` without a matching `*Test.php`. Models (`Article`, `Thread`, `Reply`, `User`) and rules under `app/Rules/` are the other places coverage often thins out.

It runs the suite with coverage (`./vendor/bin/pest --coverage` or `phpunit` with Xdebug/PCOV, whichever the project already documents in CONTRIBUTING) and picks five least-covered files that still hold real branches. New Pest tests go in the matching suite: Integration jobs use the same `CreatesUsers` / database setup as neighbouring job tests; pure rules stay under `tests/Unit`. Assertions use Pest expectations and exercise outcomes (database relations, events like `SpamWasReported`, validation failures), not private property reads.

Production PHP is unchanged unless a test exposes a bug, which is named in the pull request. The description includes coverage before and after. MySQL for testing is provided inside the sandbox (or SQLite only if the project already supports it for tests); the agent does not silently rewrite `phpunit.xml` to weaken the database. Helpers in `tests/CreatesUsers.php` and `tests/HttpAssertions.php` are reused instead of inventing a second user factory path.

## Start it with one API call

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

```json
{
  "agent": "claude",
  "input": "Run the test suite with coverage, pick the five least-covered files that hold real logic, and write Pest tests for them that exercise behaviour, not implementation details. Do not change production code unless a test reveals a bug; if it does, say so in the description. Open a pull request with the coverage before and after.",
  "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. In a Laravel.io-shaped app it adds Pest files under `tests/Unit` or `tests/Integration/Jobs` (for example covering `ReportSpam` attaching reporters and dispatching `SpamWasReported`, or `UpdatePassword` hashing behaviour). `app/Jobs` and other production paths stay untouched absent a documented fix.

The description lists the five files, the coverage figures before and after, and the exact Pest command that passed. The trajectory keeps the coverage table and any SQL errors the agent had to work through.

Before merging, a reviewer checks that new tests follow Pest style already in the repo, that they do not call external Algolia or Telegram services (env already nulls those in `phpunit.xml`), and that factories used match `database/factories`. Once merged, the existing Tests GitHub Action runs them.

## Run it on every job class merged without a test

When a pull request adds a class under `app/Jobs/` without a file under `tests/Integration/Jobs/`, your server sends this request so Pest coverage for that job lands before release.

Listen for `run.completed` on the API key webhook and paste the pull request into the review thread. Queue starts if you batch several jobs; `max_concurrent` defaults to 4.

## Why run it on Rush?

Laravel.io needs PHP 8.4, Composer deps, a testing MySQL, and Pest with Livewire plugins. Reproducing that on every laptop is slow. On Rush the agent builds that environment in a sandbox, runs coverage, writes the missing Pest cases, and opens a pull request that already passes.

The coverage delta is written on the pull request, and the trajectory shows the Pest output. You can apply the same request to several Laravel apps and review each diff on its own.

## Frequently asked questions

### Pest or PHPUnit classes?

Pest, because that is what `composer.json` and `tests/Pest.php` set up. The agent writes `it(...)` cases consistent with `HttpImageRuleTest.php`, not new PHPUnit class files, unless a neighbouring folder still uses classes exclusively.

### Will it need Algolia or Telegram credentials?

No. `phpunit.xml` already sets `SCOUT_DRIVER=null` and null Telegram env vars. Tests should not make outbound calls; if a job would, the agent fakes the facade the way other integration tests do.

### Feature tests or unit tests?

Whichever suite matches the file. Jobs go under Integration next to `CreateThreadTest.php`; pure rules stay under Unit. It does not demote everything to HTTP feature tests.

### Does it change Livewire components?

Not for this job. If coverage points at a Livewire component, it adds Pest Livewire tests using the installed plugin, still without rewriting the component unless a bug is found.
