Laravel and Dusk on Codeship

Written by: Alfred Nutile
7 min read

Some time back, I posted on how to set up Laravel and Behat using Selenium and headless Chrome. But since that article, a new option has come into view -- Dusk.

This has several advantages over Behat. For one, the install is greatly simplified. On top of that, the speeds and simplicity in testing the UI and JavaScript have all been wrapped into PHPUnit. Invented by the creator of Laravel, Dusk has amazing integration into the base of Laravel, from easily mocking events, jobs, models, etc. to running migrations and transactions.

In this article, I will cover a much-updated approach to getting all of this working on Codeship, including how to troubleshoot when things are not going as expected on a Codeship build.

Setting Up Your Local Environment

As in the last post, I reference Matthew Setter's article about Laravel and Codeship. From there though, the next steps change from the previous article since there is no Behat or Selenium to set up.

If you miss the Behat Gherkin workflow, try Pickle.

Instead, I follow the installations docs as seen on Laravel Docs. This uses the standalone ChromeDriver, eliminating the need for installing Selenium as well. The docs on that page do a great job of explaining how to get set up.

The only thing I would point out is that if you are running your tests in your VM, which I do most of the time, you just need to set your VM to know the IP of your host machine. So when you're running Dusk from inside of it and point to the URL of your app (eg, http://foo.com), then the VM's /etc/hosts file needs to match that domain to the host IP. This will then open up Chrome on your host machine via this driver.

In this example, I'll keep it simple and run the server on my host machine. First, I'll edit my .env file to be APP_URL=http://127.0.0.1:8000 instead of the default and then in the terminal, type:

php artisan serve

You will end up seeing this:

Your First Dusk Test

We are now ready to write the first test. To begin, I'll use the command to stub it out:

php artisan dusk:make FirstUITest

This will make a file, tests/Browser/FirstUITest.php. Then I'll just keep it simple and leave the default stubbed test in there:

 browse(function (Browser $browser) {
                $browser->visit('/')
                        ->assertSee('Laravel');
            });
        }
    }

Now, to run this locally and make sure all is working and running from my host machine:

php artisan dusk

You should see, as in the image below, Chrome pop up and run the tests.

Setting Up Codeship for Dusk

Now that we have our test, we need to get Codeship ready to run Dusk. First, I'll add a .env.codeship file:

APP_ENV=testing
    APP_URL=http://127.0.0.1:8000
    APP_KEY=base64:nF7Ns2Gz9olX2rmfquKzblBRVHIvsFzicqh78TGHh6A=

Then, I'd like to make a ci/setup.sh folder and file with this content:

#!/bin/sh
    set -e
    phpenv local 5.6
    composer install --no-interaction
    ./vendor/laravel/dusk/bin/chromedriver-linux &
    cp .env.codeship .env
    php artisan serve > /dev/null 2>&1 &
    sleep 3

This makes it easier to debug a build when you SSH into Codeship, as I will demonstrate later on.

All right, now wrap up the two install settings on Codeship as seen in the image below.

Now push your code!

Troubleshooting a Build

Sometimes things will not work out on the CI as expected, and this is great! Well, great in that the CI really does catch the little details that are easy to miss when running tests locally. For example, a classic one for me is that on a Mac, I class with a filename FooBar.php but the name class Foobar will pass. But on the CI and pure Linux, it won't. since the caps do not match. I’d much rather have this happen on the CI than on my server.

SSH and dump

One great feature of Codeship is the ability to SSH in and debug. Once you are logged in, you can run:

>sh ./ci/setup.sh
    >php artisan dusk

This is where, in my opinion, it pays off to just have these files instead of numerous lines to run.

After that, you should still see the fail. At this point, alter the test to look like this and add the dump():

{
        $this->browse(function (Browser $browser) {
            $browser->visit('/')->dump()
                    ->assertSee('Laravel');
        });
    }

Then after you run the test again, you'll get a ton of output on the screen. For me, this led to a message that ChromeDriver could not connect to the APP_URL, so I just made sure to rerun php artisan serve. Once, I made the mistake of setting assets to use https, but as you see above, I am serving PHP over http.

Logging and tail

This is a very simple workflow I do locally but it even comes in handy on Codeship. Using a terminal like iTerm, I can have one terminal open and two panes. Then in the top pane, I can SSH in and run the test, while in the bottom one I can tail the logs:

tail -f clone/storage/logs/laravel.log

That makes it easy to see results while running tests and trying new things in the top pane.

The log file will not be there until there is something to log.

SCP and screenshots

Finally, Dusk saves screenshots of failed jobs. They are located in tests/Browser/screenshots and named after the function name and number, eg, failure-testExample-0.png. This does not help you much in SSH mode! But if you're lucky enough to have SSH running on your machine and a port open on your router, then:

scp -v ~/clone/tests/Browser/screenshots/*.png yourname@your_ip:~/

This will download those files locally to your computer. This is needed since SCP to Codeship requires a password, so you can't just download those files from your machine.

!Sign up for a free Codeship Account

Gherkin and BDD

In case you're missing BDD and the Gherkin syntax that Behat provides, I want to share how to use pickle. By using Pickle, you can still have the same flow as before, where there's a Gherkin-based test to run that will use Dusk.

To begin with, let's install Pickle into the dev part of your app using Composer:

composer require alnutile/pickle -dev

The Pickle docs mention cgr and global install. This is great for your host machine or VM (Guest), but for Codeship, we'll just include it into our dev composer.json.

Then in my project, I'll make a folder and file, tests/features/example_pickle.feature:

Feature: Running pickle on Codeship
      Scenario: Is the site loaded
      Given I am on the home page of my app
      Then I should see the intro text

Now we want to make our Dusk test out of this. I can later make a unit or integration test out of this same file as well:

vendor/bin/pickle initialize --context=browser tests/features/example_pickle.feature

This will stub out a file located at tests/Browser/ExamplePickleTest.php for editing.

Just like before, it is stubbed out, but in this case, the file Pickle created is broken into steps. This will allow you to build up your tests and your code, since this is happening before you start to code, one step at a time. By the time I'm done, it will look like this:

class ExamplePickleTest extends DuskTestCase
    {
        /**
        * @var Browser
        */
        protected $browser;
        public function testsTheSiteLoaded()
        {
            $this->browse(function (Browser $browser) {
                $this->browser = $browser;
                $this->givenIAmOnTheHomePageOfMyApp();
                $this->thenIShouldSeeTheIntroText();
            });
        }
        protected function givenIAmOnTheHomePageOfMyApp()
        {
            $this->browser->visit('/');
        }
        protected function thenIShouldSeeTheIntroText()
        {
            $this->browser->assertSee('Laravel');
        }
    }

Okay, now to run it locally:

vendor/bin/pickle run --context=browser tests/features/example_pickle.feature

All this is doing is wrapping Dusk, so as before, you could just run php artisan dusk, seeing the test come together one step at a time. And that is it; we can leave Codeship settings as they are.

To make the Integration or Feature test out of this, run:

vendor/bin/pickle initialize tests/features/example_pickle.feature

As you are completing the steps in that file, you can run:

vendor/bin/pickle run tests/features/example_pickle.feature

And as with Dusk, Pickle is just wrapping PHPUnit, so in your Codeship test settings, make sure to add vendor/bin/phpunit --stop-on-failure.

As you see, getting up to speed with Dusk and Laravel on Codeship is very easy. There really is no reason not to test your UI, even when it contains JavaScript.

Stay up to date

We'll never share your email address and you can opt out at any time, we promise.