skip to content

In Laravel 13, how do you set up Laravel Dusk and write a first browser test that signs a new user up?

level: juniorimportance: should knowfreq 30%

answer

  1. dev dependency, then dusk:install
  2. tests/Browser and DuskTestCase
  3. APP_URL must reach a running app
  4. browse() hands you a Browser
  5. php artisan dusk runs the suite

basics

~20 s

Require laravel/dusk as a dev dependency and run php artisan dusk:install, which creates tests/Browser and DuskTestCase and downloads ChromeDriver. Point APP_URL at the running app, chain visit(), type() and press() inside $this->browse(), and run php artisan dusk.

solid answer

~40 s

Install with `composer require laravel/dusk --dev`, then `php artisan dusk:install`: it creates `tests/Browser` with an example test and page classes, writes `tests/DuskTestCase.php`, and downloads a ChromeDriver binary for your OS. Set `APP_URL` to the address where the app is actually served, because Dusk drives a real Chrome against that URL and does not start a web server. A test calls `$this->browse(function (Browser $browser) { ... })` and chains `visit('/register')`, `type('name', 'Ada')`, `type('email', ...)`, `press('Register')`, then `assertPathIs('/dashboard')`. `type()` finds an input or textarea by its `name` when given a plain word; `press()` finds a button by text, name or selector. Run it with `php artisan dusk`, not `php artisan test`. With Pest installed, `dusk:install` wires `tests/Browser` to `DuskTestCase` in `tests/Pest.php`. The Laravel 13 docs now recommend Pest 4's browser testing for new projects.

code

bash · 4 lines
bash
composer require laravel/dusk --dev
php artisan dusk:install
php artisan serve --no-reload &
php artisan dusk

go deeper

for a junior

Recall the install steps, dusk:install, the tests/Browser folder, and the browse() closure with visit, type, press and an assertion.

for a middle

Explain that Dusk drives real Chrome via ChromeDriver against the app at APP_URL, and how type() and press() find elements.

for a senior

Keep Dusk as a dev-only dependency, match ChromeDriver to Chrome, and use a dedicated .env.dusk file so browser runs never touch real data.

for a principal

Decide whether browser tests belong in Dusk or Pest's browser plugin for your stack, weighing existing suites against the docs' current recommendation.

## What Dusk is **Laravel Dusk** is Laravel's first-party browser automation package. A Dusk test starts a real Chrome through **ChromeDriver** (a small server that speaks the WebDriver protocol), points it at your running application, and clicks and types like a user. Because the page runs its own JavaScript, Dusk can test what HTTP feature tests cannot: date pickers, modals, Alpine or Livewire behaviour, redirects done in the browser. ## Installing it 1. `composer require laravel/dusk --dev`. It must stay a **dev** dependency; the package registers login helper routes in every non-production environment. 2. `php artisan dusk:install`. This creates `tests/Browser/` with an `ExampleTest.php` and `Pages/` classes, writes `tests/DuskTestCase.php`, and installs a ChromeDriver binary for your operating system. 3. Set `APP_URL` in `.env` to the URL the app is served on, for example `http://127.0.0.1:8000` with `php artisan serve`. Dusk **does not start your application**; it sends the browser to that URL. 4. Optionally create `.env.dusk.local`: when `php artisan dusk` runs in the `local` environment, it backs up `.env`, swaps in that file for the run, and restores it afterwards. If Chrome on the machine is newer than the downloaded driver, `php artisan dusk:chrome-driver --detect` installs the matching version. ## The generated base class `tests/DuskTestCase.php` extends `Laravel\Dusk\TestCase`. Its `prepare()` method, marked with PHPUnit's `#[BeforeClass]` attribute, starts ChromeDriver on port 9515 (unless running in Sail), and its `driver()` method builds Chrome options: a 1920x1080 window, and `--headless=new` plus `--disable-gpu` unless headless mode is disabled. `DUSK_DRIVER_URL` can point it at a different WebDriver server. ## The first test: a sign-up flow ```php $this->browse(function (Browser $browser) { $browser->visit('/register') ->type('name', 'Ada Lovelace') ->type('email', '[email protected]') ->type('password', 'secret-password') ->type('password_confirmation', 'secret-password') ->press('Register') ->assertPathIs('/dashboard'); }); ``` - `browse()` takes a closure and passes it one `Browser` per parameter, so a two-parameter closure gets two browsers. - `visit()` is relative to `APP_URL`. - `type('email', ...)` clears the field and sends keystrokes. A plain word is matched against an `input` or `textarea` with that `name`; an `#id` or any other CSS or `@` selector is used as given. - `press('Register')` finds a button by selector, name, value or visible text and clicks it. - Assertions such as `assertPathIs()`, `assertSee()` and `assertInputValue()` read the live page. ## Page classes `dusk:install` also creates `tests/Browser/Pages/Page.php` and `HomePage.php`, and `php artisan dusk:page SignupPage` generates more. A page class declares its `url()`, an `assert()` method that checks the browser really is on that page, and an `elements()` map of shorthand selectors such as `'@email' => 'input[name=email]'`. `$browser->visit(new SignupPage)` navigates to the URL and runs the page's assertions, so a sign-up flow reads as steps on named pages rather than raw URLs and selectors. ## Running | Command | Purpose | |---|---| | `php artisan dusk` | run the browser suite (accepts the usual PHPUnit or Pest arguments) | | `php artisan dusk --browse` | open a visible browser instead of headless mode, outside CI | | `php artisan dusk:fails` | re-run only the tests that failed last time | | `php artisan dusk:make SignupTest` | generate a new test in `tests/Browser` | ## Dusk with Pest When Pest is installed, `dusk:install` writes a Pest-style example test and adds `pest()->extend(Tests\DuskTestCase::class)->in('Browser')` to `tests/Pest.php`, so `test('...', function () { $this->browse(...); })` works. That is Dusk running under Pest. Separately, the Laravel 13.x documentation now carries a warning that **Pest 4 includes its own browser testing** and recommends it over Dusk for new projects; Dusk remains supported and is what many existing suites use. ## What to say in an interview - Dusk drives real Chrome via ChromeDriver; no Selenium or JDK is required by default. - The app must be running at `APP_URL`. - `browse()`, `visit()`, `type()`, `press()`, then an assertion. - `php artisan dusk`, not `php artisan test`.

  • The first Dusk run fails with a connection error before any page loads. What do you check first?
    That the app is actually being served at `APP_URL` (Dusk never starts it; run `php artisan serve` or use your local server), and that ChromeDriver matches the installed Chrome. `php artisan dusk:chrome-driver --detect` installs the driver version that matches the detected Chrome.
  • Should a brand-new Laravel 13 project start its browser tests with Dusk?
    The 13.x Dusk docs recommend Pest 4's built-in browser testing for new projects, citing performance and usability. Dusk is still maintained and suits teams with existing Dusk suites or a PHPUnit-only codebase; a new project already on Pest has a reason to start there.

saying these in an interview costs you the question

  • Dusk starts its own web server, so APP_URL does not matter
  • Dusk tests run with php artisan test like feature tests
  • Dusk needs a Selenium server and a JDK installed
  • laravel/dusk belongs in require so production can run browser tests
  • Dusk simulates HTTP requests in-process like the feature test client