Using Laravel Dusk with Valet Linux

Chris Di Carlo • November 16, 2020

Recently, I started working in a large codebase that didn't have any tests but - oh boy - did it have a lot of business rules and complex UI interactions! I had spun up my local Valet (just a note: I run Linux, so I use cpriego/valet-linux and got my dev environment up and running. As I started working on new features, I began TDD'ing everything out and adding tests as needed.

I wanted to add Laravel Dusk to the mix as I went about adding some of these new features. Never having dabbled with Dusk, I did what any newcomer would do: open the docs and grab a simple, no-brainer example to run as a learning test case. In my case, it was the example under "Creating Browsers": APP_URL

public function test_basic_example()
    {
        $user = User::factory()->create([
            'email' => 'taylor@laravel.com',
        ]);

        $this->browse(function ($browser) use ($user) {
            $browser->visit('/login')
                    ->type('email', $user->email)
                    ->type('password', 'password')
                    ->press('Login')
                    ->assertPathIs('/home');
        });
    }

Simple enough and instantly understandable what was going on if you have previous PHPUnit testing experience. Excited to get my first green bar, I quickly run the test and ...

Wham! Red. Ugly, irritating, piss-me-off-because-I-copied-the-code-verbatim, red. What gives? Here's the error message I got:

no such element: Unable to locate element: {"method":"css selector","selector":"body email"}

Um, okay. Diving into the docs again, everything looked as it should. After an hour of searching the Net, I came across one suggestion that might explain it: my APP_URL in my .env.testing file wasn't set to my Valet site. Quick fix! Yay! Run the test again, drumroll please...

Same error. Okay, so not the solution.

Digging deeper, I found the dump() method that would spit out the rendered HTML and there came the Aha! moment. Here's the output after dumping right after the visit('/login'):

<html><head></head><body></body></html>

That's interesting. Looks nothing like my Blade template. Now the previous error message makes total sense. But why isn't it rendering the view?

I disabled headless mode in the base DuskTestCase so it would spawn a browser window and got yet another error:

unknown error: Chrome failed to start: exited abnormally.
(unknown error: DevToolsActivePort file doesn't exist)
(The process started from chrome location /usr/bin/chromium is no longer running, so ChromeDriver is assuming that Chrome has crashed.)

Wow, the browser can't even start, so something is definitely off it's rocker here. More searching finally pointed me in the right direction. The underlying issue? I had to set the acceptInsecureCerts capability on the WebDriver to true in order for the Valet-served page to render properly. Inside the DuskTestCase, chain setCapability('acceptInsecureCerts', true) onto the RemoteWebDriver::create call. Here's what that looks like in my test case:

return RemoteWebDriver::create(
    $_ENV['DUSK_DRIVER_URL'] ?? 'http://localhost:9515',
    DesiredCapabilities::chrome()->setCapability(
        ChromeOptions::CAPABILITY,
        $options
    )->setCapability('acceptInsecureCerts', true)
);

After re-enabling headless mode and removing the dump() call, the

Happy coding! Cheers!