In this post, I will try to explain how to do integration tests for your Phoenix project and add them to the checks in your repository

These are the tools that we will use:

Ex_machina to create test data.

to create test data. Wallaby to test your web applications by simulating realistic user interactions.

to test your web applications by simulating realistic user interactions. GitHub Actions to configure the environment and run the tests at GitHub.

ExMachina

The first step will be to configure your project to easily create test data. As mentioned above, we will use ex_machina . To install it follow the instructions of their repository. Once we have installed the library, let's configure it to our needs.

Factories and Factory Module

We will split factories into separate files and will import them by creating a Factory module.

Here we have the code of our Client factory.

defmodule OurProject . ClientFactory do defmacro __using__ ( _opts ) do quote do def client_factory do % OurProject . Clients . Client { name: "Client Name" , contact_info: "Client contact_info" } end end end end

And then we import it in our Factory Module.

defmodule OurProject . Factory do use ExMachina . Ecto , repo: OurProject . Repo use OurProject . ClientFactory end

Once we have created our Factory module and our factories we can use them in any test importing the factory module. You can with ExMachina you can build or insert test data, the main difference is that build returns an object that is not saved at the database. For more information read the Overview section of their repository

Here is an example test that inserts a client when we need it. Calling the client_fixture function.

defmodule OurProject . SomeClientTest do use OurProject . DataCase import OurProject . Factory def client_fixture ( attrs \\ % { } ) do insert ( :client , attrs ) end ... end

Wallaby

We already have our data so we can start with the integration tests. Install wallaby following the instructions on their GitHub page and configure it with Chromedriver.

config :wallaby , driver: Wallaby . Experimental . Chrome , chrome: [ headless: true ]

Now, we will create a FeatureCase module to configure the database, create the session and import the modules and helpers that our tests will need. Here we will import our Factory module.

defmodule OurProject . FeatureCase do use ExUnit . CaseTemplate using do quote do use Wallaby . DSL import Wallaby . Query alias OurProject . Repo import Ecto import Ecto . Changeset import Ecto . Query import OurProject . Router . Helpers import OurProject . TestHelpers . Navigation import OurProject . Factory end end setup tags do :ok = Ecto . Adapters . SQL . Sandbox . checkout ( OurProject . Repo ) unless tags [ :async ] do Ecto . Adapters . SQL . Sandbox . mode ( OurProject . Repo , { :shared , self ( ) } ) end metadata = Phoenix . Ecto . SQL . Sandbox . metadata_for ( OurProject . Repo , self ( ) ) { :ok , session } = Wallaby . start_session ( metadata: metadata ) { :ok , session: session } end end

Finally, we are ready to create our first test. We are going to create a test that requires fake data so we can see how to use the factories inside an integration test.

defmodule OurProject . DeleteClientTest do use OurProject . FeatureCase , async: false setup % { session: session } do client = insert ( :client ) { :ok , session: session , client: client } end test "remove client" , % { session: session , client: client } do session |> visit ( "/clients" , client . name ) |> click ( link ( client . name ) ) |> click ( link ( "delete" ) ) |> assert_has ( css ( ".toast-message" , count: 1 , text: "Client successfully deleted" ) ) end end

GitHub Actions

We have our integration tests and we want to check them when we submit a pull request. With a few steps, we can configure our GitHub workflow to run the tests every time we push to the branch.

Chromedriver

We have to add Chromedriver to our CI. To do it we will use an action created by @nanasses . Here you can read the documentation.

- uses : nanasess/setup - chromedriver@master

Compile our project

We have to get the dependencies, compile the project and run the migrations.

- name : Install Dependencies run : mix deps.get - run : mix compile - run : mix ecto.migrate

Compile our assets

In order to have our javascript compiled it's needed to compile our assets.

- run : npm install working-directory : ./assets - run : npm run deploy - - prefix ./assets

Run the tests

And finally, run the tests.

- run : mix test - - trace

Overview

There is our entire ci.yml file.

name : Continuous Integration on : [ push ] jobs : test : env : MIX_ENV : ci DATABASE_URL : postgres : //postgres : postgres@localhost : 5432/postgres runs-on : ubuntu - latest services : db : env : POSTGRES_USER : postgres POSTGRES_PASSWORD : postgres POSTGRES_DB : postgres image : postgres : 11 ports : [ '5432:5432' ] options : > - - - health - cmd pg_isready - - health - interval 10s - - health - timeout 5s - - health - retries 5 steps : - uses : actions/checkout@v1.0.0 - name : Recover dependency cache uses : actions/cache@v1 id : deps_cache with : path : deps key : $ { { runner.OS } } - deps - $ { { hashFiles('**/mix.lock') } } restore-keys : | ${{ runner.OS }}-deps-${{ env.cache-name }}- ${{ runner.OS }}-deps- ${{ runner.OS }}- - name : Recover build cache uses : actions/cache@v1 with : path : _build key : $ { { runner.OS } } - build - $ { { env.cache - name } } restore-keys : | ${{ runner.OS }}-build- ${{ runner.OS }}- - uses : actions/setup - elixir@v1.0.0 with : otp-version : 22.x elixir-version : 1.9.x - uses : nanasess/setup - chromedriver@master - name : Install Dependencies run : mix deps.get - run : mix compile - run : mix ecto.migrate - run : npm install working-directory : ./assets - run : npm run deploy - - prefix ./assets - run : mix test - - trace

That's it

We have our tests created and running on GitHub. If you are interested in GitHub Actions, at Codegram we have a repository with GitHub Actions workflows that can be useful to you.

I hope you found this post useful. If you have any comments, questions or suggestions, tell us on Twitter!

Photo by Glenn Carstens-Peters on Unsplash