DEV Community

Arnau Besora for codegram

Posted on • Originally published at codegram.com

Phoenix: Integration tests at GitHub Actions

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.
  • Wallaby 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.

# test/suport/factories/client.ex 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.

# test/support/factory.ex 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.

# test/our_project/client/some_client_test.ex defmodule OurProject.SomeClientTest do use OurProject.DataCase import OurProject.Factory def client_fixture(attrs \\ %{}) do # `insert*` returns an inserted comment. Only works with ExMachina.Ecto # Associated records defined on the factory are inserted as well. 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/test.exs 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.

# test/support/feature_case.ex 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 our Router Helpers import OurProject.Router.Helpers #Import custom helpers if we need them import OurProject.TestHelpers.Navigation #Import our ExMachina factories import OurProject.Factory end end # Connect to the test database and create the session for each test 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.

#test/integration/client/delete_client.exs 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.

# .github/workflows/ci.yml - uses: nanasess/setup-chromedriver@master 

Compile our project

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

# .github/workflows/ci.yml - 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.

# .github/workflows/ci.yml - run: npm install working-directory: ./assets - run: npm run deploy --prefix ./assets 

Run the tests

And finally, run the tests.

# .github/workflows/ci.yml - run: mix test --trace 

Overview

There is our entire ci.yml file.

name: Continuous Integration on: [push] # This workflow will build and test a Phoenix application that uses # PostgreSQL as a database. Will also cache dependencies and build # artifacts to speed up the build. 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

Top comments (0)