Setting up Laravel Dusk in Docker on Apple Silicon


For a freelance project, I needed to set up Laravel Dusk in a Docker environment on an Apple Silicon M4 chip. This was my first experience with Dusk, and I encountered some challenges along the way. In this post, I’ll share the steps I took to get it working.

Docker Setup

You can find the complete Docker setup in my GitHub repository

Adding Laravel Dusk

I logged into my Docker container and installed Laravel Dusk using Composer:

composer require laravel/dusk --dev
php artisan dusk:install

I tried running the example tests, using the php artisan dusk command, but it failed with an error:

Failed to connect to localhost port 9515 after 0 ms: Couldn't connect to server

I added a selenium service to my docker-compose.yml file. Important to note is that I had to use the selenium/standalone-chromium image, as the selenium/standalone-chrome image was not compatible with my Apple Silicon M4 chip.

  selenium:
    image: selenium/standalone-chromium
    ports:
      - "4444:4444"
    shm_size: 2gb
    volumes:
      - /dev/shm:/dev/shm

I created a .env.dusk.local file, where the APP_URL points to the php-apache service url:

APP_URL=http://php-apache

I also made sure my home page is rendering a basic view with the text “Laravel”.

resources/views/home.blade.php:

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel</title>
    </head>
    <body>
        Laravel
    </body>
</html>

routes/web.php:

use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return view('home');
});

Database Reset

I added a database reset step with the DatabaseTruncation trait to ensure a clean state for each test.

use Illuminate\Foundation\Testing\DatabaseTruncation;

abstract class DuskTestCase extends BaseTestCase
{

    use DatabaseTruncation;
    //...

    protected function afterTruncatingDatabase(): void
    {
        $this->artisan('db:seed');
    }

    //...
}

However: I noticed my very first test did not come with a seeded database, only the migrations were run. This is because the afterTruncatingDatabase method is not called when the initial migrations run. After looking into the sourcecode of the DatabaseTruncation trait, I noticed there is a check for a seed boolean, which will seed a database after both the initial migration and the truncation. This means we can get rid of the afterTruncatingDatabase method and just set the seed boolean to true :

use Illuminate\Foundation\Testing\DatabaseTruncation;

abstract class DuskTestCase extends BaseTestCase
{

    use DatabaseTruncation;
    protected $seed = true;

    //...
}