resources/boost/skills/dusk/SKILL.md
End-to-end browser testing with Laravel Dusk. Used exclusively for full user flows requiring a real Chrome browser — JavaScript interactions, multi-step forms, and visual assertions.
npx skillsauth add codebar-ag/coding-guidelines duskInstall 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.
tests/Browser/..env.dusk.local is configured with isolated test DB and app URL.DatabaseTruncation or DatabaseMigrations, never RefreshDatabase.dusk="" selectors for all interactive elements under test.loginAs() to bypass repetitive auth UI unless auth flow is under test.waitFor* assertions.assertNoJavaScriptErrors() after each visit().tests/Browser/.DatabaseTruncation (preferred) or DatabaseMigrations; never RefreshDatabase.dusk="" selectors for test targeting.pause(); wait for explicit UI state transitions.uses(DatabaseTruncation::class);
it('user can submit an invoice', function () {
// Arrange
$user = User::factory()->create();
// Act + Assert
$this->browse(function (Browser $browser) use ($user) {
$browser->loginAs($user)
->visit('/invoices/create')
->assertNoJavaScriptErrors()
->type('@amount-input', '100')
->press('@submit-button')
->waitForText('Invoice created')
->assertSee('Invoice created');
});
});
<!-- Blade/HTML — use dusk attributes, not CSS classes -->
<button dusk="submit-invoice">Submit</button>
<input dusk="amount-input" type="number" name="amount">
// Page Object
class InvoicePage extends Page
{
public function __construct(private readonly int $invoiceId) {}
public function url(): string { return "/invoices/{$this->invoiceId}"; }
public function assert(Browser $browser): void
{
$browser->assertPathIs($this->url());
}
public function elements(): array
{
return [
'@mark-paid-button' => '[dusk="mark-paid-button"]',
];
}
public function markAsPaid(Browser $browser): void
{
$browser->click('@mark-paid-button')
->waitForText('Invoice marked as paid');
}
public function fillForm(Browser $browser, string $amount): void
{
$browser->type('@amount-input', $amount);
}
public function submitForm(Browser $browser): void
{
$browser->press('@submit-button');
}
public function assertSuccess(Browser $browser): void
{
$browser->waitForText('Invoice created')
->assertSee('Invoice created');
}
}
// Waiting — never use pause()
$browser->waitFor('@invoice-table'); // ❌ pause(3000)
$browser->waitForText('Invoice created'); // ❌ pause(2000)
$browser->waitUntilMissing('@loading-spinner'); // ❌ pause(5000)
php artisan dusk.php artisan dusk tests/Browser/InvoiceFlowTest.php.RefreshDatabase in Dusk tests (transactions invisible across HTTP processes)pause(3000) — arbitrary sleeps make tests slow and brittledusk="" attributesassertNoJavaScriptErrors() after visit()PestTesting/SKILL.md — Pest syntax used for Dusk testsPHPUnit/SKILL.md — feature tests for non-browser scenariostesting
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.