We were recently tasked with creating a test suite using feature tests (a type of integration tests). There are a few options for libraries which are likely all great, and we may explore others in the future, but we landed on using Wallaby mostly because of the natural syntax.
This guide is just an introduction to writing feature tests for Phoenix and we’ll likely dive deeper in future articles.
Overview
- Config greenfield app for feature tests using wallaby and headless chrome
- Create a few simple tests
- Run the tests
Install Chromedriver
There are different methods of installing chromedriver locally, so go with whatever suits your environment.
Here’s an example of how to install chromedriver using npm.
$ npm i -g chromedriver --chromedriver_version=79.0.3945.36
NOTE: The version of chromedriver should match the version of chrome that you have installed. Otherwise you’ll get session errors.
Create an app
Let’s create a new throwaway app to work with:
$ mix phx.new app
Then the usual setup:
$ cd app
$ mix ecto.create
Add deps:
We only need wallaby so open mix.exs and add the following to deps:
{:wallaby, "~> 0.23.0", runtime: false, only: :test}
And run:
$ mix deps.get
Configure Wallaby
There are a few configuration steps, the first is to add the following to config/test.exs
config :wallaby,
driver: Wallaby.Experimental.Chrome,
chrome: [headless: true] # enable/disable
Notice that Chrome is an experimental feature of Wallaby and that you can toggle headless with this configuration. There are some situations where it’s helpful to see what’s going on in the test browser.
Next we’re going to ensure that Wallaby is started and set the wallaby base_url
env variable in test/test_helper.exs:
{:ok, _apps} = Application.ensure_all_started(:wallaby)
Configure Concurrent Testing
From the docs:
If you’re testing a Phoenix application with Ecto 2 and a database that supports sandbox mode then you can enable concurrent testing by adding the Phoenix.Ecto.SQL.Sandbox plug to your Endpoint. It’s important that this is at the top of endpoint.ex before any other plugs.
Open LIB_PATH/endpoint.ex
and add the plug at the beginning:
defmodule AppWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :app
if Application.get_env(:your_app, :sql_sandbox) do
plug Phoenix.Ecto.SQL.Sandbox
end
# ...
Next, open config/test.exs
and configure Phoenix to serve endpoints in tests and enable SQL sandbox:
config :app, AppWeb.Endpoint,
http: [port: 4002],
server: true # --- Enabled
config :app, :sql_sandbox, true # --- Added
config :wallaby,
driver: Wallaby.Experimental.Chrome,
chrome: [headless: true]
Your test configuration should look similar to above at this point.
Then in test/test_helper.exs
you can provide some configuration to Wallaby. At minimum, you need to specify a :base_url
, so Wallaby knows how to resolve relative paths.
Application.put_env(:wallaby, :base_url, AppWeb.Endpoint.url())
Quick Sanity Check
So now that Wallaby is configured (at least for our simple test cases) let’s do a quick sanity check to see if anythings out of whack:
$ mix test
If your tests succeed, then we’re good to continue.
Add FeatureCase Helper
We need to add a new case template to include in feature tests.
Create test/support/feature_case.ex
with this content:
defmodule AppWeb.FeatureCase do
use ExUnit.CaseTemplate
using do
quote do
use Wallaby.DSL
alias App.Repo
import Ecto
import Ecto.Changeset
import Ecto.Query
import AppWeb.Router.Helpers
end
end
setup tags do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(App.Repo)
unless tags[:async] do
Ecto.Adapters.SQL.Sandbox.mode(App.Repo, {:shared, self()})
end
metadata = Phoenix.Ecto.SQL.Sandbox.metadata_for(App.Repo, self())
{:ok, session} = Wallaby.start_session(metadata: metadata)
{:ok, session: session}
end
end
This is taken from the docs and manages some of the hand-wavy business of importing modules and preparing for concurrent tests. We’ll use this module in any feature tests we write.
Write Feature Test
Ok, so after all the configuration, let’s get into what we set out to accomplish.
Writing feature tests with Phoenix.
We haven’t made any changes to the UI so we’re just going to test that the index page is loaded with some predictable element on the page. section.phx-hero
Create a new file at test/app_web/features/index_page_test.exs
with the new test:
defmodule AppWeb.Features.IndexPageTest do
use AppWeb.FeatureCase, async: true
import Wallaby.Query
test "index page has a welcome message", %{session: session} do
session
|> visit("/")
|> find(css("section.phx-hero"))
|> assert_has(css("h1", text: "Welcome to Phoenix!"))
end
end
This simple test uses the session created by FeatureCase, visits the page and tests that some key elements are visible on the page using headless chrome.
To run:
$ mix test
Success! You should have a fully green test suite at this point. (If you don’t and get stuck hit us up, and we’ll try to help).
Conclusion
This guide was intended to be an intro to writing feature tests for phoenix. We covered the basics of configuring and using Wallaby and wrote a simple test.
There are many more elements to writing feature tests and we hope to cover more detailed tests in the future.
Let me know if there are any issues with the guide, or if you have any questions. @tmartin8080