resources/boost/skills/pesttesting/SKILL.md
Laravel testing conventions using the Pest PHP framework. Covers test structure, AAA pattern, HTTP assertions, datasets, mocking, browser tests, and architecture tests.
npx skillsauth add codebar-ag/coding-guidelines pesttestingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
vendor/bin/pest works).phpunit.xml/env test config).it, describe, expect).assertCreated, assertForbidden, etc.).uses(RefreshDatabase::class) for DB-touching files.// Basic test — AAA pattern
uses(RefreshDatabase::class);
it('creates an invoice for the given order', function () {
// Arrange
$order = Order::factory()->create();
// Act
$response = $this->postJson('/api/invoices', ['order_id' => $order->id]);
// Assert
$response->assertCreated();
expect(Invoice::count())->toBe(1);
});
// Grouped with describe() and beforeEach()
describe('InvoiceController', function () {
beforeEach(function () {
$this->user = User::factory()->create();
$this->actingAs($this->user);
});
it('lists all invoices', function () {
Invoice::factory()->count(3)->create();
$this->getJson('/api/invoices')->assertSuccessful();
});
it('creates an invoice', function () {
$order = Order::factory()->create();
$this->postJson('/api/invoices', ['order_id' => $order->id])
->assertCreated();
});
});
// Datasets for multiple inputs
it('rejects invalid email addresses', function (string $email) {
$this->postJson('/api/users', ['email' => $email])
->assertUnprocessable();
})->with([
'empty string' => [''],
'missing @' => ['notanemail'],
'missing tld' => ['user@domain'],
]);
// Named HTTP assertion methods
$response->assertSuccessful(); // ❌ assertStatus(200)
$response->assertCreated(); // ❌ assertStatus(201)
$response->assertNoContent(); // ❌ assertStatus(204)
$response->assertUnprocessable(); // ❌ assertStatus(422)
$response->assertForbidden(); // ❌ assertStatus(403)
$response->assertUnauthorized(); // ❌ assertStatus(401)
$response->assertNotFound(); // ❌ assertStatus(404)
// Architecture tests
arch('no debug calls in production code')
->expect('App')
->not->toUse(['dd', 'dump', 'var_dump', 'ray']);
arch('controllers have the correct suffix')
->expect('App\Http\Controllers')
->toHaveSuffix('Controller');
// Browser test baseline with Dusk + DatabaseTruncation
uses(\Illuminate\Foundation\Testing\DatabaseTruncation::class);
it('submits invoice flow in browser', function () {
$this->browse(function (Browser $browser) {
$browser->visit('/invoices/create')
->assertNoJavaScriptErrors()
->waitFor('@submit-button');
});
});
# Run all tests through Laravel
php artisan test
# Run Pest directly
vendor/bin/pest
# Run a specific file
vendor/bin/pest tests/Feature/InvoiceControllerTest.php
# Filter by test name/description
vendor/bin/pest --filter="creates an invoice"
# Run a focused group (if groups are configured)
vendor/bin/pest --group=feature
beforeEach() to reduce duplication before adding new assertions.Dusk/SKILL.md.assertStatus(200) instead of named assertion methodsRefreshDatabase in browser (Dusk) tests — use DatabaseTruncationpause(3000) in browser tests — use waitFor() or waitForText()dusk="" attributesuses(RefreshDatabase::class) in feature/unit files that touch the databaseassertNoJavaScriptErrors() after visit() in browser testsDusk/SKILL.md — full browser (E2E) test conventionsPHPStan/SKILL.md — static analysis runs alongside teststesting
Translation and localization conventions for Laravel. Use when adding user-facing strings, creating translation files, or working with lang/ directory.
tools
Reusable behaviour shared across multiple unrelated classes. Traits provide shared Eloquent scopes, accessors, lifecycle hooks, and small stateless helper methods.
development
Tailwind CSS v4 styling conventions. Use when working with CSS, Tailwind utilities, or customizing the theme in Laravel projects.
development
Orchestration classes that coordinate multiple Actions, external APIs, or domain operations into a cohesive workflow. Services own transaction boundaries and third-party API integrations.