Test your Laravel with GitHub Actions and Laravel Dusk
Tags: phpunit, laravel, php, webdev
Published: 2019-09-02 09:21:02


> This post was published first at my own [blog](https://zah.me/2019/09/01/test-your-laravel-with-github-actions-and-laravel-dusk/)

Last week, I got access to the new GitHub Actions v2.0, which is way different than the first version they have released. You can think of it as a world-class CI/CD solution

> GitHub Actions makes it easy to automate all your software workflows, 
> now with world-class CI/CD. Build, test, and deploy your code right from GitHub. 
>Make code reviews, branch management, and issue triaging work the way you want.

I decided to dive into it and test it, you will get 2000 free minutes to test your private repositories, and you can even run your tests/deployments on multiple operating systems, not only linux, which is a huge thing if you are developing an [electron application](https://darawish.io/domainbook/?utm_campaign=blogpost&utm_medium=referral&utm_source=devto&utm_content=sharelink) like me.

![Github Actions Pricing](https://thepracticaldev.s3.amazonaws.com/i/4nr0ne7ps9rgec1vno2b.png)

You can read more about GitHub actions and signup for the beta from this [link](https://github.com/features/actions/signup/?utm_campaign=blogpost&utm_medium=referral&utm_source=zahme&utm_content=sharelink).

Till today, there is no official template that you can use with PHP, but thanks to [Franz Liedke](https://github.com/franzliedke) you can use his [simple template](https://github.com/actions/starter-workflows/issues/15#issuecomment-521809926) and change it however you want.

For sure, this is not what I am going to talk about today, this post is mainly to explain how you can test your Laravel application using Laravel Dusk and GitHub Actions. I won't list too much information, instead, I'll just explain first how you can use GitHub Actions and then I'll use my [own docker image](https://hub.docker.com/r/zaherg/laravel-dusk) that I've built specifically for Laravel Dusk.

## Introduction

It is important for you to understand the [core concepts of GitHub Actions](https://help.github.com/en/articles/about-github-actions#core-concepts-for-github-actions)but listing them is out of the scope of this post. You are encouraged to read these concepts from [GitHub Docs](https://help.github.com/en/articles/about-github-actions#core-concepts-for-github-actions).

Now that we have all the knowledge that we need, let's build our first **GitHub Action Workflow**.

## Prerequisite

Before building our first Workflow, you need to make sure that your account has access to the new GitHub Actions, as mentioned above, you can signup for beta access from this [link](https://github.com/features/actions/signup/).
If they enabled it on your account, you will get a message like this:

> GitHub Actions is already enabled on your account! Go test it out in one of your repositories today. 

Otherwise, the message will say:

> This account is already on the waiting list for the GitHub Actions Beta! We'll notify you when we've enabled it on your account. Make sure your primary email address is up-to-date so we can get a hold of you.   

## Creating our first Workflow

As stated in the documentation, you should create a file in the path `.github/workflows/ci.yml`, this file will contain our workflow code.

Basically, a workflow file will have 3 main top-level words:

1. **name**: Which is the name of the workflow.
2. **on**: The action that will cause the workflow to run.
3. **jobs**: A list of all the jobs that your workflow will execute.

And the workflow should have at least one job for it to run.

Our first workflow will execute a simple job to test our Laravel application using PHPUnit, and if you checked Franz 
comment you will notice that this one is a simple version of his comment:

```yaml
name: CI

on: [push]

jobs:
  phpunit: # name of the job
    runs-on: ubuntu-latest # the host operating system
    steps:
        - uses: actions/checkout@v1 # the action to use before running anything
        - name: Install Composer dependencies # the name of the step
          run: composer install --prefer-dist # the command to run
        - name: Run tests # the name of the second step
          run: php vendor/bin/phpunit # the command to run
```

The above code tells GitHub actions to install composer dependencies and phpunit on our code, and the comments explain
each keyword. A small note, before running any job, I found it is important to use `actions/checkout@v1` action, as it will clone the code within your virtual environment. You can read more about the checkout actions from this [link](https://github.com/actions/checkout/).

## Creating our Laravel Dusk Tests Workflow

Now that you know how the code for the workflow looks like, let's check how we can use it to test Laravel Dusk tests.
The main changes will be within the jobs section, as I'll assume that you want to test your codes on push, but you are
free to look at the [Events that trigger workflows](https://help.github.com/en/articles/events-that-trigger-workflows#webhook-events)
and implements them within your workflow later.

As we all know, to test your Laravel application you will need certain packages and applications, like google chrome or chromium and many x.org libraries. You can check my [Dockerimage](https://github.com/linuxjuggler/laravel-dusk/blob/master/7.3/Dockerfile) 
file and see which libraries I've installed. Please note that they provide you with many software [preinstalled](https://help.github.com/en/articles/software-in-virtual-environments-for-github-actions). 


> I just found out that you can run the tests on the host and no need to pull my own docker image, but I'll explain to you how you can use my image, to explain the <a href="https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idcontainer">container</a>
keyword, and how to use the local software.


To run your code within a docker image, you can use the keyword `container` within your jobs which tells github to run all the steps within the specific docker image, since I already built an image to test your code with all the software preinstalled.

The same docker image can be used with other services like [Bitbucket](https://bitbucket.org/) and you can check this [article](https://zah.me/2018/02/03/running-laravel-dusk-tests-on-bitbucket-the-easy-way/) and the recent update for the demo code [here](https://bitbucket.org/zaherg/laravel-dusk/src/master/bitbucket-pipelines.yml).

### Create the Job

To recap, our job will have a name, steps and we need to specify the host and the docker image. For me I'll use the latest version of ubuntu so the code is like:

```yaml
  dusk-php-latest:
    runs-on: ubuntu-latest
    container: docker://zaherg/laravel-dusk:latest
    steps:
      - uses: actions/checkout@v1
        with:
          fetch-depth: 1
      - name: Prepare the environment
        run: cp .env.example .env
      - name: Install Composer dependencies
        run: |
          composer install --no-progress --no-suggest --prefer-dist --optimize-autoloader
          php artisan key:generate
      - name: Run dusk tests
        run: |
          php artisan dusk:chrome-driver
          nohup bash -c './vendor/laravel/dusk/bin/chromedriver-linux > /dev/null 2>&1 &'
          nohup bash -c 'php artisan serve > /dev/null 2>&1 &'
          php artisan dusk
```

The above sample will use PHP 7.3 as it is the latest version for the `zaherg/laravel-dusk` image and it:

1. Pull the docker image
2. Uses github checkout action to clone the code to our docker image.
3. Create a new `.env` file.
4. Install composer dependencies
5. Generate a key for our application.
6. Run `dusk:chrome-driver` to update our chromedriver binary.
7. Run `chromedriver-linux` in the background.
8. Run `php artisan serve` in the background to have a local server to use for our tests.
9. Run our `dusk` tests.

If we want to test our code with PHP 7.2 we can just use `laravel-dusk:7.2` so our code will be the same as above except the container line which will become:

```yml
    container: docker://zaherg/laravel-dusk:7.2
```

Now, as I mentioned in my note, you can run your Laravel Dusk tests directly on the host virtual machine, and yes it is faster and by default, they are using **PHP 7.3**. The changes to what we have written are not that big, you just need to remove the `container` from the whole thing so the code will be like the following:

```yml
  dusk-host:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
        with:
          fetch-depth: 1
      - name: Prepare the environment
        run: cp .env.example .env
      - name: Install Composer dependencies
        run: |
          composer install --no-progress --no-suggest --prefer-dist --optimize-autoloader
          php artisan key:generate
      - name: Run dusk tests
        run: |
          php artisan dusk:chrome-driver
          ./vendor/laravel/dusk/bin/chromedriver-linux > /dev/null 2>&1 &
          php artisan serve > /dev/null 2>&1 &
          php artisan dusk
```

To recap, you have two ways to test your Laravel application using GitHub Actions and Laravel Dusk, either on the host machine or using a custom made docker image. Also, the same way we used the `container` in our code, you can use it with any other docker image you want.

## Final workflow file

This is the workflow file I've explained which cover all the cases:

```yaml
name: CI

on: [push]

jobs:

  dusk-php-latest:
    runs-on: ubuntu-latest
    container: docker://zaherg/laravel-dusk:latest
    steps:
      - uses: actions/checkout@v1
        with:
          fetch-depth: 1
      - name: Prepare the environment
        run: cp .env.example .env
      - name: Install Composer dependencies
        run: composer install --no-progress --no-suggest --prefer-dist --optimize-autoloader
      - name: Install Composer dependencies
        run: php artisan key:generate
      - name: Upgrade chrome driver
        run: php artisan dusk:chrome-driver
      - name: Start Chrome Driver
        run: ./vendor/laravel/dusk/bin/chromedriver-linux > /dev/null 2>&1 &
      - name: Run Laravel Server
        run: php artisan serve > /dev/null 2>&1 &
      - name: Run dusk tests
        run: php artisan dusk


  dusk-php-73:
    runs-on: ubuntu-latest
    container: docker://zaherg/laravel-dusk:7.3
    steps:
      - uses: actions/checkout@v1
        with:
          fetch-depth: 1
      - name: Prepare the environment
        run: cp .env.example .env
      - name: Install Composer dependencies
        run: composer install --no-progress --no-suggest --prefer-dist --optimize-autoloader
      - name: Install Composer dependencies
        run: php artisan key:generate
      - name: Upgrade chrome driver
        run: php artisan dusk:chrome-driver
      - name: Start Chrome Driver
        run: ./vendor/laravel/dusk/bin/chromedriver-linux > /dev/null 2>&1 &
      - name: Run Laravel Server
        run: php artisan serve > /dev/null 2>&1 &
      - name: Run dusk tests
        run: php artisan dusk

  dusk-php-72:
    runs-on: ubuntu-latest
    container: docker://zaherg/laravel-dusk:7.2
    steps:
      - uses: actions/checkout@v1
        with:
          fetch-depth: 1
      - name: Prepare the environment
        run: cp .env.example .env
      - name: Install Composer dependencies
        run: composer install --no-progress --no-suggest --prefer-dist --optimize-autoloader
      - name: Install Composer dependencies
        run: php artisan key:generate
      - name: Upgrade chrome driver
        run: php artisan dusk:chrome-driver
      - name: Start Chrome Driver
        run: ./vendor/laravel/dusk/bin/chromedriver-linux > /dev/null 2>&1 &
      - name: Run Laravel Server
        run: php artisan serve > /dev/null 2>&1 &
      - name: Run dusk tests
        run: php artisan dusk

  dusk-host:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
        with:
          fetch-depth: 1
      - name: PHP version
        run: php -v
      - name: Prepare the environment
        run: cp .env.example .env
      - name: Install Composer dependencies
        run: composer install --no-progress --no-suggest --prefer-dist --optimize-autoloader
      - name: Install Composer dependencies
        run: php artisan key:generate
      - name: Upgrade chrome driver
        run: php artisan dusk:chrome-driver
      - name: Start Chrome Driver
        run: ./vendor/laravel/dusk/bin/chromedriver-linux > /dev/null 2>&1 &
      - name: Run Laravel Server
        run: php artisan serve > /dev/null 2>&1 &
      - name: Run dusk tests
        run: php artisan dusk
```