From asyrafhussin-agent-skills-1
Laravel 13 testing with Pest PHP 4 or PHPUnit 12. Use when writing feature tests, unit tests, or any test code in a Laravel application. Triggers on tasks involving HTTP tests, model factories, database assertions, mocking facades, authentication testing, or test organisation patterns.
npx claudepluginhub joshuarweaver/cascade-code-languages-misc-1 --plugin asyrafhussin-agent-skills-1This skill uses the workspace's default tool permissions.
> **Supports both Pest PHP 4 and PHPUnit 12.** See Framework Detection below.
AGENTS.mdREADME.mdmetadata.jsonrules/auth-acting-as.mdrules/auth-sanctum.mdrules/db-assert-has.mdrules/db-assert-missing.mdrules/db-assert-soft-deletes.mdrules/factory-define.mdrules/factory-relationships.mdrules/factory-sequences.mdrules/factory-states.mdrules/fake-ai-agent.mdrules/fake-ai-data.mdrules/fake-ai-media.mdrules/fake-event.mdrules/fake-mail.mdrules/fake-notification.mdrules/fake-queue.mdrules/fake-storage.mdSearches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
Supports both Pest PHP 4 and PHPUnit 12. See Framework Detection below.
PHPUnit version note: Laravel 13 ships with
phpunit/phpunit: ^12.5.12in its defaultcomposer.json. All patterns in this skill are compatible with PHPUnit 11, 12, and 13.
Comprehensive testing guide for Laravel 13 applications. Contains 24 rules across 6 categories for writing fast, readable, and reliable tests. Supports both Pest PHP 4 and PHPUnit 12 (Laravel 13 default).
Before writing or reviewing any test code, detect which testing framework the project uses:
# Look for these in require-dev:
# "pestphp/pest" → Pest
# "phpunit/phpunit" (without pest) → PHPUnit
pestphp/pest is present → use Pest syntaxphpunit/phpunit is present → use PHPUnit syntaxtests/Pest.php exists → Pest is configured, use Pest syntax"I couldn't detect the testing framework. Does this project use Pest PHP or PHPUnit?"
| Pest | PHPUnit | |
|---|---|---|
| Test function | test('...', fn() => ...) | public function test_...(): void |
| Readable name | it('...', fn() => ...) | #[Test] public function it_...() |
| Grouping | describe('...', fn() => ...) | Test class name / nested classes |
| Trait application | uses(RefreshDatabase::class) | use RefreshDatabase; inside class |
| Before each | beforeEach(fn() => ...) | protected function setUp(): void |
| After each | afterEach(fn() => ...) | protected function tearDown(): void |
| Parameterised | ->with([...]) | #[DataProvider] attribute |
| Global setup | uses(...)->in('Feature') in Pest.php | Base TestCase class |
assertStatus, assertJson, assertJsonPath, assertDatabaseHas, assertModelExists, actingAs, Mail::fake(), Queue::fake(), Event::fake(), Notification::fake(), Storage::fake() — all work the same in Pest and PHPUnit.
Reference these guidelines when:
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | HTTP & Feature Tests | CRITICAL | http- |
| 2 | Model Factories | CRITICAL | factory- |
| 3 | Database Assertions | HIGH | db- |
| 4 | Faking Services | HIGH | fake- |
| 5 | Authentication Testing | HIGH | auth- |
| 6 | Test Organisation Patterns | MEDIUM | pest- |
http-test-structure - Arrange/Act/Assert with factories — Pest + PHPUnit exampleshttp-assert-response - assertStatus, assertJson, assertRedirect, assertJsonMissinghttp-assert-json-fluent - Fluent assertJson with AssertableJson closurehttp-refresh-database - RefreshDatabase vs DatabaseTransactions — when to use eachfactory-define - Define factories with typed fake data and PHP 8.3 syntaxfactory-states - Factory states for distinct test scenariosfactory-sequences - sequence() for varied data across multiple recordsfactory-relationships - has(), for(), recycle(), afterCreating()db-assert-has - assertDatabaseHas, assertModelExists for presence checksdb-assert-missing - assertDatabaseMissing, assertModelMissing for deletiondb-assert-soft-deletes - assertSoftDeleted, trashed() factory statefake-mail - Mail::fake(), assertSent vs assertQueued, assertNothingSentfake-queue - Queue::fake(), assertPushed, assertPushedOnfake-notification - Notification::fake(), assertSentTo, assertCountfake-event - Event::fake(), assertDispatched, assertNotDispatchedfake-storage - Storage::fake(), UploadedFile::fake(), assertExistsfake-ai-agent - Agent::fake(), assertPrompted, preventStrayPrompts (Laravel 13+)fake-ai-media - Image::fake(), Audio::fake(), Transcription::fake() (Laravel 13+)fake-ai-data - Embeddings::fake(), Reranking::fake(), Files::fake(), Stores::fake() (Laravel 13+)auth-acting-as - actingAs() for session/web authenticated testsauth-sanctum - Sanctum::actingAs() for API token authenticationpest-describe-it - describe()/it() (Pest) or test class organisation (PHPUnit)pest-datasets - with() datasets (Pest) or #[DataProvider] (PHPUnit)pest-hooks - beforeEach/afterEach (Pest) or setUp/tearDown (PHPUnit)<?php
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
test('authenticated user can create a post', function () {
$user = User::factory()->create();
$this->actingAs($user)
->postJson('/api/posts', ['title' => 'Hello World', 'body' => 'Content.'])
->assertStatus(201)
->assertJsonPath('data.title', 'Hello World');
$this->assertDatabaseHas('posts', ['title' => 'Hello World', 'user_id' => $user->id]);
});
<?php
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class PostControllerTest extends TestCase
{
use RefreshDatabase;
public function test_authenticated_user_can_create_a_post(): void
{
$user = User::factory()->create();
$this->actingAs($user)
->postJson('/api/posts', ['title' => 'Hello World', 'body' => 'Content.'])
->assertStatus(201)
->assertJsonPath('data.title', 'Hello World');
$this->assertDatabaseHas('posts', ['title' => 'Hello World', 'user_id' => $user->id]);
}
}
Read individual rule files for detailed explanations and code examples.
Each rule file contains:
For the complete guide with all rules expanded: AGENTS.md