agentsclimarketplace

Laravel testing

Skill HamzaAlayed/laravel-claude-agents/gemini/skills/laravel-testing

The Laravel test-authoring cookbook — fakes with exact assertion syntax, Pest v4 browser testing vs Dusk, factory states + sequences, time control, DB strategies. Use when writing or reviewing Pest / PHPUnit tests, reproducing a bug as a regression test, choosing between fakes and mocks, or setting up browser tests. Recipes only — test strategy and Ship / Hold verdicts stay with qa-engineer.From its SKILL.md

Install
npx -y skills add HamzaAlayed/laravel-claude-agents --skill laravel-testing

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 13 stars13 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

4.4 KB, as published. Nobody here has run it

Laravel Testing Cookbook

Match the project first: Pest vs PHPUnit from composer.json, DB strategy from existing tests (RefreshDatabase — transaction-based, skips migrating when the schema is current — vs DatabaseMigrations / DatabaseTruncation, both slower full resets needed for browser tests). Seeding: prefer L13's #[Seed] / #[Seeder(OrderStatusSeeder::class)] attributes over manual $this->seed() boilerplate; #[UnitTest] on a pure-logic method skips booting the app for just that test. Never introduce a second runner or strategy.

Fakes — assertion syntax

Fake the framework primitive, assert the interaction. Never mock what Laravel fakes.

PrimitiveSetupAssert
MailMail::fake()Mail::assertSent(OrderShipped::class, fn ($m) => $m->hasTo($user->email)) · assertQueued · assertNothingSent
NotificationNotification::fake()Notification::assertSentTo($user, InvoicePaid::class, fn ($n, $channels) => in_array('mail', $channels))
Queue / BusQueue::fake() / Bus::fake()Bus::assertDispatched(ProcessOrder::class, fn ($job) => $job->order->is($order)) · assertChained · assertBatched · assertNotDispatched
EventEvent::fake([OrderShipped::class])Event::assertDispatched(OrderShipped::class) — always pass the allowlist: a bare Event::fake() suppresses model events and factories break silently
HTTPHttp::fake(['api.stripe.com/*' => Http::response(['id' => 'ch_1'], 200)])Http::assertSent(fn (Request $r) => $r->url() === … && $r['amount'] === 500). Fake success, 4xx, 5xx, and Http::failedConnection() timeout
StorageStorage::fake('avatars')Storage::disk('avatars')->assertExists($path) · assertMissing
ProcessProcess::fake(['git *' => Process::result('ok')])Process::assertRan(fn ($p) => str_contains($p->command, 'git'))

Jobs: Bus::fake() proves dispatch; invoking $job->handle() directly proves effect. Test both, plus failed().

Time

$this->travelTo(now()->addDays(30)), $this->freezeTime(), $this->travelBack(). Any TTL, expiry, or scheduling logic gets a time-travel test — never sleep().

Factories

  • States for variants: OrderFactory::new()->paid()->forUser($user). Never hand-build models in tests.
  • Sequence for controlled variation: ->state(new Sequence(['status' => 'active'], ['status' => 'churned'])).
  • Relationships: ->has(Post::factory()->count(3)) / ->for($team). recycle($tenant) to share one parent across the tree — the multi-tenant test essential.
  • Model::factory()->make()->getAttributes() for validation-payload arrays (doc-backed; ->raw() exists but is undocumented).

Browser tests

Detect first, then match: pestphp/pest-plugin-browser (Pest v4 — current) vs laravel/dusk (legacy — keep, don't migrate mid-PR). Pest v4: visit('/dashboard')->assertSee(…), plus free checks Dusk lacks — assertNoJavascriptErrors(), assertNoConsoleLogs(), assertNoAccessibilityIssues(). Use them on every page test.

Livewire / Inertia / Filament

  • Livewire: Livewire::test(CreateOrder::class)->set('email', '[email protected]')->call('save')->assertHasNoErrors()->assertDispatched('order-created').
  • Inertia: $this->get(route('orders.index'))->assertInertia(fn (Assert $page) => $page->component('Orders/Index')->has('orders', 3)).
  • Filament: livewire(CreateOrder::class)->fillForm([...])->call('create')->assertNotified().

Coverage that must exist

  • Every protected endpoint: one allowed + one denied authorization test (403), and an unauthenticated test (401) for APIs.
  • Every validation rule that guards money, quantity, or state: a failing-input test asserting assertJsonValidationErrors (APIs) or assertInvalid / assertRedirectBackWithErrors (classic web forms).
  • Every production bug: a regression test that fails on the old code. Name it after the bug.
  • Feature tests assert three layers: status, shape (assertJsonPath, assertJsonStructure), and DB state (assertDatabaseHas, assertDatabaseCount).

Keep looking

Skills are one crate of 627,801. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.