dusk: Can't run dusk tests on ubuntu 16.04

I am trying laravel dusk on a fresh installation laravel 5.4.x-dev This is what I get when I run php artisan dusk

PHPUnit 5.7.5 by Sebastian Bergmann and contributors.

Runtime:       PHP 7.0.13-0ubuntu0.16.04.1 with Xdebug 2.4.0
Configuration: /var/www/html/dusk/phpunit.dusk.xml

E                                                                   1 / 1 (100%)

Time: 2.5 minutes, Memory: 10.00MB

There was 1 error:

1) Tests\Browser\ExampleTest::testBasicExample
Facebook\WebDriver\Exception\WebDriverCurlException: Curl error thrown for http POST to /session with params: {"desiredCapabilities":{"browserName":"chrome","platform":"ANY"}}

Operation timed out after 30000 milliseconds with 0 bytes received

/var/www/html/dusk/vendor/facebook/webdriver/lib/Remote/HttpCommandExecutor.php:287
/var/www/html/dusk/vendor/facebook/webdriver/lib/Remote/RemoteWebDriver.php:121
/var/www/html/dusk/tests/DuskTestCase.php:32
/var/www/html/dusk/vendor/laravel/dusk/src/TestCase.php:176
/var/www/html/dusk/vendor/laravel/framework/src/Illuminate/Support/helpers.php:639
/var/www/html/dusk/vendor/laravel/dusk/src/TestCase.php:177
/var/www/html/dusk/vendor/laravel/dusk/src/TestCase.php:107
/var/www/html/dusk/vendor/laravel/dusk/src/TestCase.php:81
/var/www/html/dusk/tests/Browser/ExampleTest.php:21

ERRORS!
Tests: 1, Assertions: 0, Errors: 1.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 26
  • Comments: 76 (26 by maintainers)

Most upvoted comments

This problem also exists on Linux Mint (which is unsurprising as it is built on top of Ubuntu).

The problem can be alleviated by running a separate instance of ChromeDriver in a second terminal window and supplying a valid port number (I used chromedriver --port 8888) and then modifying DuskTestCase with:

RemoteWebDriver::create(
    'http://localhost:8888', DesiredCapabilities::chrome()
);

(Thanks to @abalozz)

Whilst this is ok as a work around it removes one of Dusk’s most appealing features (ie. not having to run a separate selenium server in order to run tests).

I initially assumed that this must be a port conflict with the default (9515) and so tried changing the port without running the separate instance of ChromeDriver but this returns a different error (saying that ChromeDriver can’t be opened on that port).

Running this (with PR #33 included) from within the Homestead vm (vagrant ssh) still gives me

`1) Tests\Browser\ExampleTest::testBasicExample Facebook\WebDriver\Exception\WebDriverCurlException: Curl error thrown for http POST to /session with params: {“desiredCapabilities”:{“browserName”:“chrome”,“platform”:“ANY”}}

Failed to connect to localhost port 9515: Connection refused`

Running it from the host takes ~13 seconds every single time. Anybody has an idea what this could cause?

This is my setup

NB: at the moment i didn’t implement a deploy stage and in my test stage i’ve to implement mySQL service. But the core to work with Laravel Dusk is all in there 😃

.gitlab-ci.yml

stages:
  - build
  - test

before_script:
  - '[[ ! -e /.dockerenv ]] && exit 0'

composer:
  stage: build
  image: shincoder/homestead
  script:
    - sh bin/composer_build.sh
  artifacts:
    paths:
      - vendor/

dusk:
  stage: test
  image: shincoder/homestead
  script:
    - sh bin/dusk_test.sh
    - php artisan dusk
  dependencies:
    - composer

composer_build.sh

#!/bin/sh

# setup php libraries.
composer install --no-interaction --optimize-autoloader

dusk_tests.sh

#!/bin/sh

# makes sure all your repos are up to date
apt-get update -yqq

# laravel dusk dependencies
apt-get -y install chromium-browser libxpm4 libxrender1 libgtk2.0-0 libnss3 \
    libgconf-2-4 libnss3-dev libxi6 libgconf-2-4 xvfb gtk2-engines-pixbuf \
    xfonts-cyrillic xfonts-100dpi xfonts-75dpi xfonts-base xfonts-scalable \
    imagemagick x11-apps

# load test environment
cp .env.dusk.testing .env

# generate an application key. Re-cache.
php artisan key:generate

# make chrome driver executable
# chmod 777 vendor/laravel/dusk/bin/chromedriver-linux

# run the 'graphic' server
Xvfb -ac :0 -screen 0 1280x1024x16 &

# start local server and wait 4 seconds
php artisan serve &
sleep 5

DuskTestCase.php

    /**
     * Create the RemoteWebDriver instance.
     *
     * @return \Facebook\WebDriver\Remote\RemoteWebDriver
     */
    protected function driver()
    {
        $chromeOptions = new ChromeOptions();
        $chromeOptions->addArguments(['no-sandbox']);
        $capabilities = DesiredCapabilities::chrome();
        $capabilities->setCapability(ChromeOptions::CAPABILITY, $chromeOptions);

        return RemoteWebDriver::create(
            'http://localhost:9515',
            $capabilities, 150000, 150000
        );
    }

I also use Dusk in GitLab CI. With a few adjustments it works fine. Basically, these are:

  • Use script to emulate a tty
  • Use Xvfb to provide a virtual X display
  • Run chrome with --no-sandbox

Provide tty

GitLab CI does not provide a tty in its docker runners, so I had to wrap the dusk command into the script command:

dusk:
  stage: test
  script:
    - chmod +x vendor/laravel/dusk/bin/chromedriver-linux # https://github.com/laravel/dusk/issues/81
    - script -q -e -c 'php artisan dusk' # https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/issues/1021

Use Xvfb

I use my own DuskCommand class. It starts Xvfb once for the whole test suite, not for each single test:

<?php
namespace App\Console\Commands;

use Laravel\Dusk\Console\DuskCommand as BaseCommand;
use Symfony\Component\Process\ProcessBuilder;

class DuskCommand extends BaseCommand
{
    /**
     * The X Display to use
     *
     * @var integer
     */
    protected $xDisplay = 17;

    /**
     * The display resolution for the headless X server
     *
     * @var string
     */
    protected $xDisplayResolution = '1280x720x24';

    /**
     * Setup the Dusk environment to run the given callback.
     *
     * @param  \Closure  $callback
     * @return mixed
     */
    protected function withDuskEnvironment($callback)
    {
        return parent::withDuskEnvironment(function () use ($callback) {
            return $this->withChromeDriver($callback);
        });
    }

    /**
     * Run the given callback with chrome driver.
     *
     * @param  \Closure  $callback
     * @return mixed
     */
    protected function withChromeDriver($callback)
    {
        // Start a headless X server
        $xvfb = (new ProcessBuilder())
            ->setTimeout(null)
            ->add('exec')
            ->add('/usr/bin/Xvfb')
            ->add(':' . $this->xDisplay)
            ->add('-screen')->add('0')->add($this->xDisplayResolution)
            ->getProcess();
        $xvfb->start();

        // Start the chromedriver
        $chrome = (new ProcessBuilder())
            ->setTimeout(null)
            ->add('exec')
            ->add(base_path('vendor/laravel/dusk/bin/chromedriver-linux'))
            ->getProcess()
            ->setEnv(['DISPLAY' => ':' . $this->xDisplay]);
        $chrome->start();

        // Terminate both processes once we are done
        return tap($callback(), function () use ($chrome, $xvfb) {
            $chrome->stop();
            $xvfb->stop();
        });
    }
}

It is registered in AppServiceProvider:

<?php
namespace App\Providers;

use App\Console\Commands\DuskCommand;
use Illuminate\Support\ServiceProvider;
use Laravel\Dusk\DuskServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        // Laravel Dusk: Must not be registered in production
        // because of the unprotected login route.
        if ($this->app->environment('local', 'testing')) {
            $this->app->register(DuskServiceProvider::class);
            $this->commands(DuskCommand::class);
        }
    }
}

Apply --no-sandbox

This is needed because GitLab CI runs your build script as root inside the Docker container. I did this by configuring DuskTestCase as follows:

<?php
namespace Tests;

use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Laravel\Dusk\TestCase as BaseTestCase;

abstract class DuskTestCase extends BaseTestCase
{
    use CreatesApplication;

    public static function prepare()
    {
        // Chromedriver is already started in custom DuskCommand.
    }

    /**
     * Create the RemoteWebDriver instance.
     *
     * @return \Facebook\WebDriver\Remote\RemoteWebDriver
     */
    protected function driver()
    {
        $chrome = DesiredCapabilities::chrome();
        if (config('app.env_docker')) {
            $chrome->setCapability(
                ChromeOptions::CAPABILITY,
                (new ChromeOptions)->addArguments(['--no-sandbox'])
            );
        }
        return RemoteWebDriver::create('http://localhost:9515', $chrome);
    }
}

You might have noticed that I introduced config('app.env_docker'), so add the following to config/app.php:

    'env_docker' => env('APP_ENV_DOCKER', false),

And your .env file in GitLab CI should contain: APP_ENV_DOCKER=true This ensures that you use --no-sandbox only as part of your CI pipeline where everything runs in a container, and not on your local machine where this might be a potential security issue.

I was generating the same error, but that was why $browser->resize(1024, 768); // Width and Height change it in:

protected function driver()
    {
        $options = (new ChromeOptions())->addArguments([
            '--disable-gpu',
            '--headless',
            '--window-size=1024, 768',
        ]);

        return RemoteWebDriver::create(
            'http://localhost:9515', DesiredCapabilities::chrome()->setCapability(
                ChromeOptions::CAPABILITY, $options
            )
        );
    }

and it worked ok

After getting chrome not reachable, I researched it on the internet and the first link was http://stackoverflow.com/questions/28364012/webdriver-exception-chrome-not-reachable. The accepted answer suggests no-sandbox.

I read about it and it is related to web safety. Google suggests it’s better to use another browser than to use Chrome without sandbox (when talking about regular usage). Without sandbox, the browser is more free to access operating system and user files without any restriction, which explains the lack of security. Given the nature of automated tests on a closed environment and a specific web project, the lack of security doesn’t worry me right now. I still don’t understand why I was able to run Dusk 2 days ago without any issue and now I’m having this problem, but at least I can come back to this some other time.

Increasing timeout to 150 seconds allowed me to gather more information on the problem.

	protected function driver() {
		return RemoteWebDriver::create(
			'http://localhost:9515',
			$capabilities, 150000, 150000
		);
	}

With that, I started getting

root@dusk:/var/www/solucoesideais/laravel-dusk# php artisan dusk
PHPUnit 5.7.15 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 1.91 minutes, Memory: 10.00MB

There was 1 error:

1) Tests\Browser\ExampleTest::testBasicExample
Facebook\WebDriver\Exception\UnrecognizedExceptionException: chrome not reachable
  (Driver info: chromedriver=2.27.440175 (9bc1d90b8bfa4dd181fbbf769a5eb5e575574320),platform=Linux 4.4.0-31-generic x86_64)

And the only solution I have for it so far is to run chrome with no-sandbox option.

	protected function driver() {
		$chromeOptions = new ChromeOptions();
		$chromeOptions->addArguments(['no-sandbox']);
		$capabilities = DesiredCapabilities::chrome();
		$capabilities->setCapability(ChromeOptions::CAPABILITY, $chromeOptions);
		
		return RemoteWebDriver::create(
			'http://localhost:9515',
			$capabilities, 150000, 150000
		);
	}

With the no-sandbox flag I am able to use Dusk successfully.

Any clue how to make it available to run Dusk in fresh Linux installation? It works fine in Homestead, but when I try to do the same on fresh Ubuntu installation (Docker), I run first:

apt-get -y install libxpm4 libxrender1 libgtk2.0-0 \
libnss3 libgconf-2-4 chromium-browser \
xvfb gtk2-engines-pixbuf xfonts-cyrillic \
xfonts-100dpi xfonts-75dpi xfonts-base \
xfonts-scalable imagemagick x11-apps

and then

Xvfb :0 -screen 0 1280x960x24 &

but it still doesn’t work. I’m getting:

Facebook\WebDriver\Exception\WebDriverCurlException: Curl error thrown for http POST to /session with params: {“desiredCapabilities”:{“browserName”:“chrome”,“pl atform”:“ANY”,“chromeOptions”:{“binary”:“”,“args”:[“–disable-gpu”,“–headless”] }}}

Operation timed out after 30000 milliseconds with 0 bytes received

Yeah, the same for me. I tried ‘–no-sandbox’, because Chrome suggested me to do so. I think it would be good to have the setting in Dusk.

My 2 cents here. I tried the followings and it seems that it is a step closer to running successfully. Yes, it is still not working in my machine. But perhaps it can run on yours.

I tried to execute chromedriver-linux directly, which tells me something like “libnss3.so” is missing. So I run “apt-get install libnss3”. Then it tells me “error while loading shared libraries: libgconf-2.so.4: cannot open shared object file: No such file or directory”. I install “apt-get install libgconf-2-4” as well.

At this point, I can finally run the chromedriver-linux directly. Then I kill the shit that is using port 9515. (That shit is probably the chromedriver-linux.)

I run “php artisan dusk” again. Now it shows this error.

There was 1 error:

  1. Tests\Browser\BackendLoginTest::testLoginPage Facebook\WebDriver\Exception\UnknownServerException: unknown error: cannot find Chrome binary (Driver info: chromedriver=2.25.426924 (649f9b868f6783ec9de71c123212b908bf3b232e),platform=Linux 4.4.0-31-generic x86_64)

[PROJECT_PATH]/vendor/facebook/webdriver/lib/Exception/WebDriverException.php:114 [PROJECT_PATH]/vendor/facebook/webdriver/lib/Remote/HttpCommandExecutor.php:322 [PROJECT_PATH]/vendor/facebook/webdriver/lib/Remote/RemoteWebDriver.php:121 [PROJECT_PATH]/tests/DuskTestCase.php:33 [PROJECT_PATH]/vendor/laravel/dusk/src/TestCase.php:180 [PROJECT_PATH]/vendor/laravel/framework/src/Illuminate/Support/helpers.php:639 [PROJECT_PATH]/vendor/laravel/dusk/src/TestCase.php:181 [PROJECT_PATH]/vendor/laravel/dusk/src/TestCase.php:111 [PROJECT_PATH]/vendor/laravel/dusk/src/TestCase.php:85 [PROJECT_PATH]/tests/Browser/BackendLoginTest.php:16

Time to sleep now. Hope that someone continue figuring out what is going on 😃

P.S. I am running it in Ubuntu 14.04 Server.

SOLVED!!!

In DuskTestCase.php File

Old Code of driver():

protected function driver()
    {
        $options = (new ChromeOptions)->addArguments([
            '--disable-gpu',
            '--headless',
            '--window-size=1920,1080',
        ]);

        return RemoteWebDriver::create(
            'http://localhost:9515', DesiredCapabilities::chrome()->setCapability(
                ChromeOptions::CAPABILITY, $options
            )
        );
    }

Just Add ‘–no-sandbox’ flag

New Code:


protected function driver()
    {
        $options = (new ChromeOptions)->addArguments([
            '--disable-gpu',
            '--headless',
            '--window-size=1920,1080',
            '--no-sandbox'
        ]);

        return RemoteWebDriver::create(
            'http://localhost:9515', DesiredCapabilities::chrome()->setCapability(
                ChromeOptions::CAPABILITY, $options
            )
        );
    }

On Ubuntu Linux 16.04, I got this to work:

Install Chromium & dependencies for headless testing sudo apt-get -y install chromium-browser xvfb gtk2-engines-pixbuf xfonts-cyrillic xfonts-100dpi xfonts-75dpi xfonts-base xfonts-scalable imagemagick x11-apps

Create a customDuskCommand Which extends the original, with this handle method:

    public function handle()
    {
        $xvfb = (new ProcessBuilder())
            ->setTimeout(null)
            ->setPrefix('/usr/bin/Xvfb')
            ->setArguments(['-ac',  ':0', '-screen', '0', '1280x1024x16'])
            ->getProcess();

        $xvfb->start();

        try {
            parent::handle();
        } finally {
            $xvfb->stop();
        }

        return;
    }

@deleugpn i replace the docker/image with this one: shincoder/homestead

it’s the copy/paste environment of vagrant but in docker.

It works ! i will post my solution as soon as i clean a bit my CI scripts. see you soon and thx all.

Yeah Im working on Xvfb atm think there is the problem in the docker file…

I think they should add an error output and autoexit in chrome with “not allowed to run as root in sandbox mode” this it at least what most of my package managers do (for example yaourt in archlinux), and that way they often stop me from doing more harm than good.

However the generell rule in linux is try to do as little as possible with root, especially if youre working with webapps and scripting languages such as php…

@mrdevries Works fine on my host too, but I’m not experiencing much lag, might be a hardware thing. There should be a note in the docs that Dusk isn’t compatible with Homestead.

All of my previous tests are now failing and impossible to run on my Homestead and continous-integration servers. Good thing there’s the new laravel/browser-kit-testing package, which supports the my tests. Learn more here: https://laravel.com/docs/5.4/upgrade#upgrade-5.4.0