Laravel Passport and Travis Ci

March 2nd, 2019

When using Laravel Passport in a project that uses Travis for continuous integration, it is important to make sure that the testing environment on travis is configured properly, otherwise you may encounter errors that will prevent your build from passing.

The .travis.yml file

After some trial and error, I have come up with a working .travis.yml configuration.

# .travis.yml
language: php

php:
  - 7.1
  - 7.2

before_script:
  - travis_retry composer self-update
  - travis_retry composer install --prefer-source --no-interaction --no-suggest
  - cp .env.travis .env
  - php artisan key:generate
  - php artisan migrate
  - php artisan passport:keys

script:
  - vendor/bin/phpunit

sudo: false

The first two sections are self-explanatory. We are going to be testing a PHP project, and we want Travis to test our code against PHP 7.1 and 7.2.

The before_script section is where we outline how we want the testing environment to be prepared before the tests are run. Lets break this down line by line:

The script section is where we tell Travis how to run our tests. Note that I am specifying that I want travis to use the version of PHPUnit that was installed via Composer, rather than the global version that it makes available to us in the container. This way I can always know for sure exactly which version of PHPUnit I am running, and we can run a newer version if we want to.

The last section, sudo: false, is how we tell Travis to run our tests in a containerized environment. This often means that our tests will run faster (though not always.). The downside is that we don't have sudo available to us when provisioning. If we were to need that option we would have to use the slower, non-container environment that Travis offers.

The .env configuration file

This is the special .env.travis file I used to specify application specific testing configuration:

APP_NAME=ExampleLaravelApplication
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_URL=http://localhost

DB_CONNECTION=sqlite
DB_DATABASE=:memory:
DB_USERNAME=homestead
DB_PASSWORD=secret

BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
SESSION_LIFETIME=120
QUEUE_DRIVER=sync

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_DRIVER=log
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

The most important option here is the DB_DATABASE=:memory: option. This tells the application that we want to use an in-memory sqlite database. Even though the APP_ENV is "local" here, it will be over-written by the ENV values specified in the phpunit.xml file. This is where we set the application environment to "testing" for the lifetime of the test run.

The phpunit.xml file

We also set some importan environment variables in the phpunit.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="vendor/autoload.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false">
    <testsuites>
        <testsuite name="Feature">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>

        <testsuite name="Unit">
            <directory suffix="Test.php">./tests/Unit</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./app</directory>
        </whitelist>
    </filter>
    <php>
        <env name="APP_ENV" value="testing"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
        <env name="DB_CONNECTION" value="testing" />
        <env name="PASSPORT_CLIENT_SECRET" value="Dtg9myGAIsTUbTck2kxrxeZ5TDnE1qbVvTeYIuPN" />
    </php>
</phpunit>

There are two important things to note about this file:

Thats it! Once you understand how the pieces fit together it is not as complex as it first seems.