Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Testbench Dusk Laravel Package

orchestra/testbench-dusk

Laravel Dusk testing helper for package development. Orchestra Testbench Dusk lets you write browser tests for your Laravel packages, bootstrapping a test application with Dusk support so you can verify real user interactions end to end.

View on GitHub
Deep Wiki
Context7

Getting Started

Testbench Dusk lets you run real browser tests against your package without spinning up a full Laravel app. It boots the orchestra/testbench-dusk skeleton application under PHP's built-in server and points Dusk's Chrome driver at it.

Minimal setup

  1. Install the version that matches your orchestra/testbench major (they are lock-stepped with Laravel: testbench-dusk ^9 for Laravel 11, ^10 for Laravel 12, ^11 for Laravel 13):

    composer require --dev orchestra/testbench-dusk
    
  2. Make sure Chrome/Chromium and a matching chromedriver are on the machine (in CI, install them before the test run; Dusk's driver installer or a manual download both work). Mismatched Chrome/chromedriver versions are the single most common "it says nothing works" failure.

  3. Create tests/Browser/ExampleTest.php extending Orchestra\Testbench\Dusk\TestCase (not Laravel\Dusk\TestCase):

    use Laravel\Dusk\Browser;
    use Orchestra\Testbench\Dusk\TestCase;
    
    class ExampleTest extends TestCase
    {
        protected function defineRoutes($router)
        {
            $router->get('/demo', fn () => view('demo'));
        }
    
        protected function beforeServingApplication($app)
        {
            $app->register(MyPackageServiceProvider::class);
        }
    
        public function test_demo_page_renders()
        {
            $this->browse(function (Browser $browser) {
                $browser->visit('/demo')
                    ->assertSee('Hello')
                    ->click('@save')
                    ->waitForText('Saved');
            });
        }
    }
    
  4. Run with vendor/bin/phpunit tests/Browser (keep these out of your fast unit suite; put them in a Browser testsuite or a dusk group).

Where to look first: the docs at packages.tools/testbench-dusk.html, then the Orchestra\Testbench\Dusk\TestCase and Orchestra\Testbench\Dusk\DuskServer sources — those two classes define everything you'll override.

First use case: a Blade component, Livewire/Alpine widget, or JS-driven flow in your package that you cannot meaningfully assert with $this->get(). If it doesn't need a browser, use plain Testbench feature tests — they're orders of magnitude faster.

Implementation Patterns

Declare routes, don't rely on the package's routes. The served app is the skeleton, so your package's controllers/routes are only available if the provider registers them. defineRoutes($router) is the cheapest way to expose a fixture page:

protected function defineRoutes($router)
{
    $router->get('/forms', fn () => view('forms.index'));
    $router->post('/forms', [FormController::class, 'store']);
}

For anything substantial, prefer Testbench's workbench/ application: routes in workbench/routes/web.php, views in workbench/resources/views, and your provider loaded via getPackageProviders(). Both Dusk tests and normal feature tests then exercise the same fixtures.

Use beforeServingApplication() / afterServingApplication() for app-level setup. These run inside the skeleton app before and after the server serves requests — register providers, point the view finder at your test fixtures, swap bindings:

protected function beforeServingApplication($app)
{
    $app['config']->set('app.key', 'base64:...');
    $app['view']->addLocation(__DIR__.'/views');
    $app->register(MyPackageServiceProvider::class);
}

(tweakApplication() / removeApplicationTweaks() are deprecated aliases — migrate if you have older tests.)

Authenticate through the UI, not actingAs(). The browser talks to a separate PHP process, so PHPUnit's session and $this->app state are not shared. Either create a login route and fill the form like a user, or add a dedicated test-only route in beforeServingApplication() that logs in the user and redirects.

Database state: use DatabaseMigrations or migrate:fresh, not RefreshDatabase. Transactions opened in PHPUnit are invisible to the served app's requests. Seed data in beforeServingApplication() or via a test-only route before $this->browse().

Selector strategy. Add dusk="save" attributes to your package's Blade output and use @save selectors; prefer waitForText / waitFor / waitUntilMissing over assertSee for anything rendered by JS. Chain ->screenshot('name') (Dusk writes to tests/Browser/screenshots by default) on failure paths — it's the fastest way to debug a red build.

Console error assertions. $browser->assertConsoleLogHasNoErrors() is a cheap guard for JS regressions in package assets.

CI setup. Run Chrome headless (the package passes --disable-search-engine-choice-screen, --disable-smooth-scrolling, etc. by default so first-run dialogs don't hang the driver). Keep the browser suite as a separate job or workflow — it's slow and needs a display stack.

Gotchas and Tips

  • Version lock-step is mandatory. Testbench Dusk minor versions track Testbench Core and Laravel Dusk; composer will refuse to install a mismatched pair. Bump all three together (composer update orchestra/testbench orchestra/testbench-dusk laravel/dusk) rather than chasing Dusk alone.
  • The served app is a skeleton, not your package. If a route 404s or a view is missing, you forgot to register the provider or add the view path. There is no @vite manifest in the skeleton — avoid @vite directives (and asset helpers that require a build) in Dusk views; use inline CSS/JS or a published asset path.
  • Port collisions. The server binds a fixed local port (8000 by default). Parallel test runs or a forgotten server process will cause flaky timeouts — kill stale servers, or override the port used by DuskServer in your base test case.
  • php -S pipe hangs on older releases. Several releases fixed DuskServer hanging when the built-in server's output pipe fills; if your suite randomly freezes on the first request, upgrade to the latest patch in your major before debugging anything else.
  • Deprecated hooks. tweakApplication() → beforeServingApplication(), removeApplicationTweaks() → afterServingApplication(). Old code still works but will break in a future major.
  • package:dusk-purge cleans generated skeleton/state left behind by Dusk runs; use --pretend to preview what it will delete. Useful in CI between jobs and locally when the skeleton gets dirty.
  • Debugging levers, in order: ->screenshot(), $browser->dump() / dd(), ->assertConsoleLogHasNoErrors(), then the DuskServer output (it echoes the PHP server's stdout into the test run). If Chrome can't connect, the error is almost always the chromedriver/Chrome version pair, not your test.
  • Extension points: override driver() for custom Chrome flags, defineRoutes() for fixtures, beforeServingApplication() for app bootstrapping, and substitute a custom DuskServer if you need a different host/port/served app. Subclass TestCase once into tests/Browser/DuskTestCase.php so future package-wide tweaks live in one place.
  • Cost/benefit: each Dusk test spawns a server and a browser. Reserve it for interaction/JS behavior; everything else belongs in Testbench HTTP tests where a full suite runs in seconds.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo