Skip to content

Commit cb8f2a4

Browse files
committed
Reformat SKILL.md per Claude Skills best practices
1 parent 69e6c9d commit cb8f2a4

1 file changed

Lines changed: 39 additions & 65 deletions

File tree

  • resources/boost/skills/pest-plugin-ai
Lines changed: 39 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,38 @@
11
---
22
name: pest-plugin-ai
3-
description: One-shot Pest verification CLI for Laravel/PHP agents. Use whenever the user wants to quickly check that a change actually works — hitting a route, asserting a model relationship or factory, checking a queued job/mail/notification fires, screenshotting a page, asserting visible content, testing a click or form submission, checking for JavaScript errors, asserting accessibility, doing visual regression, or testing responsive layouts. Triggers include "verify this works", "did my change break X", "screenshot the homepage", "check this route returns 200", "make sure the mail fires", "test the login form", "see if the page renders", "check it on mobile", "is the form working", or any one-off behavioral check on a Laravel app that does not warrant a permanent test file. Also use after any Blade/Livewire/CSS/JS change to visually confirm the result. opening tinker for behavioral checks, hitting endpoints with curl, or eyeballing the browser yourself.
3+
description: One-shot Pest verification CLI for Laravel and PHP agents. Use whenever the user wants to quickly check that a change actually works, including hitting a route, asserting a model relationship or factory, checking a queued job, mail, or notification fires, screenshotting a page, asserting visible content, testing a click or form submission, checking for JavaScript errors, asserting accessibility, doing visual regression, or testing responsive layouts. Triggers include "verify this works", "did my change break X", "screenshot the homepage", "check this route returns 200", "make sure the mail fires", "test the login form", "see if the page renders", "check it on mobile", "is the form working", or any one-off behavioral check on a Laravel app that does not warrant a permanent test file. Also use after any Blade, Livewire, CSS, or JS change to visually confirm the result. Prefer `vendor/bin/pest --ai="<code>"` over writing throwaway test files, opening tinker for behavioral checks, hitting endpoints with curl, or eyeballing the browser manually.
44
---
55

66
# pest-plugin-ai
77

8-
One-shot Pest verification for AI agents. Wrap any PHP snippet in
9-
`vendor/bin/pest --ai="<code>"` and Pest creates a temporary test, runs it,
10-
and deletes it. The snippet lives inside `it('verify', function () { ... })`,
11-
so use Pest's expectation API and any helpers available in the test suite
12-
(`visit()`, `actingAs()`, `Mail::fake()`, factories, etc.).
8+
One-shot Pest verification for AI agents. Wrap any PHP snippet in `vendor/bin/pest --ai="<code>"`. Pest creates a temporary test, runs it, and deletes it. The snippet lives inside `it('verify', function () { ... })`, so use Pest's expectation API and any helpers available in the test suite (`visit()`, `actingAs()`, `Mail::fake()`, factories, and so on).
139

1410
## How it works
1511

16-
`pest --ai="<code>"` writes a temp file like:
12+
`pest --ai="<code>"` writes a temp file shaped like this:
1713

1814
```php
1915
<?php
16+
2017
it('verify', function () {
21-
<code>
18+
/* your snippet goes here */
2219
});
2320
```
2421

25-
Then runs it with the project's normal Pest configuration (Feature/Browser
26-
namespace `uses`, traits applied via `tests/Pest.php`, etc.) and cleans up
27-
afterwards. Because the file has **no `use` imports**, every class must be
28-
fully qualified.
22+
It then runs with the project's normal Pest configuration (Feature and Browser namespace `uses`, traits applied via `tests/Pest.php`) and cleans up afterwards. The file has **no `use` imports**, so every class must be fully qualified.
2923

3024
## Critical rules
3125

32-
- **Always use `vendor/bin/pest`**, never bare `pest`. The bare command often
33-
isn't on `PATH` and you'll get "command not found" instead of a real result.
34-
- **Always fully qualify class names**: `\App\Models\User`, `\Illuminate\Support\Facades\Mail`,
35-
`\App\Notifications\WelcomeNotification`. The generated test has no
36-
`use` statements, so unqualified names will throw `Class "User" not found`.
37-
- **Don't replace real tests with `--ai`**. This is a verification probe, not a
38-
way to skip writing tests. If the behavior is worth keeping a regression
39-
guard on, write a proper test file.
40-
- **Don't paper over missing setup.** If a check fails because a factory,
41-
seeder, or migration is missing, stop and ask the user to add it. Don't
42-
bend `--ai` invocations into fixtures.
43-
- **Delete screenshots after reviewing them.** They land in the project root
44-
and clutter the repo if left behind.
45-
- **Quote the snippet so the shell preserves PHP syntax.** Use double quotes
46-
on the outside and single quotes inside (or escape `$` as `\$` if you need
47-
shell interpolation suppressed).
26+
- **Use `vendor/bin/pest`, never bare `pest`.** The bare command often is not on `PATH` and produces "command not found" instead of a real result.
27+
- **Fully qualify every class name:** `\App\Models\User`, `\Illuminate\Support\Facades\Mail`, `\App\Notifications\WelcomeNotification`. The generated test has no `use` statements, so unqualified names throw `Class "User" not found`.
28+
- **Do not replace real tests with `--ai`.** This is a verification probe, not a way to skip writing tests. If the behavior is worth a regression guard, write a proper test file.
29+
- **Do not paper over missing setup.** If a check fails because a factory, seeder, or migration is missing, stop and ask the user to add it. Do not bend `--ai` invocations into fixtures.
30+
- **Delete screenshots after reviewing them.** They land in the project root and clutter the repo if left behind.
31+
- **Quote the snippet so the shell preserves PHP syntax.** Use double quotes outside, single quotes inside, and escape `$` as `\$` so the shell does not interpolate variables.
4832

4933
## Backend verification
5034

51-
Use factories to seed state inside the snippet — don't rely on existing data.
35+
Seed state with factories inside the snippet. Do not rely on existing data.
5236

5337
```bash
5438
vendor/bin/pest --ai="\$user = \App\Models\User::factory()->create(); expect(\$user->exists)->toBeTrue();"
@@ -68,54 +52,54 @@ Mail, notifications, and queued jobs work via the standard fakes:
6852
vendor/bin/pest --ai="\Illuminate\Support\Facades\Mail::fake(); \App\Models\User::factory()->create()->notify(new \App\Notifications\Welcome()); \Illuminate\Support\Facades\Notification::assertSentTo(...);"
6953
```
7054

71-
## Frontend / browser verification
55+
## Frontend and browser verification
7256

73-
Browser features come from `pestphp/pest-plugin-browser`. If `visit()` is not
74-
defined, install it before continuing:
57+
Browser features come from `pestphp/pest-plugin-browser`. If `visit()` is undefined, install it first:
7558

7659
```bash
7760
composer require pestphp/pest-plugin-browser --dev
7861
npm install playwright@latest
7962
npx playwright install
8063
```
8164

82-
Use relative paths in `visit()` — Pest resolves them against the app URL.
83-
Always pass a descriptive `filename:` to screenshots so the file is easy to
84-
locate (and delete) afterwards. After any Blade/Livewire/CSS/JS change,
85-
reach for these to visually confirm the result.
65+
Use relative paths in `visit()`. Pest resolves them against the app URL. Always pass a descriptive `filename:` to screenshots so the file is easy to locate (and delete) afterwards. After any Blade, Livewire, CSS, or JS change, reach for these to visually confirm the result.
8666

87-
**Smoke screenshots** to confirm a page renders:
67+
### Smoke screenshots
8868

8969
```bash
9070
vendor/bin/pest --ai="visit('/')->screenshot(filename: 'homepage');"
9171
vendor/bin/pest --ai="visit('/dashboard')->screenshot(filename: 'dashboard', fullPage: true);"
9272
vendor/bin/pest --ai="visit('/')->screenshotElement('.hero', filename: 'hero-section');"
9373
```
9474

95-
**Content / element assertions**:
75+
### Content and element assertions
9676

9777
```bash
9878
vendor/bin/pest --ai="visit('/')->assertSee('Welcome');"
9979
vendor/bin/pest --ai="visit('/login')->assertPresent('input[name=email]');"
10080
vendor/bin/pest --ai="visit('/')->assertVisible('.navbar');"
10181
```
10282

103-
**Responsive checks** via device emulation or explicit viewport:
83+
### Responsive checks
84+
85+
Emulate a device or set an explicit viewport:
10486

10587
```bash
10688
vendor/bin/pest --ai="visit('/')->on()->mobile()->screenshot(filename: 'home-mobile');"
10789
vendor/bin/pest --ai="visit('/')->on()->iPhone14Pro()->screenshot(filename: 'home-iphone14pro');"
10890
vendor/bin/pest --ai="visit('/')->resize(375, 812)->screenshot(filename: 'home-375x812');"
10991
```
11092

111-
**Interaction flows**:
93+
### Interaction flows
11294

11395
```bash
11496
vendor/bin/pest --ai="visit('/')->click('Login')->assertPathIs('/login');"
11597
vendor/bin/pest --ai="visit('/contact')->type('email', 'test@example.com')->press('Send')->assertSee('Message sent');"
11698
```
11799

118-
**Health checks** for JS errors, accessibility, and visual drift:
100+
### Health checks
101+
102+
JavaScript errors, accessibility, and visual drift:
119103

120104
```bash
121105
vendor/bin/pest --ai="visit('/')->assertNoJavaScriptErrors();"
@@ -125,9 +109,7 @@ vendor/bin/pest --ai="visit('/')->assertScreenshotMatches();"
125109

126110
## Combining browser and backend
127111

128-
The most powerful pattern: drive the UI, then assert the side effect. Always
129-
assert a frontend signal first (`assertSee`, `assertPathIs`) so you know the
130-
action was processed before checking what it touched on the backend.
112+
Drive the UI, then assert the side effect. Always assert a frontend signal first (`assertSee`, `assertPathIs`) so you know the action was processed before checking what it touched on the backend.
131113

132114
```bash
133115
vendor/bin/pest --ai="\Illuminate\Support\Facades\Mail::fake(); visit('/contact')->type('email', 'test@example.com')->type('message', 'Hello')->press('Send')->assertSee('Message sent'); \Illuminate\Support\Facades\Mail::assertSent(\App\Mail\ContactForm::class);"
@@ -141,33 +123,25 @@ vendor/bin/pest --ai="\Illuminate\Support\Facades\Notification::fake(); visit('/
141123
vendor/bin/pest --ai="visit('/checkout')->type('card', '4242424242424242')->press('Pay')->assertSee('Transaction processed'); expect(\App\Models\Order::count())->toBe(1);"
142124
```
143125

144-
## Database & RefreshDatabase
126+
## Database and RefreshDatabase
145127

146-
If a check fails with "no such table" or similar, look in `tests/Pest.php`
147-
for a commented `RefreshDatabase` line, e.g.
148-
`// uses(RefreshDatabase::class)->in('Feature');`.
128+
If a check fails with "no such table" or similar, look in `tests/Pest.php` for a commented `RefreshDatabase` line, for example `// uses(RefreshDatabase::class)->in('Feature');`.
149129

150-
**Do not silently uncomment it.** Ask the user first. If the project's test
151-
database is persistent (anything other than SQLite `:memory:`), enabling
152-
`RefreshDatabase` will wipe it on every run. Confirm the test DB is in-memory
153-
or otherwise expendable before flipping the switch.
130+
**Do not silently uncomment it.** Ask the user first. If the project's test database is persistent (anything other than SQLite `:memory:`), enabling `RefreshDatabase` wipes it on every run. Confirm the test database is in-memory or otherwise expendable before flipping the switch.
154131

155132
## Pitfalls
156133

157-
- **`use` inside the snippet is invalid.** The code runs inside a closure body namespace imports must happen at file top, which you don't control. Always FQCN.
158-
- **`__DIR__` / `__FILE__` resolve to `/tmp`**, not your tests folder. Don't read fixtures by relative path; pass absolute paths or use `base_path()` / `storage_path()`.
159-
- **One `--ai` per invocation.** You can't chain multiple verifications in a single command. Run them separately.
160-
- **Every failure reports the test name as `verify`.** If you batch checks into one snippet, the failure won't tell you which one broke. Keep snippets focused on a single behavior.
161-
- **Traits can't be added inline.** `RefreshDatabase`, `WithFaker`, etc. must be wired through `tests/Pest.php` `uses()`; the snippet inherits whatever is already configured.
162-
- **Browser tests need a reachable app.** `visit('/foo')` hits the configured app URL make sure `php artisan serve` (or your usual dev server) is running, or the browser plugin's built-in server is configured.
134+
- **`use` inside the snippet is invalid.** The code runs inside a closure body, so namespace imports must happen at file top, which you do not control. Always use fully qualified class names.
135+
- **`__DIR__` and `__FILE__` resolve to `/tmp`**, not the tests folder. Do not read fixtures by relative path. Pass absolute paths or use `base_path()` and `storage_path()`.
136+
- **One `--ai` per invocation.** Multiple verifications cannot be chained in a single command. Run them separately.
137+
- **Every failure reports the test name as `verify`.** If you batch checks into one snippet, the failure will not tell you which one broke. Keep snippets focused on a single behavior.
138+
- **Traits cannot be added inline.** `RefreshDatabase`, `WithFaker`, and similar traits must be wired through `tests/Pest.php` `uses()`. The snippet inherits whatever is already configured.
139+
- **Browser tests need a reachable app.** `visit('/foo')` hits the configured app URL, so make sure `php artisan serve` (or your usual dev server) is running, or the browser plugin's built-in server is configured.
163140
- **Screenshots persist on failure too.** A failed assertion still leaves the PNG in the project root. Sweep them up regardless of outcome.
164-
- **Shell escaping bites.** Backticks, `!` (in zsh), and `$` will all be interpreted before PHP sees them. Escape `$` as `\$`, avoid `!`, and prefer single quotes inside the snippet (`'foo'`) over double.
141+
- **Shell escaping bites.** Backticks, `!` (in zsh history), and `$` are all interpreted before PHP sees them. Escape `$` as `\$`, avoid `!`, and prefer single quotes inside the snippet (`'foo'`) over double.
165142

166143
## When NOT to use
167144

168-
- The behavior deserves a permanent regression guard → write a real test file
169-
in `tests/Feature` or `tests/Browser`.
170-
- The check needs more than ~3 statements or any helper function → write a
171-
real test file; long shell-quoted snippets are painful to read and edit.
172-
- The user is asking for a fix or refactor, not a verification → use the
173-
appropriate edit/test workflow, not `--ai`.
145+
- The behavior deserves a permanent regression guard. Write a real test file in `tests/Feature` or `tests/Browser` instead.
146+
- The check needs more than roughly three statements or any helper function. Long shell-quoted snippets are painful to read and edit; write a real test file.
147+
- The user is asking for a fix or refactor, not a verification. Use the appropriate edit and test workflow, not `--ai`.

0 commit comments

Comments
 (0)